아래 명령은 설치된 모든 패키지를 upgrade합니다.

$ pip install --upgrade $(pip list | egrep -v 'Pack|----' | awk '{print $1}')

아래 명령은 pip, wheel, setuptools를 제외한 패키지를 모두 제거합니다.

$ pip uninstall $(pip list | egrep -v 'Pack|----|pip|wheel|setuptools')

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

requirements.txt로 협업 상황에서의 의존성 관리하기  (0) 2018.11.07
pip  (0) 2018.11.05
__slots__  (0) 2018.11.03
Context Manager  (0) 2018.11.01
Argument Unpacking  (0) 2018.10.30

requirements.txt는 npm의 packages.json과 유사하게, 의존성의 목록을 관리하는 Python의 관례적인 파일입니다. 다수의 개발자가 Python으로 프로젝트를 진행하는 경우, 개발 시 필요한 의존성 패키지들을 동일하게 맞추고 개발하는 것이 좋습니다. Python은 requirements.txt라는 개념을 통해 이를 해결합니다.

pip freeze

pip freeze라는 명령이 있습니다. pip list처럼 시스템에 설치된 파이썬 패키지의 목록을 출력하는데, freeze의 경우 이 목록을 raw하게 표현한다는 특징이 있습니다.

$ pip3 freeze
pbr==4.0.4
six==1.11.0
stevedore==1.28.0
virtualenv==16.0.0
virtualenv-clone==0.3.0
virtualenvwrapper==4.8.2

이전에 pip install을 하면서, 특정 버전의 패키지를 설치할 때 사용했던 표현과 동일합니다. 따라서 최초 개발자 A는 pip freeze 명령어의 결과를 외부 파일로 export해 의존성 목록을 만들 수 있습니다.

$ pip3 freeze > requirements.txt

requirements.txt 파일 내에는 다음과 같이 개발 시 필요한 패키지들이 저장됩니다.

$ cat requirements.txt
pbr==4.0.4
six==1.11.0
stevedore==1.28.0
virtualenv==16.0.0
virtualenv-clone==0.3.0
virtualenvwrapper==4.8.2

파일 이름은 아무렇게나 해도 상관 없으나, 관례 상 위처럼 requirements.txt를 사용하는 것이 좋습니다.

pip install -r [filename]

pip install 명령에는 전달할 수 있는 많은 인자들이 존재하지만, --upgrade와 이 -r 인자를 가장 많이 사용할 것입니다. pip install 뒤에 -r을 붙이고, 의존성 목록이 적혀 있는 파일의 경로를 입력하면 적혀 있는 그대로 패키지들이 설치됩니다.

$ pip3 install -r requirements.txt
Collecting pbr==4.0.4 (from -r requirements.txt (line 1))
https://files.pythonhosted.org/packages/b3/5d/c196041ffdf3e34ba206db6d61d1f893a75e1f3435699ade9bd65e089a3d/pbr-4.0.4-py2.py3-none-any.whl
Collecting six==1.11.0 (from -r requirements.txt (line 2))
https://files.pythonhosted.org/packages/67/4b/141a581104b1f6397bfa78ac9d43d8ad29a7ca43ea90a2d863fe3056e86a/six-1.11.0-py2.py3-none-any.whl
Collecting stevedore==1.28.0 (from -r requirements.txt (line 3))
https://files.pythonhosted.org/packages/17/6b/3b7d6d08b2ab3e5ef09e01c9f7b3b590ee135f289bb94553419e40922c25/stevedore-1.28.0-py2.py3-none-any.whl

(...)

Installing collected packages: pbr, six, stevedore, virtualenv, virtualenv-clone, virtualenvwrapper
Successfully installed pbr-4.0.4 six-1.11.0 stevedore-1.28.0 virtualenv-16.0.0 virtualenv-clone-0.3.0 virtualenvwrapper-4.8.2


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

귀찮음을 줄여주는 간단한 pip 관련 명령 모음(Draft)  (0) 2018.11.12
pip  (0) 2018.11.05
__slots__  (0) 2018.11.03
Context Manager  (0) 2018.11.01
Argument Unpacking  (0) 2018.10.30

좀 잘 나가는 프로그래밍 언어라면, 패키지(라이브러리) 생태계가 굉장히 활발하게 형성되어 있습니다. 그 대표격으로 JavaScript 진영의 npm이 있고, 이와 유사한 패키지 생태계로 Python에는 PyPI(Python Package Index)가 있습니다. 그리고 이들은 pip를 이용해 관리할 수 있습니다. pip를 이용해 외부 라이브러리를 설치하면, 파이썬이 설치된 경로의 site-packages 디렉토리에 적용되어 즉시 사용할 수 있게 됩니다. 별도의 의존성 있는 모듈이나 패키지도 함께 설치해 주기 때문에 매우 편리합니다.

Linux 기반 운영체제에서 pythonpython3 명령이 별도로 존재하는 것처럼, pippip3 명령도 별도로 존재합니다. 각각 python2에 대한 라이브러리, python3에 대한 라이브러리를 관리합니다. pip --version 또는 pip -V를 통해 설치되어 있는 pip의 버전을 확인할 수 있습니다.

$ pip -V
pip 10.0.1 from /usr/local/lib/python2.7/site-packages/pip (python 2.7)
$ pip3 --version
pip 10.0.1 from /usr/local/lib/python3.6/site-packages/pip (python 3.6)

pip install [packages ...]

PyPI에서 packages에 해당하는 패키지들을 가져와 설치합니다. 아래의 명령은 virtualenvwrapper를 설치합니다.

$ pip3 install virtualenvwrapper
Collecting virtualenvwrapper
  Downloading https://files.pythonhosted.org/packages/2b/8c/3192e10913ad945c0f0fcb17e9b2679434a28ad58ee31ce0104cba3b1154/virtualenvwrapper-4.8.2-py2.py3-none-any.whl

(...)

https://files.pythonhosted.org/packages/b3/5d/c196041ffdf3e34ba206db6d61d1f893a75e1f3435699ade9bd65e089a3d/pbr-4.0.4-py2.py3-none-any.whl (98kB)
    100% |████████████████████████████████| 102kB 2.1MB/s
Installing collected packages: six, pbr, stevedore, virtualenv-clone, virtualenvwrapper
Successfully installed pbr-4.0.4 six-1.11.0 stevedore-1.28.0 virtualenv-clone-0.3.0 virtualenvwrapper-4.8.2

여러 개의 패키지들을 한 번에 설치할 수도 있으며, 이미 존재하는 패키지인 경우 'Requirement already satisfied'라는 결과가 보여집니다. 아래의 명령은 시스템에 이미 설치되어 있는 virtualenv와 virtualenvwrapper를 설치합니다.

$ pip3 install virtualenv virtualenvwrapper
Requirement already satisfied: virtualenv in /usr/local/lib/python3.6/site-packages (16.0.0)
Requirement already satisfied: virtualenvwrapper in /usr/local/lib/python3.6/site-packages (4.8.2)
Requirement already satisfied: stevedore in /usr/local/lib/python3.6/site-packages (from virtualenvwrapper) (1.28.0)
Requirement already satisfied: virtualenv-clone in /usr/local/lib/python3.6/site-packages (from virtualenvwrapper) (0.3.0)
Requirement already satisfied: six>=1.10.0 in /usr/local/lib/python3.6/site-packages (from stevedore->virtualenvwrapper) (1.11.0)
Requirement already satisfied: pbr!=2.1.0,>=2.0.0 in /usr/local/lib/python3.6/site-packages (from stevedore->virtualenvwrapper) (4.0.4)

다음과 같이 특정 버전의 패키지를 설치할 수도 있습니다. 아래의 명령은 virtualenvwrapper의 4.7 버전을 설치합니다.

$ pip3 install virtualenvwrapper==4.7
Collecting virtualenvwrapper==4.7
  Downloading 

(...)

Installing collected packages: virtualenvwrapper
Successfully installed virtualenvwrapper-4.7.0

pip list

pip list는 pip에 의해, 또는 수동으로 설치되어 있는 패키지들의 목록을 출력합니다.

$ pip3 list
Package           Version
----------------- -------
pbr               4.0.4
pip               10.0.1
setuptools        39.0.1
virtualenv        16.0.0

(...)

wheel             0.31.0

pip install --upgrade [packages ...]

packages에 해당하는 패키지들을 시스템에서 찾아, 설치되어 있으면 최신 버전으로 업그레이드하고, 그렇지 않으면 pip install을 진행합니다. 패키지가 이미 최신 버전으로 설치되어 있다면, 'Requirement already up-to-date'라는 결과가 보여집니다. 아래는 최신 버전인 virtualenv최신 버전이 아닌 virtualenvwrapper를 업그레이드하는 명령입니다.

$ pip3 install --upgrade virtualenv virtualenvwrapper
Requirement already up-to-date: virtualenv in /usr/local/lib/python3.6/site-packages (16.0.0)

(...)

Installing collected packages: virtualenvwrapper
  Found existing installation: virtualenvwrapper 4.7.0
    Uninstalling virtualenvwrapper-4.7.0:
      Successfully uninstalled virtualenvwrapper-4.7.0
Successfully installed virtualenvwrapper-4.8.2

pip uninstall [packages ...]

packages에 해당하는 패키지들을 시스템에서 제거합니다. 시스템에 존재하지 않는 패키지일 경우, 'Skipping *** as it is not installed.'라는 결과가 보여집니다. 아래는 설치되어 있는 jinja2와 markupsafe, 설치되어 있지 않은 flask를 제거하는 명령입니다.

$ pip3 uninstall jinja2 markupsafe flask
Uninstalling Jinja2-2.10:
  Would remove:
    /usr/local/lib/python3.6/site-packages/Jinja2-2.10.dist-info/*
    /usr/local/lib/python3.6/site-packages/jinja2/*
Proceed (y/n)? y
  Successfully uninstalled Jinja2-2.10
Uninstalling MarkupSafe-1.0:
  Would remove:
    /usr/local/lib/python3.6/site-packages/MarkupSafe-1.0.dist-info/*
    /usr/local/lib/python3.6/site-packages/markupsafe/*
Proceed (y/n)? y
  Successfully uninstalled MarkupSafe-1.0
Skipping flask as it is not installed.


Python의 모든 클래스는 인스턴스 속성(instance attribute)을 가집니다. 기본적으로, 이러한 객체의 인스턴스 속성을 관리하기 위해 Python에서 내부적으로 딕셔너리를 사용합니다. 객체의 __dict__ 필드에 접근하여 인스턴스 속성들을 딕셔너리 형태로 확인할 수 있고, 이는 런타임에 새로운 속성을 설정하는 데에 매우 유용하게 사용됩니다.

그러나, 알려진(known) 속성들로 구성된 클래스들의 경우 이러한 구조는 딕셔너리가 낭비하는 RAM 때문에 병목이 발생할 수 있습니다. 클래스 레벨에 __slots__라는 변수를 설정해서, 해당 클래스에 의해 만들어진 객체의 인스턴스 속성 관리에 딕셔너리 대신 속성에 대한 고정된(fixed) set을 사용하도록 할 수 있습니다.

__slots__가 정의된 클래스의 인스턴스에는 __dict__ 필드가 없다 정도밖에 차이가 없어 보이지만, IronPython의 도움을 받아 메모리 사용량을 보면, 효율이 확실히 개선된 것을 확인할 수 있습니다. ipython-memory-usage를 사용해, 1024 * 256개의 객체 생성에 대한 메모리 사용량을 확인해 보았습니다.

In [1]: class WithoutSlots:
   ...:     def __init__(self, name, identifier):
   ...:         self.name = name
   ...:         self.identifier = identifier
   ...:

In [2]: class WithSlots:
   ...:     __slots__ = ['name', 'identifier']
   ...:     def __init__(self, name, identifier):
   ...:         self.name = name
   ...:         self.identifier = identifier
   ...:

In [3]: import ipython_memory_usage.ipython_memory_usage as imu

In [4]: size = 1024 * 256

In [5]: imu.start_watching_memory()
In [5] used 0.0000 MiB RAM in 5.31s, peaked 0.00 MiB above current, total RAM usage 15.57 MiB

In [6]: x = [WithoutSlots(1, 1) for _ in range(size)]
In [6] used 22.6680 MiB RAM in 0.80s, peaked 0.00 MiB above current, total RAM usage 38.24 MiB

In [7]: x = [WithSlots(1, 1) for _ in range(size)]
In [7] used 9.3008 MiB RAM in 0.72s, peaked 0.00 MiB above current, total RAM usage 47.54 MiB


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

requirements.txt로 협업 상황에서의 의존성 관리하기  (0) 2018.11.07
pip  (0) 2018.11.05
Context Manager  (0) 2018.11.01
Argument Unpacking  (0) 2018.10.30
[Python] zip  (0) 2018.07.28

Context(문맥)이라는 단어가 참 많은 곳에서 사용되기 때문에 조금 애매하지만, 아무튼 Python의 특정 객체들은 context를 가집니다. 예를 들어, file 객체는 open-close의 2가지 context를 가지는 식입니다.

file 객체의 open과 close처럼, context가 명확한 객체의 경우 Python에서는 원하는 타이밍에 정확하게 리소스를 할당하고 제거할 수 있도록 context manager 프로토콜을 갖도록 하는 것을 권고하고 있습니다. 'context manager 프로토콜을 가지고 있다'의 조건은 생각보다 간단합니다.

  • 매직 메소드 __enter__()를 구현하고 있어야 한다.
  • 매직 메소드 __exit__()을 구현하고 있어야 한다.

이 두 매직 메소드들은 가장 일반적인 context manager인 with-as 문에서 사용됩니다.

with 문에 의해 감싸진 객체는, 블럭이 시작되기 이전에 as 뒤의 객체에 __enter__()의 반환값을 할당하며, 블럭을 탈출하는 시점에 해당 객체의 __exit__()을 호출합니다. file의 경우, __enter__()에서 파일 객체를 열어 반환하고, __exit__()에서 파일 객체를 닫는(close) 역할을 하므로 context manageable하다고 말할 수 있습니다.

Context manageable한 클래스 만들기

__enter__()와 __exit__()이 정의된, context manageable한 클래스를 만들고 with-as 문에 사용해 보겠습니다.

역시, Python은 생각보다 훨씬 깊습니다.

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

pip  (0) 2018.11.05
__slots__  (0) 2018.11.03
Argument Unpacking  (0) 2018.10.30
[Python] zip  (0) 2018.07.28
[Python] Coroutines  (0) 2018.07.27

Python에서 언더스코어처럼, asterisk(*)도 꽤 특별하게 사용할 수 있었습니다. 가장 일반적인 사용 사례는 수 사이의 곱셈과 거듭제곱 연산, Sequence 객체의 반복 확장, 그리고 아래의 가변 인자 표현식이었습니다.

Argument unpacking

Iterable 객체는 unpacking이 가능합니다. 이를 함수 인자에도 적용할 수 있는데, 여기에서 asterisk(*) 기호를 사용합니다.

이를 Argument unpacking이라 부르며, 위치 인자의 argument unpacking에는 List와 Tuple, String과 같은 sequence 객체를 사용할 수 있습니다. 아래는 키워드 인자에 대한 argument unpacking입니다.

여기에는 Dictionary와 같은 mapping 객체를 사용할 수 있습니다.

응용

Argument unpacking은 설정 데이터를 외부에서 다룰 때 유용하게 사용할 수 있는데, 아래와 같습니다. 데이터베이스에 연결하는 스크립트를 작성한다고 가정해 보겠습니다.

위처럼 argument unpacking으로 설정 데이터를 관리하는 경우, 대표적으로 아래 2가지의 강점을 가집니다.

  1. 코드가 간결해집니다. config에서 관리하는 데이터가 많아질수록, 간결함은 더 강해집니다.
  2. 추상화 레벨을 높여 유지 보수에 조금이나마 편의성을 제공합니다. 설정이 추가되거나 제거되는 경우, argument unpacking을 사용하는 코드에서는 원본 해당 객체만 수정함으로써 해결 가능하게 됩니다.


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

__slots__  (0) 2018.11.03
Context Manager  (0) 2018.11.01
[Python] zip  (0) 2018.07.28
[Python] Coroutines  (0) 2018.07.27
[Python] memoize  (0) 2018.07.26

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

assert라는 개념은 가정 설정문을 뜻하는 assertion에서 나오게 되었습니다. 프로그램 개발의 과정에서 '실수는 일어난다'고 가정하고, 참/거짓을 미리 가정하는 문을 배치하여 이를 방지하는 것입니다. 이것을 방어적 프로그래밍(defensive programming)이라고 부르며, 방어적 프로그래밍의 가장 일반적인 구현 방식은 여기서 말한 assert를 사용합니다.

assert

assert(가정 설정문)은 단순하게 프로그램의 특정 지점에서 항상 참이어야 하는 문장입니다. Python을 비롯해 assertion을 지원하는 프로그래밍 언어들은 대부분 assert의 조건을 확인하여 참이면 다음 문장으로 넘어가고, 거짓이면 프로그램을 정지시킵니다. Python에서는 assert의 조건이 거짓인 경우 AssertionError를 발생시킵니다. assert의 예는 다음과 같습니다.

assert [condition] 형태입니다. 조금 현실적으로 바꾼다면, 아래처럼 작성할 수 있습니다.

assert에 메시지를 작성할 수도 있습니다. assert [condition], [message] 형태입니다.

이는 raise AssertionError('Data should only contain positive values')와 같은 결과를 내보냅니다.

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

[Python] Coroutines  (0) 2018.07.27
[Python] memoize  (0) 2018.07.26
[Python] Generator  (0) 2018.07.23
[Python] Iterable, Sequence, Iterator  (0) 2018.07.22
[Python] Decorator  (0) 2018.07.21

+ Recent posts