다음은 예제로 적합하도록 수정 된 일반적인 레시피입니다. 패키지로 작성된 Python 라이브러리를 처리하기 위해 현재 사용하고 있으며, 상호 의존적 인 파일이 포함되어 있으며, 일부는 부분적으로 테스트 할 수 있습니다. 의이 부르 자 lib.foo
하고 액세스해야한다고 말하는 lib.fileA
기능 f1
과 f2
, 및 lib.fileB
클래스를 Class3
.
print
이것이 어떻게 작동하는지 설명하기 위해 몇 가지 전화를 포함 시켰습니다 . 실제로 당신은 그것들을 제거하고 싶을 것 from __future__ import print_function
입니다.
이 특정 예제는에 항목을 실제로 삽입해야 할 때 표시하기에는 너무 단순합니다 sys.path
. (참조 라스 '대답은 우리가 경우에 할 우리가 패키지 디렉토리의 두 개 이상의 수준을 가지고 있고, 우리가 사용하는 경우, 필요 os.path.dirname(os.path.dirname(__file__))
정말하지 않습니다 -하지만 상처 중 여기가.) 그것은없이이 작업을 수행하는 안전 충분한이기도 if _i in sys.path
테스트. 그러나 각 가져온 파일을 삽입하는 경우 동일한 경로에 대한 예, 두 경우 fileA
와는 fileB
패키지-이 클러부터 임포트 유틸리티에 원하는 sys.path
그것의 좋은이 가지고있는 동일한 경로 많은 시간이, 그래서 if _i not in sys.path
상용구에 있습니다.
from __future__ import print_function # only when showing how this works
if __package__:
print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
from .fileA import f1, f2
from .fileB import Class3
else:
print('Not a package; __name__ is {!r}'.format(__name__))
# these next steps should be used only with care and if needed
# (remove the sys.path manipulation for simple cases!)
import os, sys
_i = os.path.dirname(os.path.abspath(__file__))
if _i not in sys.path:
print('inserting {!r} into sys.path'.format(_i))
sys.path.insert(0, _i)
else:
print('{!r} is already in sys.path'.format(_i))
del _i # clean up global name space
from fileA import f1, f2
from fileB import Class3
... all the code as usual ...
if __name__ == '__main__':
import doctest, sys
ret = doctest.testmod()
sys.exit(0 if ret.failed == 0 else 1)
여기 아이디어는 이것입니다 (그리고 이것들은 모두 python2.7과 python 3.x에서 동일하게 작동합니다).
일반 코드에서 import lib
또는 from lib import foo
일반 패키지로 일반 패키지 가져 오기로 실행하면 __package
is lib
and __name__
is lib.foo
입니다. 에서 가져 오는 첫 번째 코드 경로 .fileA
를 사용합니다.
로 실행하면 python lib/foo.py
, __package__
아무도 없을 것입니다 __name__
될 것입니다 __main__
.
우리는 두 번째 코드 경로를 사용합니다. lib
디렉토리가 이미있는 것입니다 sys.path
추가 할 필요가 없습니다 그래서. fileA
등에서 수입
로 lib
디렉토리 내에서 실행될 경우 python foo.py
동작은 사례 2와 동일합니다.
로 lib
디렉토리 내에서 실행되는 경우 python -m foo
동작은 사례 2 및 3과 유사합니다. 그러나 lib
디렉토리 경로 가에 있지 않으므로 sys.path
가져 오기 전에 추가합니다. Python을 실행 한 다음에도 마찬가지 import foo
입니다.
이후 ( .
인 에 sys.path
, 우리는 정말 여기에 경로의 절대 버전을 추가 할 필요가 없습니다. 우리가 원하는 깊은 패키지 중첩 구조는 곳입니다 from ..otherlib.fileC import ...
, 차이가 있습니다. 당신이이 일을하지 않는 경우, 당신은 할 수 있습니다 모든 sys.path
조작을 완전히 생략하십시오 .)
노트
여전히 기발한 것이 있습니다. 이 모든 것을 외부에서 실행하면 :
$ python2 lib.foo
또는:
$ python3 lib.foo
동작은의 내용에 따라 다릅니다 lib/__init__.py
. 그것이 존재하고 비어 있으면 모든 것이 잘됩니다.
Package named 'lib'; __name__ is '__main__'
그러나 lib/__init__.py
자체로 가져 routine
와서 routine.name
직접 (으)로 내보낼 수 있다면 lib.name
다음을 얻을 수 있습니다.
$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'
즉, 패키지를 통해 한 번 모듈을 두 번 가져온 다음 코드를 __main__
실행하도록 다시 가져옵니다 main
. 파이썬 3.6 이상은 이것에 대해 경고합니다 :
$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'
경고는 새로운이지만, 경고-에 대해 동작하지 않습니다. 일부 는 이중 가져 오기 트랩 이라고 하는 것의 일부 입니다. (자세한 내용은 이슈 27487을 참조하십시오 .) Nick Coghlan의 말 :
이 다음 트랩은 3.3을 포함한 모든 현재 버전의 Python에 존재하며 다음 일반 지침에 요약 할 수 있습니다. "패키지 디렉토리 또는 패키지 내의 디렉토리를 Python 경로에 직접 추가하지 마십시오".
여기서 규칙을 위반하는 동안 로드되는 파일이 패키지의 일부로로드 되지 않는 경우 에만 해당 규칙이 적용 되며 수정 사항은 해당 패키지의 다른 파일에 액세스 할 수 있도록 특별히 설계되었습니다. (그리고 내가 언급했듯이, 우리는 아마 단일 레벨 패키지에 대해 이것을해서는 안됩니다.) 우리가 깨끗하게하고 싶다면 다음과 같이 다시 작성할 수 있습니다.
import os, sys
_i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
if _i not in sys.path:
sys.path.insert(0, _i)
else:
_i = None
from sub.fileA import f1, f2
from sub.fileB import Class3
if _i:
sys.path.remove(_i)
del _i
즉, sys.path
가져 오기를 수행 할 수있을 정도로 오래 수정 한 다음 원래 상태로 되돌립니다 ( _i
if의 사본 하나만 추가 한 경우에만 사본 하나 삭제 _i
).