RDB에서 한 스키마에 복수 개의 primary key가 있으면, 그들을 혼합하여 유일성을 판단한다. 예를 들어, 학번으로 유일성을 구분해야 하는 '학생' 테이블에서는, '학번'이라는 하나의 primary key를 사용할 수도 있고, '학년', '반', '번호'로 컬럼을 나누어 이들에게 모두 primary key 제약을 걸 수도 있다는 것이다.

'Python 계열 > SQLAlchemy' 카테고리의 다른 글

Column.like, Column.ilike, not_, ~expr  (0) 2019.02.12
특정 컬럼만 SELECT  (0) 2019.02.12
aliasing과 함수  (0) 2019.02.12
limit  (0) 2019.02.12
query 객체가 실제로 쿼리를 실행하는 시기  (0) 2019.02.12

`@app.route(...)에선 데코레이션된 view function이 GET 요청만을 처리할 수 있도록 만든다. route 데코레이터의 시그니처는route(self, rule, **options)`인데, 라우팅이 되면 werkzuug.routing.Rule 객체를 사용해 이를 등록하므로, 키워드 인자인 options는 Rule 클래스의 생성자 인자와 동일하다.

'Python 계열 > Flask' 카테고리의 다른 글

GET '/' -> 'Hello World'  (1) 2019.02.12

pip로 설치한 패키지들은, 흔히 말하는 '전역 환경'에서 관리되기에 문제가 생길 수 있습니다. 한 프로젝트에선 Flask 0.13을 쓰고 다른 프로젝트에선 Flask 1.0을 쓰는 버전 관리 문제나, 다른 프로젝트에선 쓰지 않을 numpy를 사용한다거나 하는 경우입니다. 특히 위와 같은 버전 관리 문제의 경우, 여간 번거로운 일이 아닙니다. 프로젝트 A에서 Flask 0.13, 프로젝트 B에서 Flask 1.0을 쓴다면, 아래와 같은 시나리오가 전개됩니다.

  • 프로젝트 A를 진행하기 위해 Flask 0.13 설치
  • 프로젝트 B를 진행하기 위해 Flask를 uninstall하고 1.0 설치
  • 다시 프로젝트 A를 진행하기 위해 Flask를 uninstall하고 0.13 설치
  • Flask uninstall 과정에서 werkzueg, jinja와 같은 의존성 라이브러리는 제거되지 않아 1.0에선 생기지 않던 오류 발생
  • pip, wheel, setuptools만 남기고 모두 삭제하고 다시 Flask 0.13을 비롯한 프로젝트 A의 의존성 설치

이런 문제를 해결하기 위해 virtual environment라는 개념이 존재합니다. 이는 디렉토리 단위로 격리된 Python 환경을 구성해 줍니다. 대표적으로 virtualenv라는 CLI 라이브러리를 사용합니다.

$ pip3 install virtualenv

virtualenv -p [python_version] [venv_name]

virtualenv의 사용법은 매우 간단합니다.

$ virtualenv venv
Using base prefix '/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6'

(...)

Installing setuptools, pip, wheel...done.

위의 명령을 실행하면 venv라는 디렉토리가 생성되고, 격리된 Python 환경이 구성됩니다. 기본 Python 버전은 virtualenv 패키지가 설치된 경로의 python입니다. 위의 경우 전역의 python 3.6.5 환경에 설치되어 있는 virtualenv를 사용했으므로, python 3.6.5로 구성됩니다. 특정 버전에 대해서 가상 환경을 구성하려면, --python이나 -p 인자를 이용해 버전을 명시하면 됩니다.

$ virtualenv -p python2 venv
Running virtualenv with interpreter /usr/local/bin/python2

(...)

Installing setuptools, pip, wheel...done.

. [venv_name]/bin/activate

venv 하위의 bin 디렉토리에 있는 activate 파일을 실행시켜 가상 환경을 활성화합니다. 활성화에 성공하면, 쉘의 맨 앞에 가상 환경의 디렉토리명이 표시됩니다.

$ . venv/bin/activate
(venv) $

활성화된 가상 환경 안에서 사용하는 pip는 해당 가상 환경에서만 적용되기 때문에, 전역 환경과 확실하게 격리된 환경을 구성할 수 있게 됩니다. 또한 venv가 활성화되는 주체는 쉘 단위기 때문에 디렉토리를 이동해도 계속해서 유지되며, 가상 환경 내에서는 pip와 pip3를 구분하지 않습니다. 가상 환경에서 빠져 나오려면, deactivate 명령을 입력합니다.

(venv) $ deactivate
$ 


'Python 계열 > Python External Library' 카테고리의 다른 글

[Python External Library] virtualenvwrapper  (0) 2018.09.07

virtualenv는 디렉토리 단위로 가상의 Python 환경을 구성함에 있어 굉장히 강력합니다. 이 점에 대해선 반박할 여지가 없는데, 한 가지 단점이라면 가상 환경이 한 곳에서 관리되지 않아 기억하기 번거롭다는 것입니다. virtualenvwrapper를 사용할 경우, 터미널이 현재 위치한 경로와 관계 없이 가상 환경을 활성화할 수 있다는 장점이 있습니다. 조금의 설정 과정을 거치고 나면, 더욱 더 편하게 virtual environment를 관리하고 사용할 수 있게 됩니다. virtualenvwrapper는 내부적으로 virtualenv를 의존합니다.

$ pip3 install virtualenvwrapper

가상 환경을 관리할 디렉토리 생성 & 환경 변수 설정

먼저 홈 디렉토리로 이동합시다.

$ cd ~

가상 환경이 들어갈 디렉토리를 생성합니다. .venvs 라는 이름을 사용하겠습니다.

$ mkdir .venvs

이제 홈 디렉토리의 .bashrc.zshrc, .profile처럼 쉘의 환경 변수를 관리할 수 있는 곳에 WORKON_HOMEVIRTUALENVWRAPPER_PYTHON 환경 변수를 export하고, virtualenvwrapper.sh를 실행하도록 설정합니다.

export WORKON_HOME=~/.venvs
export VIRTUALENVWRAPPER_PYTHON="$(which python3)"
source /usr/local/bin/virtualenvwrapper.sh

virtualenvwrapper! 써보자!

mkvirtualenv [venv_name]

mkvirtualenvvenv_name을 이름으로 하는 가상 환경을 생성합니다.

$ mkvirtualenv test
Using base prefix '/usr/local/Cellar/python/3.6.5_1/Frameworks/Python.framework/Versions/3.6'
New python executable in /Users/planb/.venvs/test/bin/python3.6
Also creating executable in /Users/planb/.venvs/test/bin/python
Installing setuptools, pip, wheel...done.
virtualenvwrapper.user_scripts creating /Users/planb/.venvs/test/bin/predeactivate

(...)

virtualenvwrapper.user_scripts creating /Users/planb/.venvs/test/bin/get_env_details
(test) $

가상 환경이 생기고, 즉시 activate됩니다. virtualenvwrapper는 virtualenv를 의존하고 있기 때문에, 명령어도 꽤 유사합니다. 가상 환경에 다른 Python 버전을 사용하고자 하는 경우 virtualenv 때처럼 -p--python 인자를 사용하면 됩니다.

$ mkvirtualenv -p python2 test_python2
Running virtualenv with interpreter /usr/local/bin/python2
New python executable in /Users/planb/.venvs/test_python2/bin/python2.7
Also creating executable in /Users/planb/.venvs/test_python2/bin/python
Installing setuptools, pip, wheel...done.

(...)

virtualenvwrapper.user_scripts creating /Users/planb/.venvs/test_python2/bin/get_env_details
(test_python2) $

가상 환경을 빠져나오려면, virtualenv와 동일하게 deactivate를 사용합니다.

(test_python2) $ deactivate
$

workon ([venv_name])

workon 명령은 venv_name에 해당하는 가상 환경에 진입하거나, venv_name이 전달되지 않는 경우엔 가상 환경의 목록을 불러옵니다.

(test_python2) $ workon
test
test_python2
(test_python2) $ workon test
(test) $

rmvirtualenv [venv_names ...]

rmvirtualenv 명령은 venv_names에 해당하는 가상 환경을 모두 제거합니다.

$ rmvirtualenv test test_python2
Removing test...
Removing test_python2...

제거하려는 가상 환경에 workon(activate)되어 있다면, 오류가 발생합니다.

(test) $ rmvirtualenv test
Removing test...
ERROR: You cannot remove the active environment ('test').
Either switch to another environment, or run 'deactivate'.


re는 Python에서 정규 표현식을 사용하기 위한 모듈입니다. 이는 Perl에 있는 것과 유사한 정규 표현식 연산을 제공합니다. str와 bytes 타입에 모두 적용 가능하지만, str 패턴을 bytes 객체에 적용하거나 bytes 패턴을 str 객체에 적용하는 것은 불가능합니다. 이스케이핑은 \ 기호를 사용합니다.

모듈 레벨 함수

re 모듈에는 정규 표현식을 위한 많은 함수들이 존재합니다.

re.compile(pattern, flags=0)

인자로 전달된 정규 표현식 문자열 pattern을 통해 Pattern 객체를 만들어 반환합니다.

Pattern 객체에 대한 것들은 아래에서 다시 설명합니다.

re.search(pattern, string, flags=0)

string을 스캔하여 pattern이 일치하는 첫 번째 위치를 찾고, 이에 대응되는 match 객체를 반환합니다. 문자열의 어느 위치도 패턴과 일치하지 않으면 None을 반환합니다.

re.match(pattern, string, flags=0)

string의 선두에 0개 이상의 문자가 pattern과 일치하는 경우, 대응하는 match 객체를 반환합니다. 문자열이 패턴과 일치하지 않으면 None을 반환합니다. 1개 이상의 \n으로 이루어진 multiline string의 경우에도 문자열의 시작 부분을 기준으로 판단합니다.

  • search : 문자열의 어느 위치든 pattern과 일치하는지의 여부를 판단
  • match : 문자열의 시작 부분에서만 pattern과의 일치 여부를 판단

re.fullmatch(pattern, string, flags=0)

string의 전체가 pattern과 일치하면 대응하는 match 객체를 반환합니다. 여기서도 문자열이 패턴과 일치하지 않으면 None을 반환합니다.

re.split(pattern, string, maxsplit=0, flags=0)

string을 전달된 pattern을 기준으로 split합니다. maxsplit최대 몇 개까지 문자열을 split할지를 나타냅니다. 해당 인자가 0이 아니면, 최대 maxsplit 만큼의 문자열 잘라내기가 발생하고 나머지 문자열이 list의 마지막 요소로 반환됩니다.

re.findall(pattern, string, flags=0)

string에서 pattern에 맞는 모든 문자열을 list로 반환합니다. 스캔은 왼쪽에서 오른쪽으로 진행되며, 발견된 순서대로 리스트에 추가됩니다.

re.finditer(pattern, string, flags=0)

string에서 pattern에 맞는 모든 문자열에 대한 match 객체를 yield하는 iterator를 반환합니다. findall과 동일하게 왼쪽에서 오른쪽으로 스캔이 진행되며, 발견된 순서대로 match 객체가 iterator에 추가됩니다.

re.sub(pattern, repl, string, count=0, flags=0)

string에서 pattern과 일치하는 부분은 repl로 변경하여 반환. 정규 표현식 기반의 str.replace()라고 생각하면 됩니다.

re.subn(pattern, repl, string, count=0, flags=0)

re.sub()와 같은 작업을 수행하지만 replace한 문자열의 갯수가 포함된 tuple을 반환합니다.

re.escape(pattern)

ASCII 문자, 숫자 및 _(underscore)를 제외한 패턴의 모든 문자를 이스케이프 처리합니다. 이는 메타 문자(\, %, *, + 등)가 포함되어 있을 수 있는 리터럴 문자열을 정규 표현식에 사용하는 경우 매우 유용합니다.

re.purge()

모듈 레벨 함수를 이용해 정규 표현식 관련 작업을 수행할 경우, 인자로 전달된 pattern은 함수 호출마다 Pattern 객체로 변환됩니다. 해당 함수를 이용해 정규 표현식 캐시를 지울 수 있습니다.

정규 표현식 객체(Pattern 객체)

같은 정규 표현식을 가지고 재사용하는 경우, re.compile을 통해 Pattern 객체를 만들어 사용하는 것이 더 효율적입니다. 해당 객체는 아래와 같은 메소드와 속성들을 가지고 있습니다.

regex.search(string[, pos[, endpos]])

미리 컴파일된 정규 표현식을 사용한다는 점을 제외하면 re.search()와 동일하며, 선택 인자 posendpos는 각각 search가 동작할 시작 인덱스마지막 인덱스를 명시하여 검색 영역을 제한하기 위해 사용됩니다. 각각 0, len(string)입니다.

regex.match(string[, pos[, endpos]])

미리 컴파일된 정규 표현식을 사용한다는 점을 제외하면 re.match()와 동일하며, 선택 인자들은 regex.search()와 동일한 의미입니다.

regex.fullmatch(string[, pos[, endpos]])

미리 컴파일된 정규 표현식을 사용한다는 점을 제외하면 re.match()와 동일하며, 선택 인자들은 regex.search()와 동일한 의미입니다.

regex.split(string, maxsplit=0)

미리 컴파일된 정규 표현식을 사용한다는 점을 제외하면 re.split()과 동일합니다.

regex.findall(string[, pos[, endpos]])

미리 컴파일된 정규 표현식을 사용한다는 점을 제외하면 re.findall()과 동일하며, 선택 인자들은 regex.search()와 동일한 의미입니다.

regex.finditer(string[, pos[, endpos]])

미리 컴파일된 정규 표현식을 사용한다는 점을 제외하면 re.finditer()와 동일하며, 선택 인자들은 regex.search()와 동일한 의미입니다.

regex.sub(repl, string, count=0)

미리 컴파일된 정규 표현식을 사용한다는 점을 제외하면 re.sub()와 동일합니다.

regex.subn(repl, string, count=0)

미리 컴파일된 정규 표현식을 사용한다는 점을 제외하면 re.subn()과 동일합니다.

regex.groups

정규 표현식에 존재하는 그룹의 갯수를 반환합니다. re 모듈에서 감지할 수 있는 그룹의 문법은 (?P<id>...)입니다.

regex.groupindex

그룹 이름을 번호와 매핑한 dictionary를 반환합니다. 해당 정규 표현식에 그룹이 사용되지 않았다면 비어 있는 dictionary가 반환됩니다.

regex.pattern

해당 객체를 만들 때 사용한 정규 표현식 문자열을 반환합니다.

match 객체

re 모듈의 많은 함수와 메소드에서 match 객체를 반환합니다. match 객체는 아래와 같은 메소드와 속성들을 가집니다.

match.group([group1, ...])

해당 match 객체의 subgroup 하나를 반환합니다. 인자를 전달하지 않거나 0을 전달하면 match 전체를 반환하고, 여러 개의 인자를 전달하는 경우 인자 당 하나의 항목으로 이루어진 tuple을 반환합니다. 인자로 전달된 그룹 번호가 음수이거나 그룹의 수보다 큰 경우 IndexError가 발생합니다.

match.__getitem__(g)

match.group(g)와 동일한 역할을 합니다.

match.groups(default=None)

match 객체의 모든 subgroup을 tuple로 반환합니다.

match.groupdict(default=None)

그룹 이름을 key로 한 subgroup의 dictionary를 반환합니다.

match.pos & match.endpos

각각 Pattern 객체의 search()match() 메소드에 전달된 posendpos 인자의 값입니다.

match.re & match.string

각각 match 객체 생성 시 사용된 Pattern 객체, search()match()에 전달된 string 인자를 반환합니다.


'Python 계열 > Python Standard Library' 카테고리의 다른 글

[Python Standard Library] time  (0) 2018.09.07
[Python Standard Library] random  (0) 2018.09.07

Python에서 시간에 접근하기 위해 time 모듈을 사용할 수 있습니다. 이는 다양한 시간 관련 기능을 제공합니다. time 모듈에서 중요하게 생각하는 Epoch(기원)시간이 시작되는 지점이며, 이는 플랫폼에 따라 다릅니다. Windows와 대부분의 Unix 시스템에서는 1970년 1월 1일 00:00:00(UTC)입니다. 주어진 플랫폼에서 epoch를 알고 싶다면, 아래 코드를 실행시키면 됩니다.

time 모듈에서는 아래의 용어들을 자주 사용합니다.

  • 타임스탬프(TimeStamp) : Epoch 이후로, 초 단위로 측정한 절대시간입니다.
  • 협정세계시(UTC) : 1972년부터 시행된 국제 표준시. 영어권의 사람들과 프랑스어권의 사람들은 각각 자신의 언어로 된 CUTTUC를 사용하길 원했는데, 이 분쟁은 두 언어 모두 C, T, U로 구성되어 있다는 것에 착안하여 UTC로 이름지어 졌습니다.
  • 그리니치 평균시(GMT, Greenwich Mean Time) : 런던 그리니치 천문대의 자오선상에서의 평균 태양시. UTC라고 부르기도 하는데, UTC와 GMT는 초의 소숫점 단위에서만 차이가 나기 때문입니다.
  • 지방표준시(LST, Local Standard Time) : UTC를 기준으로 경도 15도마다 1시간씩 차이가 발생하는 시간. 한국은 동경 135도를 기준으로 하고 있으며, 따라서 9시간 빠릅니다.

Epoch 이후의 시간은 초 단위로 누적되며, 거의 모든 POSIX 호환 플랫폼에서 윤초는 제외됩니다. time 모듈은 epoch 이전의 날짜와 시간을 처리하지 못할 수도 있으며, 미래 시간의 한계점은 해당 모듈이 의존하고 있는 C 라이브러리에 의해 결정됩니다. 32비트 시스템의 경우 일반적으로 2038년입니다.

epoch부터 현재까지의 시간

time.time()

Epoch부터 현재까지의 시간을 초 단위로 환산하여 float로 반환합니다. '현재 시간'의 기준은 LST입니다. UTC 기준의 timestamp를 얻어내려면, 아래의 time.mktime()time.gmtime()을 함께 사용하면 됩니다. 일반적으로 Unix 시간(Unix Timestamp)이라고 합니다.

time.gmtime([secs])

Epoch부터 인자로 전달된 secsGMT 기준struct_time 객체로 변환하여 반환합니다. 선택 인자인 secs가 제공되지 않았거나 None이면 time.time()에 의해 반환된 timestamp가 사용됩니다.

time.localtime([secs])

time.gmtime()과 비슷하지만 LST 기준struct_time 객체를 만들어 반환합니다.

똑같은 timestamp를 전달하였으나, 실행 환경이 한국 시간 기준이므로 time.gmtime()보다 9시간이 빠릅니다.

time.mktime(t)

time.localtime()의 역함수입니다. struct_time 객체를 받아 time.time()과 호환되는 float 형태의 timestamp를 반환합니다.

time.struct_time 객체

time.gmtime(), time.localtime() 등에서 반환되는, named tuple 형태로 이루어진 시간을 다루는 객체입니다. 다음과 같은 필드를 가지고 있습니다.

  • 0: tm_year
  • 1: tm_mon
  • 2: tm_mday
  • 3: tm_hour
  • 4: tm_min
  • 5: tm_sec
  • 6: tm_wday
  • 7: tm_yday
  • 8: tm_isdst
  • N/A: tm_zone - timezone 이름
  • N/A: tm_gmtoff - UTC로부터 몇 초나 앞서 있는지(KST의 경우 9시간 앞서 있으므로 32400)

문자열과의 변환

time.strftime(format[, t])

struct_time 객체인 인자 tformat에 지정된 문자열 형태로 변환합니다. t가 제공되지 않으면 time.localtime()에 의해 반환된 시간이 적용됩니다. format은 문자열이어야 합니다. format string의 종류는 Python library reference에서 확인할 수 있습니다.

time.strptime(string[, format])

string을 파싱하여 struct_time 객체로 변환합니다. format은 기본적으로 "%a %b %d %H:%M:%S %Y" 형태입니다.


'Python 계열 > Python Standard Library' 카테고리의 다른 글

[Python Standard Library] re  (0) 2018.09.07
[Python Standard Library] random  (0) 2018.09.07

난수(무작위 값)이 필요할 때가 있습니다. Python의 빌트인 모듈인 random을 사용하면, 특정한 정수 범위 내에서 하나를 선택하거나, 0에서 1 사이의 실수를 가져오거나, iterable 객체에서 요소를 선택하는 등의 일을 할 수 있습니다. Python은 난수 생성을 위해 Mersenne Twister(메르센 트위스터) 알고리즘을 사용하며, C언어 기반으로 구현되어 빠르고 스레드 안전합니다. 이 모듈에서 제공하는 함수는, 실제로는 random.Random 클래스의 인스턴스에 바인딩된 메소드입니다.

정수를 위한 함수

random.randrange(stop) | random.randrange(start, stop[, step])

인자로 전달된 범위(start, stop, step)에서 무작위로 선택된 요소를 반환합니다. random.choice(range(start, stop, step))와 결과는 동일하지만, 내부적으로 range 객체를 만들지는 않습니다. 이 함수의 위치 인자들은 range()의 인자와 동일합니다.

random.randint(a, b)

a와 b 사이의 정수 N을 반환합니다. 여기서 N은 a <= N <= b입니다. randrange(a, b+1)과 같으며, 내부적으로도 그렇게 동작합니다.

Sequence 객체를 위한 함수

random.choice(seq)

인자로 전달된 sequence 객체에서 요소 하나를 반환합니다. seq가 비어있을 경우 IndexError를 발생시킵니다.

random.shuffle(x[, random])

sequence인 x를 임의로 섞습니다. 선택적 인자인 `random`은 \[0.0, 1.0)에서 임의의 float을 반환하는 함수를 전달할 수 있는데, 기본적으로 이 인자는 `random.random()` 함수입니다.

실수를 위한 함수

random.random()

[0.0, 1.0) 범위의 실수 하나를 반환합니다.

random.uniform(a, b)

a와 b 사이의 실수 N을 반환합니다. 여기서 N은 a <= b라면 a <= N <= b이고, b < a라면 b <= N <= a입니다.

이 외에 triangular, betavariate, expovariate 등 많은 함수들이 존재하며, 이는 Python 공식 문서 - random에서 확인할 수 있습니다.

'Python 계열 > Python Standard Library' 카테고리의 다른 글

[Python Standard Library] time  (0) 2018.09.07
[Python Standard Library] re  (0) 2018.09.07

Python의 빌트인 함수인 zip()둘 이상의 iterable 객체를 한 번에 순회하기 위해 사용합니다.

zip(*iterables)

인자로 전달된 각 iterable을 집계한 tuple iterator를 반환합니다. i번째 tuple에는 iterable 각각의 i번째 요소가 들어 있습니다.

zip()은 인자로 전달된 가장 짧은 iterable 객체가 모두 소모되면 멈춥니다.

가장 긴 iterable 객체를 기준으로 zip을 수행하려면, Python 표준 라이브러리인 itertools를 사용해야 합니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

Context Manager  (0) 2018.11.01
Argument Unpacking  (0) 2018.10.30
[Python] Coroutines  (0) 2018.07.27
[Python] memoize  (0) 2018.07.26
[Python] Assert  (0) 2018.07.25

프로그래밍 분야에서의 코루틴은 동시성 작업을 위한 기술입니다. Python에서도 코루틴을 구현할 수 있는데, 여기서의 코루틴은 generator와 꽤 유사합니다. Generator는 데이터의 생산자인데 반해, Coroutines은 데이터의 소비자입니다.

Python의 generator는 iterator를 생성하는 특별한 함수 객체로, yield 구문을 통해 필요할 때만 값을 반환합니다. Python 2.5에서 generator에 특별한 기능이 생겼는데, 바로 generator 속으로 값을 전달하는 기능입니다.(PEP 342 -- Coroutines via Enhanced Generators) 이는 두 generator가 번갈아 가면서 제어권을 넘기는 형태를 구성할 수 있게 됩니다.

Python 2.5에서 yield는 표현식이 되었습니다. 이전까지는 generator에서 값을 내놓는 지점을 설정하는 용도로 쓰였으나, 표현식이 되었다는 것은 '값으로 평가된다'는 말이 됩니다. 이를 통해 외부에서 generator로 값을 주입할 수 있고, yield는 재실행되는 시점에 입력값으로 평가됩니다. 이는 generator가 외부로부터 입력을 받는 함수(서브루틴)와 같이 동작할 수 있다는 것을 의미합니다.

generator 함수를 통해 코루틴을 생성했습니다. 생성 직후 코루틴의 실행 위치는 while True 이전에 멈춰 있습니다. next()를 한 번 호출하고 나면, s = (yield) 구문을 만나 멈추게 됩니다. 해당 표현식은 단순한 바인딩 구문이며, 따라서 우변이 평가되기 이전까지 코루틴이 멈춰 있습니다. Generator로 생성된 객체는 매직 메소드인 __next__()send() 메소드를 가집니다. 전자(__next__())는 next() 함수에 대응하여 다음번 yield 구문까지 실행하기 위한 메소드이며, 후자(send())는 코루틴 내부의 yield로 값을 밀어넣는 역할을 합니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

Argument Unpacking  (0) 2018.10.30
[Python] zip  (0) 2018.07.28
[Python] memoize  (0) 2018.07.26
[Python] Assert  (0) 2018.07.25
[Python] Generator  (0) 2018.07.23

프로그래밍 분야에서 동적 계획법의 핵심이 되는 기술로 메모이제이션(memoization)이 있습니다. 이전에 계산한 값을 메모리에 저장함으로써, 동일한 계산의 반복 수행을 제거하여 프로그램 실행 속도를 빠르게 하는 기술입니다. 단적으로 말하면, 동일한 input에 대해 동일한 output이 나오는 함수지만 실행 비용이 비싼 경우 메모이제이션을 적용할 수 있습니다.

메모이제이션 구현하기

@memoize라는 간단한 메모이제이션 데코레이터를 구현해 보도록 합시다.

인자들을 stringify하여 cache 딕셔너리에 들어 있는지 검사하고, 들어 있지 않다면 함수의 실행 결과를 저장하여 나중에 똑같은 인자를 통해 해당 함수를 다시 호출했을 때 cache 딕셔너리에 저장된 값을 즉시 반환합니다. 따라서 memoize 데코레이터가 붙어 있는 expensive_fn 함수를 처음 실행했을 때는 3초가 걸렸지만, 똑같은 인자로 두 번째 실행했을 때는 매우 빠른 속도로 결과 값을 얻어낼 수 있습니다.

functools.lru_cache

Python 3.2 이상에서는 빌트인 모듈인 functoolslru_cache 데코레이터를 사용해서 함수의 반환값들을 메모이제이션할 수 있습니다.

'Python 계열 > Python 레거시 글' 카테고리의 다른 글

[Python] zip  (0) 2018.07.28
[Python] Coroutines  (0) 2018.07.27
[Python] Assert  (0) 2018.07.25
[Python] Generator  (0) 2018.07.23
[Python] Iterable, Sequence, Iterator  (0) 2018.07.22

+ Recent posts