python3 -m pip install ~~
: 패키지가, 시스템에 설치된 파이썬 버전에 맞게 설치되도록 보장할 수 있다.요약
python -m venv
source bin/activate
deactivate
python -m pip freeze
python3 -m pip install -r requirements.txt
본문
python3 -m pip show numpy
python -m venv
로 접근 가능python3
명령어$which python3
$python3 --version
$python3 -m venv myproject
$cd myproject
$ls
(myproject)$ which python3
(myproject)$ ls -l /tmp/myproject/bin/python3
python3 -m pip freeze > requirements.txt
명령을 사용해, requirements.txt
에 환경 정보를 저장 가능하다.$ python3 -m pip install -r /tmp/myproject/requirements.txt
하지만 이 txt에는 파이썬 버전은 들어가지 않으므로, 파이썬 버전을 별도로 관리해야 한다.
__init__.py
를 추가하면 간단한 패키지를 만들 수 있다.__all__
special attribute에 지정해, 공개 API를 제공할 수 있다.__init__.py
파일에 외부에 공개할 이름만 import 하거나, _
를 붙임으로써, __all__
로 API를 명시할 필요가 없을 것이다.__init__.py
가 있는 디렉토리에선, 이 디렉터리에 있는 다른 모듈은 __init__.py
가 있는 디렉터리를 기준으로 relative 경로를 통해 import해서 사용할 수 있다.main.py
mypackage/__init__.py
mypackage/models.py
mypackage/utils.py
# main.py
from mypackage import utils
__all__
special attribute를 통해, API 소비자에게 노출할 표면적 이름을 제한할 수 있다.foo.__all__
에 있는 attribute만 import 할 수 있고,foo.__all__
가 없으면, 공개 attribute(_
가 없는)만 import 된다.mypackage/__init__.py
__all__ = []
from .utils import *
__all__ += utils.__all__
# mypackage/utils.py
__all__ = ['simulate_collision']
def _dot_product(a, b):
...
def simulate_collision(a, b):
...
sys
나 os
모듈을 사용해 알아낸 host introspection 정보가 포함된다# dev_main.py
TESTING = True
import db_connection
db = db_connection.Database()
# prod_main.py
TESTING = False
import db_connection
db = db_connection.Database()
# db_connection.py
import __main__
class TestingDataBase:
...
class RealDataBase:
...
if __main__.TESTING:
Database = TestingDataBase
else:
Database = RealDataBase
if 문을 모듈 수준(함수나 메서드 내부의 깊은 수준이 아니라)에서 사용하면, 모듈 안에서 이름이 정의되는 방식을 결정할 수 있따.
그리고 배포 환경이 복잡해지면,
configparser
내장 모듈 같은 도구를 사용하면, production 설정을 코드로부터 분리해 유지 보수할 수 있다.sys
를 활용하여, 윈도우와 우분투 등의 환경에 맞게 실행하도록 할 수 있다.
import sys
class Win32DataBase:
...
class PosixDataBase:
...
if sys.platform.startswith('win32'):
Database = Win32DataBase
else:
Database = PosixDataBase
os.environ
에서 얻은 환경 변수를 모듈 정의에 참조할 수도 있다.# my_module.py
class Error(Exception):
"""이 모듈에서 발생할 모든 예외의 상위 클래스."""
class InvalidDensityError(Error):
"""밀도 값이 잘못된 경우"""
class InvalidVolumeError(Error):
"""부피 값이 잘못된 경우"""
def determine_weight(volume, density):
if density < 0:
raise InvalidDensityError('밀도는 0보다 커야 합니다')
if volume < 0:
raise InvalidVolumeError('부피는 0보다 커야 합니다')
내용
에 예외의 전체 stack trace를 출력하기 때문에 쉽게 디버깅을 할 수 있다.try/except
문을 사용하면, 우리 모듈에서 발생한 예외가, 모듈을 호출하는 코드로부터 아주 멀리 전달돼 프로그램이 꺠지는 상황을 방지할 수 있다.try:
weight = my_module.determine_weight(1, -1)
except my_module.Error:
logging.exception('예상치 못한 오류')
>>>
ERROR:root:예상치 못한 오류
~~~~~내용~~~~
try:
weight = my_module.determine_weight(1, -1)
except my_module.InvalidDensityError:
weight = 0
except my_module.Error:
logging.exception('호출 코드에 버그가 있음')
except Exception:
logging.exception('API 코드에 버그가 있음.')
>>>
ERROR:root:예상치 못한 오류
~~~~~내용~~~~
# my_module.py
class NegativeDensityError(InvalidDensityError):
"""밀도가 음수인 경우."""
def determine_weight(volume, density):
if density < 0:
raise NegativeDensityError('밀도는 0보다 커야 합니다')
# my_module.py
class Error(Exception):
"""이 모듈에서 발생할 모든 예외의 상위 클래스."""
class DensityError(Error):
"""밀도 값이 잘못된 경우의 상위 클래스"""
class VolumeError(Error):
"""부피 값이 잘못된 경우의 상위 클래스"""
# dialog.py
import app
class Dialog:
def __init__(self, save_dir):
self.save_dir = save_dir
save_dialog = Dialog(app.prefs.get('save_dir'))
def show():
...
# app.py
import dialog
class Prefs:
def get(self, name):
...
prefs = Prefs()
dialog.show()
app.py
를 실행하면, 순환 참조 에러가 발생한다.sys.path
에서 모듈 위치를 검색한다.sys.modules
에 넣는다. (import 문을 이용해 모듈 load 가능)임포트, 설정, 실행
dialog
/ app
모두 임포트 시, 동작을 수행하지 않게 정의하자.configure()
을 구현하자.configure
단계를 분리할 수 없을 때도 있다.# dialog.py
import app
class Dialog:
def __init__(self, save_dir):
self.save_dir = save_dir
def configure():
save_dialog = Dialog(app.prefs.get('save_dir'))
def show():
...
# app.py
import dialog
class Prefs:
def get(self, name):
...
def configure():
prefs = Prefs()
# main.py
import app
import dialog
app.configure()
dialog.configure()
dialog.show()
동적 import
# dialog.py
class Dialog:
def __init__(self, save_dir):
self.save_dir = save_dir
save_dialog = Dialog()
def show():
import app # 동적 import
save_dialog.save_dir = app.prefs.get('save_dir')
...
# app.py
import dialog
class Prefs:
def get(self, name):
...
prefs = Prefs()
dialog.show()
warnings
모듈을 사용하면, 여러분의 API를 호출하는 사용자들에게, 앞으로 사용 금지될 사용법에 대해 알려줄 수 있다.-w error
명령줄 인자를 파이썬 interpretor에 넘기면, 경고를 오류로 높일 수 있다.logging
모듈로 복제해, 실행 시점에 기존 오류 보고 시스템이 경고를 잡아내게 할 수 있다.