1월 31, 2022

~Routing

 *생활코딩 Django 편을 개인 공부를 목적으로 정리한 글임을 밝힙니다*

출처:https://www.youtube.com/watch?v=pbKhn2ten9I&list=PLuHgQVnccGMDLp4GH-rgQhVKqqZawlNwG



웹 어플리케이션을 만드는 작업중에 많은 부분은 공통적입니다. 따라서 어떠한 사이트를 만들더라도 똑같이 해야할 일들이 많습니다. 

⇒ 이런 작업을 미리 해둔 소프트웨어를 Web Framework라고 합니다.

Django는 파이썬 진영의 대표적인 Web Framework로써,요청이 들어올때마다 웹 페이지를 순간적으로 찍어낼 수 있는 일종의 웹 페이지 공장입니다. 


포트의 개념

127.0.0.1이라는 IP adress를 가진 서버컴퓨터에 3개의 서버 소프트웨어가 동작하고 있습니다. 저는 서버에 접속하기 위해 http://127.0.0.1 으로 주소를 입력합니다.

이때, 3개의 소프트웨어 중 어느것과 통신하게 될지 모호해지는 문제가 발생합니다. 

이러한 문제를 해결하기 위하여 PORT라는 개념이 존재합니다. 

예를들어, 첫번째 프로그램이 80번 포트를 listening하는 중이고, 제가 그 포트를 통해 접속하고 싶다면, http://127.0.0.1:80 이렇듯 주소에 포트번호를 주어 80번 포트를 listening하는 서버와 통신할 수 있게 됩니다. 

파이썬 개발서버는 기본적으로 8000번 포트에서 listening하게 됩니다. 제가 8000번 포트를 접속하려 하는데, 가끔은 이미 8000번 포트에 파이썬 개발서버가 아닌 다른 서버가 실행되고 있을 수 있겠죠? 이럴때는 

1. 그 개발 서버를 끄고 해당 개발 서버를 실행하거나

2. 나의 개발서버를 다른 포트에 listening시킴으로서 문제를 해결할 수 있습니다

2번의 경우 ,python manage.py runserver 8888,  이런식으로 다른 포트(8888)에서 서버를 운용하라는 명령어를 주면 됩니다.


app 만들기


django-admin startproject myproject .  

으로 현재 디렉토리에 myproject라는 프로젝트를 시작합니다.

settings.py 안에는 프로젝트를 운용하는데 필요한 여러 설정들이 있습니다

urls.py 는 사용자가 접속하는 그 path에 따라서, 그 접속을(요청을) 어떻게/누가 처리해줄것인가를 지정하는 , 말하자면 routing(네트워크 안에서 통신 데이터를 보낼 때 최적의 경로를 선택하는 과정)을 담당하는 파일입니다

myproject 폴더 밖에 있는 manage.py : 프로젝트를 진행하는데 있어서 필요한 여러가지 기능이 들어가 있는 유틸리티 파일입니다.

근데, 실제로 애플리케이션은 프로젝트 안에서 구현하는 것이 아니라, app이라고 하는 더 작은 단위를 만들어서, 그 안에서 실제 구현을 하게 됩니다.

프로젝트를 만들다보면 복잡해질 수 있는데, 여러개의 app들을 만든 후, 서로 연관된 로직들을 모아서 grouping하게 됩니다. 

각각의 app안에도 urls.py 라는 파일이 또 담겨져 있게 됩니다. 

그리고 app 안에는 views.py 라는 파일이 담기고 , 그 파일 안에 여러 함수를 만들어 application의 구체적인 구현을 하게 됩니다. 

전반적인 작동과정을 보면 이해가 한결 쉽습니다.




1. 사용자가  여러가지 경로로 접속하게 되는데, 그 각각의 경로를 누구에게 위임할 것인가를 urls.py 파일을 수정해서 결정합니다
2. 그 urls.py 파일에 적혀있는데로 적당한 app으로 위임이 됩니다
3. 그럼 app 안에 있는 urls.py 안에서도 제가 작성한데로 적당한 view의 적당한 함수에 위임이 됩니다
4. 이제 구체적인 작업을 해나갈 것인데, 그 과정에서 Database를 사용하게 됩니다. 근데 django안에 model이라는 굉장히 편리한 수단이 있어서, 그 model을 통해서 DB를 사용하게 됩니다.
5. model을 통해 DB에 있는 정보를 받아서, 우리는 클라이언트에게 응답을 해주게 됩니다.
6. 그 결과 최종적으로 html이나 json이나 xml같은 형태의 데이터를 만들어 사용자에게 보내주게 됩니다.

app을 직접 만들어봅시다. django-admin startapp myapp(뒤의 myapp은 app이름) 의 명령어를 실행하자




myapp이라는 폴더가 생겼습니다.


Routing

사용자가 접속한 각각의 경로를 누가 처리할 것인가를 지정하는 것이 routing입니다

Django에서는 project폴더 안의 urls.py가 가장 큰 틀의 routing을 하고, 그것을 적당한 app으로 위임을 해주면, app이 view안에 있는 특정 함수로 위임을 하여 그 함수가 작업을 처리하게 됩니다. 


myproject/urls.py 

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"""myproject URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from xml.etree.ElementInclude import include
from django.contrib import admin
from django.urls import path, include    #include를 사용하기 위해import해줌

# http://127.0.0.1/
# http://127.0.0.1/app/

# http://127.0.0.1/create/
# http://127.0.0.1/read/1/

urlpatterns = [                          # urlpatterns안에 routing과 관련된 list가 있어야 함
    path('admin/', admin.site.urls),     # 관리자화면으로 이동하기 위한 routing설정
    path('',include('myapp.urls'))       # http://127.0.0.1/ 으로 사용자가 접속했을 때 myapp에 있는 urls의 views로 위임하기 위해
]                                     # include의 인자는 myapp.urls

myapp/urls.py

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
"""myproject URL Configuration

The `urlpatterns` list routes URLs to views. For more information please see:
    https://docs.djangoproject.com/en/4.0/topics/http/urls/
Examples:
Function views
    1. Add an import:  from my_app import views
    2. Add a URL to urlpatterns:  path('', views.home, name='home')
Class-based views
    1. Add an import:  from other_app.views import Home
    2. Add a URL to urlpatterns:  path('', Home.as_view(), name='home')
Including another URLconf
    1. Import the include() function: from django.urls import include, path
    2. Add a URL to urlpatterns:  path('blog/', include('blog.urls'))
"""
from xml.etree.ElementInclude import include
from django.contrib import admin
from django.urls import path
from myapp import views 

urlpatterns = [
    path('', views.index), 
    #사용자가 아무것도 없는 경로로 들어왔다면, views.index 실행해라
    path('create/',views.create), #사용자가 create로 들어왔다면 #views.create실행
    path('read/<id>/',views.read) #사용자가 read/1으로 들어왔다면 views.read 실행
]                                  # 가변 값이라는 것을 나타내기 위해 <>안에 값의 이름을 넣음

myapp/views.py

1
2
3
4
5
6
7
8
9
from django.shortcuts import render, HttpResponse

# Create your views here. #클라이언트로 정보를 전송하는 역할을 하는 함수
def index(request):                    #관습적으로 request를 인자에 사용(요청과 관련된 여러 정보 들어오는 객체가 전달되기에)          
    return HttpResponse('Welcome!')    # client로 보내줄때 http를 이용해서 return하겠다는 의미
def create(request):
    return HttpResponse("create")
def read(request,id):                  #가변값 id를 파라미터로 받아 return함
    return HttpResponse("Read"+id)  

127.0.0.1:8000/read/1/ 로 접속했을 시 




127.0.0.1:8000/read/2/ 로 접속했을 시 



정리!!



1. read/1 로 들어오면 사용자는 myproject의  urls.py의 urlpatterns를 확인
1-a. 확인 후 myapp.urls.py 로 이동
2. myapp.urls.py의 urlpatterns의 read/<id>를 확인
2-a. views.read로 위임됨 
3. read함수가 실행되어 HttpResponse(’Read’+id)값을 client에 보내줌

1월 30, 2022

TIL - Class

 객체지향 프로그래밍

: 시스템을 컴퓨터 명령어의 목록으로 구성하지 않고, 여러 다양한 객체들의 집합으로 구성하는 것.

= 프로그램을 객체(object)라는 기본 단위로 나누고, 객체들의 상호작용으로 기능을 구현하는 방식


클래스 없이 코딩을 하게 되면, 데이터함수가 따로 분리돼 정의되므로 문제가 생깁니다.

함수의 사용자가 함수의 작동 로직에 대해 이해도가 부족하다면, 어떠한 데이터와 필드를 넘겨줘야 하는지 이해하지 못했기에 함수를 사용하는데 있어 불편이 커지고 잘못된 매개변수를 넘길 수 있기에 오류의 가능성도 높아집니다. 


따라서 클래스를 사용합니다

Class의 정의: Class = Data + Functions


일단 클래스의 객체가 생성되고 나면, 그 후에는 함수의 코드가 어떻게 구현됐는지 몰라도 함수를 사용하는데 아무런 문제가 없습니다. 

더불어서, 클래스를 정의함으로써 새로운 type이 생기게 됩니다.

다시 말해, 클래스는 (자동차, 사용자와 같은) 어떠한 개념/컨셉/실체를 나타내는 데이터해당 데이터를 기반으로 실행시킬 수 있는 함수들을 분리하지 않고 하나로 묶어서 해당 개념을 표현하는 나만의 새로운 데이터 타입을 만들 수 있게 하여 프로그래밍을 훨씬 효과적으로 할 수 있도록 해줍니다.

1월 29, 2022

Calculator 패키지 만들기

 이러한 구조의 패키지를 만들고 작동시켜보는것이 과제였다



  • ImportError: attempted relative import with no known parent package

→ main.py에서 상대경로로 add_and_multiply 임포트시 발생하는 에러

1
2
3
4
5
#relative path
from .calculator.add_and_multiply import add_and_multiply

if __name__ == '__main__': 
		print(add_and_multiply(1,2))

왜??

main 모듈에서 상대경로를 사용할 경우 파이썬이 상대경로의 출발점, 즉 main 모듈의 위치를 찾지 못하기 때문이다.

모듈을 사용할 때에는 2가지 방법이 있다

  1. 인터프리터에서 직접 실행하거나
    1. 이때 모듈의 이름은 자동적으로 main 으로 변경
  2. 다른 모듈에서 import해 실행하거나

모듈실행 뒤 상대경로를 통해 다른 모듈을 import 할 때,

파이썬은 모듈의 이름(name)에 기반을 두고 현재모듈의 위치를 찾는다

따라서 이름이 main 으로 바껴버린 모듈은 파이썬이 위치를 찾을수가 없음

relative path의 출발점이 되는(현재 import하는 위치인 모듈, 즉 __main__으로 이름이 바뀐 모듈) 위치를 못 찾아 위와 같은 에러가 발생하는 것

  • main module에서는 패키지의 모듈을 어떻게 임포트 해야 하는가??

(참조 : https://docs.python.org/3/tutorial/modules.html#intra-package-references)

따라서 main module에서는 절대 경로를 사용해주어야 한다.

1
2
3
4
5
#absolute path
from calculator.add_and_multiply import add_and_multiply

if name == 'main':
print(add_and_multiply(1,2))

“Note that relative imports are based on the name of the current module. Since the name of the main module is always "__main__", modules intended for use as the main module of a Python application must always use absolute imports.”

“relative import(상대가져오기)는 현재 모듈의 이름에 기반해있음을 기억하라. main module의 이름이 항상 main 이기에, 파이썬의 main module로 쓰여지기 위한모듈들은 항상 absolute import(절대가져오기)를 사용해야 한다”

  • add_and_multiply.py에서 multiplication.py의 multiply함수를 절대경로와 상대경로도 각각 임포트 해보고 main 모듈과 차이점을 생각해보고 결과를 출력해보기




     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    #from .multiplication import multiply
    from calculator.multiplication import multiply
    
    def add_and_multiply(a,b):
        return multiply(a,b) + (a+b)
    
    >> No module named 'calculator'
    
    절대 경로 실행시
    
    from .multiplication import multiply
    #from calculator.multiplication import multiply
    
    def add_and_multiply(a,b):
        return multiply(a,b) + (a+b)
    >>attempted relative import with no known parent package
    상대 경로 실행시
    

    디렉토리 구조상 두개다 문제 없이 실행되는것이 옳아보임에도 문제가 난다 흐음..

    절대경로 실행시에는 calculator패키지가 존재하지 않는것처럼 결과가 출력됐다.

    상대경로실행시에는 main.py에서 상대경로로 import할때와 같은 에러가 나온다

    에러 구글링도 해보고 여러 삽질을 하다가.. vscode를 끄고 폴더에 직접 들어가서 문제점을 찾을 수 있었다... 위의 주소에 에러의 원인이 있었다..



    (main.py는 calcuator 패키지 안에 있다)

    아니다..헛짚었다.. 파일 구조를 수정해줬음에도 여전히 같은 오류가 난다

    각고의 구글링을 통해 나와 같은 문제를 겪으신것으로 추정되는 선배님(??)의 블로그에서 해결방안을 찾았다.

    https://velog.io/@hkja0111/TIL-15-Import-Module-Package - 감사합니다..

    add_and_multiply가 현재 마치 main.py 처럼 메인 모듈 행세를 하고 있는 듯 하여(add_and_multiply가 current directory로 작동하기에, absolute path를 사용하려면 current directory인 add_and_multiply부터 시작하는것이 맞으니 caculator로 올라가지 않고 바로 multiplication부터 시작하면 되지 않나 하여) main.py의 경우처럼 절대경로로 import해보았다

    
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    # from .multiplication import multiply
    from multiplication import multiply
    
    def add_and_multiply(a,b):
        return multiply(a,b) + (a+b)
    
    print(add_and_multiply(1,2))
    
    >>5
    

    정상작동한다.. add_and_multiply.py 에서 실행한 경우 다른 모듈로서 import돼 실행된 것이 아니라 직접 실행(인터프리터상에서 직접실행하고 있다) 했기에 add_and_multiply.py가 메인 모듈의 취급을 받은 것이다. 그렇기 때문에 상위의 calculator 패키지가 존재하지 않는 것처럼 에러가 나왔고, 상대경로 또한 사용할 수 없었던 것이다





    위에 있던 이 글을 기억하자....

    1
    2
    3
    4
    5
    6
    7
    8
    9
    from .multiplication import multiply
    #from multiplication import multiply
    
    def add_and_multiply(a,b):
        return multiply(a,b) + (a+b)
    
    print(add_and_multiply(1,2))
    
    >> ImportError: attempted relative import with no known parent packa
    
    
    

    ⇒ 메인 모듈의 역할을 하기에 상대경로는 사용할 수 없는 모습이다


  • __init__.py 파일의 역할 정리하기

__init__.py 는 자신이 위치한 디렉토리가 패키지의 일부임을 확인해주는 역할을 한다.

python 3.3버전부터는 __init__.py가 없어도 패키지로 인식하지만, 하위호환을 위해 생성하는 것이 안전하다.

a. Import 할때 경로의 총 길이 줄여주기

    



b. Package에서 import 할 수 있는 변수/함수/클래스 제한하기

내부적으로만 사용돼야 하는 함수가 package외부에서 import되어 사용되는 것을 막기 위해서 __all__ 변수를 지정해 줄 수 있음

package를 통해 import 될 수 있는 요소들은 모두 __all__ 변수를 통해서 정의

__all__ 변수의 default 값은 모든 함수/변수/클래스임

그러므로 __all__ 변수를 따로 정의해줌으로 import가 될 수 있는 요소들을 제한 할 수 있는

__all__ 변수는 string 값의 요소를 가지고 있는 list(list of strings)

그러므로 import 되길 원하는 요소들을 string으로 list에 선언해주면 됨


1월 29, 2022

import는 어떻게 module과 package를 찾는가

1. sys.module과 sys.path 의 차이점

파이썬에서 모듈이나 패키지를 사용하기 위해선 해당 파일(모듈의 경우) 혹은 디렉토리(패키지의 경우) 가 어딨는지 파이썬이 찾을 수 있어야 import를 하여 사용할 수 있습니다. 이때 파이썬 정해진 순서에 따라 모듈 or 패키지를 찾습니다.

  1. sys.modules
  2. built-in modules
  3. sys.path
먼저, 2번의 built-in modules의 경우, 말 그대로 파이썬에서 제공하는 공식 라이브러리들을 의미합니다. 이미 파이썬에 포함돼 나오므로 파이썬이 쉽게 찾을 수 있습니다.

1번의 sys.modules는 파이썬이 가장 먼저 확인하는 곳 입니다.
sys.moudles는 이미 로드돼 있는 모듈에 이름을 mapping하는 dictionary로서, 이미 import 된 모듈과 package들을 저장하고 있습니다. 즉, sys.modules덕분에 한번 import한 모듈이나 package를 파이썬이 또 다시 찾을 필요가 없습니다. 반대로 말하자면, 새로 import 하는 모듈이나 패키지는 sys.modules에서 찾을 수 없다는 뜻입니다.
sys.modules는 강제로 다시 로드할 수 있도록 조작할 수 있습니다.
또한, Dictionary 형임에도 불구하고, 내부의 요소들을 마음대로 수정할 수는 없고, 필수적인 부분을 건들 경우 파이썬 전체에 문제가 생길 수도 있습니다. 


3번의 sys.path는 파이썬이 가장 마지막으로 보는 장소입니다.
sys.path는 기본적으로 list이며, string 요소들을 가지고 있는 list입니다.

각 string 요소들은 이처럼 특정 경로를 나타냅니다. 
파이썬은 이 list의 경로들을 하나하나 확인하면서 해당 경로에 import 하고자 하는 package혹은 모듈이 위치해 있는지 확인합니다. 

2. sys도 import 해야되는 모듈입니다. 파이썬은 sys 모듈의 위치를 어떻게 찾을 수 있을까요?

1
2
import  sys
print(sys.modules)

{'sys': <module 'sys' (built-in)>, 'builtins': <module 'builtins' (built-in)>
sys를 import하여 sys.modules를 print해보면 이를 알 수 있습니다. 
sys module은 built-in 돼있기에, built-in module들이 있는 부분에서 찾게 됩니다.


3. Absolute path와 relative path 차이점을 서술

  • 파이썬의 built-in 모듈과 pip를 통해 설치한 외부 모듈 및 패키지는 일반적으로 import 하는데 큰 문제가 되지 않습니다.

    Built-in 모듈은 당연히 잘 찾아지고, pip로 설치한 외부 모듈도 자동으로 site-packages 라는 디렉토리에 설치가 되는데, 이 site-packages는 sys.path에 이미 포함돼 있기때문에 찾는데 문제가 없습니다.

    문제는 직접 개발한 local package입니다. 직접 개발한 local package를 import 할때는 해당 package의 위치에 맞게 import경로를 잘 선언해야 합니다

    Local package를 import 하는 경로에는

    1. absolute path
    2. relative path

    가 있습니다

    • absolute path

      1. 이름 그대로 절대 경로입니다
      2. import를 하는 파일이나 경로에 상관없이 항상 경로가 동일하기 때문

      예를들어,



      my_app이라는 프로젝트이며 package1과 package2 라는 2개의 package를 가지고 있습니다

      그리고 package2는 subpackage1라는 중첩 package를 가지고 있습니다

      Absolute path를 사용해 package1 과 package2를 import 하면 다음과 같습니다

      from package1 import module1
      from package1.module2 import function1
      from package2 import class1
      from package2.subpackage1.module5 import function2
      

      경로들의 시작점이 전부 my_app 프로젝트의 가장 최상위 디렉토리에서 시작하는 것을 볼 수 있습니다

      예를들어, subpackage1의 module5 모듈의 function2 함수를 import하려 거치는 경로는 아래와 같고,

      my_app => package2 => subpackage1 => module5.py

      이를 윈도우의 directory 형식으로 바꾸면

      my_app\package2\subpackage1\module5.py

      파이썬에서는 slash나 backslash(\)대신에 dot(.)을 사용해서 경로를 표현합니다

      이미 my_app 프로젝트 안에 있으므로 my_app은 생략하고 경로를 표현하게 됩니다.

      package2.subpackage1.module5.py

      이걸 from import키워드를 사용해 import 하려면 어떻게 할까요??

      from package2.subpackage1.module5 import function2

      정리하자면, my_app 프로젝트 내에서는 어느 파일, 어느 위치에서 import 하던지 경로가 항상 위와 동일하게 되므로 absolute path라고 하는 것입니다

      참고로 current directory 즉 현재의 프로젝트 디렉토리는 default로 sys.path에 포함합니다.

      그러므로 absolute path 는 current directory부터 경로를 시작하게 되는 것입니다.

      일반적으로 local pacakge를 import 할 때는 absolute path를 사용하면 됩니다.

      그러나 경로가 길어질 수 있다는 단점이 있습니다.

    • relative path

      경로가 길어지는 absolute path 의 단점을 보완하기 위해서 relative path를 사용합니다.

      Relative path는 프로젝트의 최상단 디렉토리를 기준으로 경로를 잡는게 아니라. import하는 위치를 기준으로 경로를 정의합니다.

      그래서 relative path는 local package안에서 다른 local package를 import 할 때 사용됩니다



      예를들어 package2의 module3에서 package2의 class1과 package2의 하위 package인 subpackage1의 module5의 function2 함수를 import하려고 하면??

      # package2/module3
      
      from . import class1
      from .subpackage1.module5 import function2
      

      여기서 dot . 은 import가 선언되는 파일의 현재 위치를 이야기 합니다

      현재 위치는 package2/module3.py 이므로, 현재 위치에서부터 원하는 모듈의 경로만 선언해주면 되는 것입니다

      또한 dot2개를 사용할 수도 있습니다. dot 2개 .. 는 현재위치에서 상위 디렉토리로 가는 경로입니다

      # subpackage1/module5.py
      from ..module4 import class4
      

      Relative path는 선언해야 하는 경로의 길이를 줄여준다는 장점 은 있지만

      헷갈리기 쉽고 파일 위치가 변경되면 경로 위치도 변경되어야 하는 단점 이 있기에

      웬만한 경우 absolute path를 사용하는 것이 권장됩니다

 

1월 27, 2022

Function Parameter 정리


1. 왜 default value parameter 를 non-default value parameter 앞에 선언하면 안될까??


함수의 파라미터에 default 값을 정의해줄 수 있습니다.

다만 주의해야 할 점은, default 값이 정의된 parameter 가 default 값이 정의되지 않은 parameter 보다 먼저 위치해 있으면 안된다는 점입니다. 만일 default value parameter를 non-default value parameter 앞에 선언하면, syntax error가 발생합니다

1
2
3
4
5
def love_you(my_name = "정우성", your_name): #default 파라미터를 your_name이라는 non-default 앞에 선언함
print(f"{my_name} loves {your_name}")

Traceback (most recent call last):
File "python", line 1 # 선언하는 line1에서 오류가 난것 확인 가능
SyntaxError: non-default argument follows default argument

음..근데 왜 오류가 나는걸까요??

Syntax Error 이기에 파이썬 문법상 금지해놓은 경우입니다.


일단 이 사진을 보면서 각 parameter의 위치를 확인해보시면, Non-Default keyword-only argument가 Keyword-only Arguments with Default 보다 앞에 옵니다.

(당황)...??


사진 우측에 있는 얘네를 이야기 한 것입니다.

Non-Default keyword-only argument 는 말 그대로 기본값이 없는 키워드 온리 매개변수이고,

Keyword-only Arguments with Default 도 말그대로 기본값이 있는 키워드 온리 매개변수 입니다.

근데 자세히 보면 그렇지도 않습니다. non-default가 먼저 나오긴 하지만, non-default와 default가 혼재돼서 나오는 것을 확인해 볼 수 있습니다.

그럼 왜 에러가 뜨는걸까요...? 다시 한번 말하지만 syntax에러입니다. 문법 자체가 이러한 표현이 불가능하게 막아둔 것입니다. 

이렇게 막아둔 이유가 있습니다. 앞서 함수를 love_you("호날두") 로 호출한다면 "호날두"는 어디로 들어가야 할 지 길을 잃게 됩니다.  my_name에 들어가자니 your_name이 비어버리게 되죠.

non-default argument가 앞에 나옴으로서 함수에 주어진 값의 위치가 모호해지게 됩니다. 이러한 혼란을 피하고자 syntax error를 통하여 default-value parameter가 non-default value parameter 앞에 오는 것을 막은 듯 보입니다.


2. 위치 인수와 가변 인수 


1
2
3
4
5
6
def func_param_with_var_args(name, *args, age):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)

func_param_with_var_args("정우성", "01012341234", "seoul", 20)

 해당 스크립트를 실행하면, 


이러한 에러가 뜹니다. 에러를 자세히 보면 코드를 쉽게 고칠 수 있습니다. 'age'라는 keyword-only argument를 놓치고 있다 합니다.

age앞의 *args가 가변형이기에 "정우성"을 제외한 나머지 값들을 모두 빨아들이기 때문입니다.

이를 해결하기 위한 방법입니다.

1. 함수를 정의할 때 *args를 age 뒤로 보내주면 에러가 나오지 않습니다.

2. 함수에 인수를 전달할 때 


이렇게 Non-default keyword only argument인 age에 값을 지정함을 안내하기 위해서 인수에 age=20 이렇게 키워드를 기록해주면 인수가 제 자리를 찾아갑니다


3. 가변 키워드 인수


1
2
3
4
5
6
7
def func_param_with_kwargs(name, age, **kwargs, address=0):
    print("name=",end=""), print(name)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)
 
func_param_with_kwargs("정우성", "20", mobile="01012341234", address="seoul")

 해당 스크립트를 실행하면, SyntaxError가 나옵니다.

앞서 보았던 사진을 기억하시나요?? 가변 키워드 인수는 가장 마지막에 위치합니다.

파이썬 문법은 **kwargs 이후로 어떠한 인수도 넘길 수 없게 설정돼 있습니다.

**kwargs를 address=0 뒤에 배치하면 에러 없이 잘 출력됩니다


순서대로 name의 값은 "정우성", age의 값은 20 이 들어갑니다. 

Keyword only arguments with default인 address의 값이 순서상 마지막 인수로 주어졌지만,  address라는 키워드와 함께 주어졌기에 address값으로 들어가는 것을 볼 수 있습니다.


4. 모든 argument들


1
2
3
4
5
6
7
8
def mixed_params(name="아이유", *args, age, **kwargs, address):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")

마찬가지로 SyntaxError가 발생합니다. 

에러 없이 작동하도록 매개변수들의 위치를 바꾸어 보겠습니다. 

1
2
3
4
5
6
7
8
def mixed_params(age, name="아이유", *args, address, **kwargs, ):
    print("name=",end=""), print(name)
    print("args=",end=""), print(args)
    print("age=",end=""), print(age)
    print("kwargs=",end=""), print(kwargs)
    print("address=",end=""), print(address)

mixed_params(20, "정우성", "01012341234", "male" ,mobile="01012341234", address="seoul")


위치 인수인 age가 제일 앞으로 이동해야 하며, default argument인 name="아이유"는 그다음 ,non default 키워드 인수인 address는 가변 인수의 뒤에, 가변 키워드 인수의 앞에 위치해야 합니다. 

주어진 인수의 순서대로 20이 age에, "정우성"이 default argument인 name에, "01012341234"와 male이 variable length positinal argument에 들어갑니다. 

Non-default keyword only argument여서 값이 없던 address에 "seoul"이라는 값이 주어집니다.

가변 키워드 인수에 mobile="01012341234"의 키워드와 값이 주어져 잘 출력되는 것을 확인했습니다.



https://getkt.com/blog/python-keyword-only-arguments/ 해당 블로그를 참조하여 포스팅을 작성했습니다.


1월 27, 2022

집단자료형: Set,Dictionary, List,Tuple

1. Set과 Dictionary의 차이

    a. set은 요소들이 순서 없이 존재하므로 몇 번째 요소를 읽어들이거나 할 수 없습니다. 

        반대로 Dicitonary는 요소들을 key 값을 통하여 읽어들일 수 있습니다(key값 중복X)

    b. dictionary의 key값은 변경할 수 없는 형식임에 반해, value값은 mutable(변경가능)합니다

        반대로 set은 mutable한 리스트형 입니다

2. List와 Tuple의 차이   

    a. 가변형인 리스트와 달리 튜플은 한번 선언된 이후 수정이 불가능 합니다

    b. list는 수정이 가능하고 여러 수의 요소들을 저장할 수 있도록 했기때문에 tuple보다 차지          하는 메모리 용량이 더 큽니다. 이에 반해 tuple은 제한적인 만큼 용량이 적습니다. 

     따라서 수정이 필요없고, 간단한 데이터를 표현할 때는 tuple을 사용하는것이 효과적입니다

1월 26, 2022

ax=b를 만족하는 x 값 구하기

 

문제는 이러합니다.

처음 접근: x의 리스트를 구해서 x를 if문 안에 넣으려 했습니다. for문을 이용하여 x를 담을 리스트에 x값을 넣으려 했으나, for문의 범위를 정하는 단계부터 어려움을 겪었습니다.


옳게된 접근

약간의 수학적 지식이 필요합니다.. 


a와 b의 값에 따라 해의 개수가 정해지기에, x를 따로 구할 필요가 없습니다. 위의 도표에 따라 if문을 작성해 줍니다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
a = int(input("첫번째 정수"))
b = int(input("두번째 정수"))

if a != 0:
  if if type(b/a) != int:      
    print("No Solution")
  elif if type(b/a) == int:    
print(b/a) elif a == 0: if b != 0: print("No Solution") elif b == 0: print("Many Solutions")

음 .. 당연히 될 줄 알았는데 해결이 되지 않습니다...

위의 도식에 따라 if문을 작성하기만 하면 되는 줄 알았는데 도무지 이유를 모르겠습니다..


무엇이 문제였는지 테스트케이스를 찬찬히 뜯어보다가 문제를 발견했습니다.

a = 2

b = -4 를 입력하면 

x가 -2가 나와야 하는데 "No Solution"이 지속적으로 발생합니다.

왜 그럴까요???

print(type(b/a)) 를 하고 나서야 이유를 알았습니다.


당연히 -4를 2로 나누면 당연히 정수 2가 나오겠거니.. 한 제 생각이 틀린것입니다.

파이썬은 나누기를 하면 float 값을 반환합니다!!!!

그래서 계속 No solution이 나왔던 것입니다.

이 문제를 단순 data type 확인을 통해 풀 수 없음을 깨달아야 합니다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
a = int(input("첫번째 정수"))
b = int(input("두번째 정수"))

if a != 0:
  if b%a != 0:     # if type(b/a) != int 이전 코드
    print("No Solution")
  elif b%a == 0:   # if type(b/a) == int 이전 코드
    print(b/a)
elif a == 0:
  if b != 0:
    print("No Solution")
  elif b == 0:
    print("Many Solutions")

b/a 가 정수 값인지 확인하기 위하여 b를 a로 나눴을 때의 나머지가 0 인지를 검사하였습니다. 이렇게 작성한다면 오류 없이 문제가 해결됩니다.

5번 라인과 7번라인에 에 int(b/a) != b/a 이런식으로 b/a가 int 값이 되는지 확인하는 방법도 있습니다.


b/a의 타입을 print해보지 않았다면 아직도 헤매고 있었지도 모릅니다..

이렇듯 문제를 해결하는 과정에서 도무지 알 수 없는 에러들이 발생하면 코드의 전개 과정을 print

등을 이용하여 일일히 뜯어본다면 문제 해결에 도움이 될 수 있다는 것을 배운 문제풀이였습니다.


1월 26, 2022

Basic Grammar1.

 파이썬 기초 문법 학습 과정에서 개인적으로 헷갈리거나 어려웠던 내용들을 정리했습니다.

1. Data types

 : 해당 데이터의 타입을 이야기 합니다. 2 / "2" / 2.0 은 사람에게는 문맥상 같은 의미를 가지지만, 컴퓨터에는 해당 3개가 모두 다른 의미를 가집니다. 그렇기에 정확한 data type의 값을 지정하는 것이 중요합니다. 

  1. String : "" 안에 있는 글자들
  2. Integer : 정수
  3. Float : 소수점 숫자
  4. Complex Numbers
  5. Boolean

 파이썬에는 다음과 같은 데이터 타입들이 존재합니다.

 4번 complex Numbers를 볼까요? 생소한 표현입니다. 이는 실수와 허수를 포함하고 있는     "복소수" 를 이야기합니다. 파이썬에서는 j를 이용하여 허수를 표현합니다.

ex) 1 + 3j, 2-4j

5번 Boolean은 True 와 Fasle, 즉 참과 거짓을 나타내는 데이터타입 입니다.

"True" 혹은 "False"처럼 큰따옴표 "" 로 묶어주면 string으로 잡히게 됩니다. true나 false처럼 대문자를 마음대로 변경해서도 안됩니다. 정확히 True와 False로 적어주셔야 합니다.


2. 변수 이름 법칙 

변수는 데이터의 식별자(일종의 별명)의 역할을 합니다. 이러한 변수의 이름을 정하는 것에도 법칙이 있습니다.

  • 변수이름은 영어 알파벳/ 숫자 / _(underscore)으로만 구성해야 합니다
  • 변수이름의 첫 글자는 알파벳이나 _(underscore)으로만 시작해야 합니다
  • 숫자로 시작할 수 없습니다
  • 영어 알파벳은 대,소문자가 구분이 됩니다
특히 저는 언더스코어_ 대신 - 를 사용한다거나, 변수의 중간에 공백(스페이스)를 넣는다거나 하는 실수를 자주 하는데요, 이러한 실수를 하지 않도록 주의해야 합니다.

3. Math Expressions

num1 = 10
num1 = num1 + 1

은 

num += 1 

로 간단하게 풀어쓸 수 있습니다. 

이러한 표현 방식은 +에만 해당되는 것이 아닙니다. 

-=

*= 

/=

%= 

등, 변수 이름을 두번 반복하는 번거로움을 피하기 위해서 다양한 연산방식을 짧게 ()= 식으로 사용할 수 있습니다.

4. Concatenating Text Strings

string을 더하는 방법엔 두가지가 있습니다

1. + 를 사용하기

print("Hello, " + "World") 

결과는 "Hello, World" 가 될 것입니다.

+는 특정 문자열이 변수에 저장돼 있을 때 사용하면 편리합니다. 

1
2
3
name = input()

print("Hello, " + name)

이런식으로 문자열이 들어있는 변수를 string에 이어줄 수 있습니다.

2. literal string interpolation 

a. 따옴표 앞에 f 를 붙여줍니다

b. 치환하고 싶은 변수(변수가 아니어도 됩니다, 함수 호출 등 가능) 를 {} 를 사용해서 표시합 니다

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
date            = 1980
python_inventor = "Guido van Rossum"
location        = "Centrum Wiskunde & Informatica"
country         = "Netherlands"

print(f"""Python was conceived in the late {date}s 
by {python_inventor} at {location} (CWI) in the {country} as a successor 
to the ABC language (itself inspired by SETL), capable of exception handling 
and interfacing with the Amoeba operating system. 
Its implementation began in December 1989.""")

이렇듯 길고 복잡한 문자열의 경우에 literal string interpolation을 사용해주면 효과적입니다.


1월 25, 2022

CSS: display

display 속성의 외부 디스플레이 유형은 레이아웃의 흐름에 요소가 어떤식으로 참여하는지를 나타냅니다. 이에 해당하는 값으로 block, inline, inline-block이 있습니다.


1. inline

 : 인라인 요소 박스를 만듭니다. 새로운 줄을 만들지 않으며, 필요한 너비만 차지합니다. 공간이 있다면 다음 요소도 같은 라인에 위치합니다. 

<span><a><img>등이 대표적인 인라인 요소입니다.


inline 요소를 알아보기 위한 간단한 예제가 있습니다

1
2
    <div> 다음의 span은 <span class="inlinecl">인라인 요소</span>입니다. inline의 시작과 끝을 알기 위해 배경색을 지정합니다
    </div>


1
2
3
.inlinecl {
  background-color: blue;
}

블록 요소인 div 안에 inline 요소인 span 이 존재합니다. inline의 성향을 살려 문단이 끊어지지 않고 이어지는 모습을 확인할 수 있습니다.




2. block

: 블록 요소 박스를 만듭니다. 줄바꿈을 하여 시작하며, 좌우로 최대한으로 늘어납니다. 

앞서 예제의 span을 <p>태그로 바꾸어 보았습니다

1
2
<div> 다음의 p는 <p class="blockcl">블록 요소</p>입니다. block의 시작과 끝을 알기 위해 배경색을 지정합니다
    </div>

앞서 css의 클래스명을 .blockcl로 바꾸어주면, 차이를 확인할 수 있습니다.


p요소는 p 이전과, 자기 자신, p 이후의 세 부분으로 레이아웃을 바꿔 놓았습니다. 

줄바꿈을 강제하는 블록요소의 특성이 드러나는 부분입니다. 


만약 inline 요소 안에 block을 넣는다면 줄바꿈이 일어나지 않을까요? css를 그대로 두고 html을 변경해 보았습니다.
1
2
 <span> 과연 block을? <p class="blockcl">block</p>과연?
    </span>

block요소인 p가 줄바꿈을 강제하여 세줄로 나눠지는 것을 확인할 수 있습니다.


3. inline-block

: inline 요소와 비슷하지만, 높이와 너비를 지정할 수 있습니다. 줄바꿈이 일어나지 않습니다.  지정하지 않을 시 inline과 같이 컨텐츠 영역이 잡힙니다.  

브라우저 너비를 채우며, 알맞게 줄바꿈되는 박스 그리드가 생성됩니다.

display 프로퍼티에 inline-block값을 설정합니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
    <div class="container">
      <nav>
        <li>밥1</li>
        <li>밥2</li>
        <li>밥3</li>
        <li>밥4</li>
      </nav>
      <div class="column2">
        <section>안녕안녕나는지수야</section>
        <section>헬륨가스먹었더니이렇게됐지헬륨가스먹었더니이렇게됐지헬륨가스먹었더니이렇게됐지헬륨가스먹었더니이렇게됐지헬륨가스먹었더니이렇게됐지헬륨가스먹었더니이렇게됐지헬륨가스먹었더니이렇게됐지헬륨가스먹었더니이렇게됐지헬륨가스먹었더니이렇게됐지</section>
      </div>
    </div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
nav {
  display: inline-block;
  vertical-align: middle;  #inline-block은 vertical-align의 영향을 받음
  width: 20%;
  background-color: rebeccapurple;
}
.column2 {
  display: inline-block;
  vertical-align: middle;
  width: 70%;
  background-color: yellowgreen;
}

inline-block을 이해하기 위해 예제를 설정했습니다. 

<nav>의 vertical-align을 변경하게 되면 보라색 란의 위치가 변경되는 것을 확인할 수 있습니다. 또한, 각 요소의 width와 height값을 바꿔줌으로써 보라색과 연두색 란의 크기를 조절할 수 있습니다. 이처럼 inline-block은 width와 height를 가진 inline요소를 생성합니다. 

nav와 .column2의 width를 각각 26%, 75%로 지정하면 줄바꿈이 되어 보라색 란 밑에 연두색 란이 오는 것을 확인할 수 있습니다. 이처럼  inline-block은 너비를 채우고 나면 자연스럽게 줄바꿈 됩니다.
1월 25, 2022

CSS: position의 속성 - relative, absolute, fixed

 CSS...css는 어렵습니다... 

마치 초등학교 시절로 돌아가 종이 접기를 하며 공간에 대해 다시금 배우는 느낌이에요..


이번에는 CSS중에서도 헷갈리는 position의 속성에 대해 알아보겠습니다.

position 속성은 문서상에 요소를 배치하는 방법을 지정합니다. position의 기본값은 static이며, 요소를 일반적 문서 흐름에 따라 배치합니다. static일때 left right top 등은 비활성화 되기에, 아무런 영향을 미치지 않습니다.

1. relative 

요소를 일반적인 흐름에 따라 배치하고, 자기 자신을 기준으로 top,right,bottom등 을 적용합니다.(원래 있어야 되는 그 자리를 기준으로) .

예를 들어, 

1
2
3
4
<div class="box" id="one">One</div>
<div class="box" id="two">Two</div>
<div class="box" id="three">Three</div>
<div class="box" id="four">Four</div>
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.box {
  display: inline-block;
  width: 100px;
  height: 100px;
  background: red;
  color: white;
}

#two {
  position: relative;
  top: 20px;
  left: 20px;
  background: blue;
}

(출처: https://developer.mozilla.org/ko/docs/Web/CSS/position )


를 보시면, two id를 가진 박스가 원래 있어야 할 위치를 기준으로 

위(top)에서 20px , 왼쪽(left)에서 20px 떨어져 위치한 것을 볼 수 있습니다


relative 요소는 다른 요소들에는 영향을 주지 않습니다. Two를 제외한 다른 요소들은 Two가 원래 위치에 있는 것처럼 배치되는 것을 확인할 수 있습니다.


2. absolute

요소는 일반적인 문서 흐름에서 벗어나고, 페이지 레이아웃에 공간도 배정하지 않습니다. 대신 부모의 position 값이 static이 아닐때, 자신의 left,right,top,bottom의 기준을 부모로 잡습니다. 만약 부모의 position 값이 static이라면, 그 위의 부모를 찾아나섭니다. 없다면 전체 문서를 기준으로 잡습니다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
.box {
  display: inline-block;
  width: 100px;
  height: 100px;
  background: red;
  color: white;
}

#two {
  position: absolute;
  top: 20px;
  left: 20px;
  background: blue;
}아

앞서의 HTML과 CSS에서 position 값 만을 absolute로 바꿔주었습니다. 

static이 아닌 부모를 찾지 못하여, 전체 문서를 기준으로 잡아 20px씩 이동을 한 모습입니다.

앞서의 예제와 다르게, 다른 요소들이 Two의 자리를 채웠습니다. absolute로 배치된 요소는 흐름에서 제거되기에, 다른 요소들은 마치 Two가 없는 것처럼 배치됩니다.

3. fixed

상자에서 완전히 벗어나 웹페이지를 기준으로 자신의 위치를 잡습니다. 따라서 스크롤를 하더라도 화면의 특정 지점에 고정되어있는 요소를 생성할 수 있습니다. 


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
.box {
  display: inline-block;
  width: 100px;
  height: 100px;
  background: red;
  color: white;
}

#two {
  position: fixed;
  top: 20px;
  right: 20px;
  background: blue;
}
body {
  height: 2000px;
}

앞서 예제에서 position 값을 fixed로 변경하고, 스크롤을 확인하기 위해 body에 height값을 주었습니다.

right에 20px을 주었기에, 화면 위와 오른쪽에서 20px 떨어진 곳에 위치한 모습입니다.


위에서 보이듯이 스크롤을 해도 그 자리에 고정돼 있음을 확인할 수 있습니다. 

position 속성은 페이지 레이아웃을 이해하는데 있어 매우 중요하기에 다양하게 사용하며 이해하는 과정이 필요합니다.