파이썬에서 네임 스페이스 패키지를 어떻게 만듭니 까?


141

Python에서 네임 스페이스 패키지를 사용하면 여러 프로젝트에 Python 코드를 배포 할 수 있습니다. 이 기능은 관련 라이브러리를 별도의 다운로드로 릴리스하려는 경우에 유용합니다. 예를 들어, 디렉토리와 Package-1Package-2에서 PYTHONPATH,

Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py

최종 사용자는 import namespace.module1import namespace.module2.

하나 이상의 Python 제품이 해당 네임 스페이스에서 모듈을 정의 할 수 있도록 네임 스페이스 패키지를 정의하는 가장 좋은 방법은 무엇입니까?


5
module1과 module2가 실제로 모듈이 아닌 하위 패키지 인 것처럼 보입니다. 내가 이해하는 것처럼 모듈은 기본적으로 단일 파일입니다. 아마도 subpkg1과 subpkg2는 이름으로 더 의미가 있을까요?
Alan

답변:


79

TL; DR :

Python 3.3에서는 아무것도 할 필요가 없으며 __init__.py네임 스페이스 패키지 디렉토리에 아무 것도 넣지 않아도 됩니다. 3.3 이전 버전에서는 미래에 대비하고 이미 암시 적 네임 스페이스 패키지와 호환되므로 pkgutil.extend_path()솔루션을 선택하십시오 pkg_resources.declare_namespace().


Python 3.3에는 암시 적 네임 스페이스 패키지가 도입되었습니다 ( PEP 420 참조) .

이것은 이제 다음으로 만들 수있는 세 가지 유형의 객체가 있음을 의미합니다 import foo.

  • foo.py파일로 표현되는 모듈
  • 파일을 foo포함하는 디렉토리로 표시되는 일반 패키지__init__.py
  • 파일이 foo없는 하나 이상의 디렉토리로 표시되는 네임 스페이스 패키지__init__.py

패키지도 모듈이지만 여기서는 "모듈"이라고 말할 때 "비 패키지 모듈"을 의미합니다.

먼저 sys.path모듈 또는 일반 패키지를 검색 합니다. 성공하면 검색을 중지하고 모듈 또는 패키지를 생성하고 초기화합니다. 모듈이나 일반 패키지를 찾지 못했지만 하나 이상의 디렉토리를 찾은 경우 네임 스페이스 패키지를 만들고 초기화합니다.

모듈 및 일반 패키지 가 작성된 파일로 __file__설정되었습니다 .py. 일반 및 네임 스페이스 패키지 __path__가 작성된 디렉토리로 설정되었습니다.

그렇게 import foo.bar하면 위의 검색이 먼저 수행 된 foo다음 패키지가 발견되면 검색 barfoo.__path__대신 검색 경로로 수행됩니다 sys.path. 경우 foo.bar발견, foo그리고 foo.bar생성 및 초기화된다.

그렇다면 일반 패키지와 네임 스페이스 패키지는 어떻게 혼합됩니까? 일반적으로 그렇지는 않지만 기존 pkgutil명시 적 네임 스페이스 패키지 메서드는 암시 적 네임 스페이스 패키지를 포함하도록 확장되었습니다.

다음과 같은 기존 일반 패키지가있는 __init__.py경우 :

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

... 레거시 동작은 검색된 경로에 다른 일반 패키지 를 추가하는 것 __path__입니다. 그러나 Python 3.3에서는 네임 스페이스 패키지도 추가합니다.

따라서 다음 디렉토리 구조를 가질 수 있습니다.

├── path1
   └── package
       ├── __init__.py
       └── foo.py
├── path2
   └── package
       └── bar.py
└── path3
    └── package
        ├── __init__.py
        └── baz.py

... 그리고 한 두로 __init__.pyextend_path줄을 (그리고 path1, path2그리고 path3당신에있는 sys.path) import package.foo, import package.bar그리고 import package.baz모든 작업은 것이다.

pkg_resources.declare_namespace(__name__) 암시 적 네임 스페이스 패키지를 포함하도록 업데이트되지 않았습니다.


2
setuptools는 어떻습니까? namespace_packages옵션 을 사용해야 합니까? 그리고 __import__('pkg_resources').declare_namespace(__name__)일?
kawing-chiu

3
나는 추가해야 namespace_packages=['package']setup.py?
Laurent LAPORTE

1
@clacke :을 사용 namespace_packages=['package']하면 setup.py가 namespace_packages.txtEGG-INFO에 추가합니다 . 아직도 영향을 모릅니다…
Laurent LAPORTE

1
@ kawing-chiu pkg_resources.declare_namespaceover 의 장점 pkgutil.extend_path은 계속 모니터링한다는 것입니다 sys.path. 이렇게 sys.path하면 네임 스페이스의 패키지가 먼저로드 된 후 새 항목이 추가되면 해당 새 경로 항목의 네임 스페이스에있는 패키지를 계속로드 할 수 있습니다. ( __import__('pkg_resources')이상 사용의 이점은 으로 노출 import pkg_resources되지 않는다는 pkg_resourcesmy_namespace_pkg.pkg_resources입니다.)
Arthur Tacca

1
@clacke 그것은 그렇게 작동하지 않습니다 (그러나 그것은 마치 효과가 있습니다.) 해당 함수로 생성 된 모든 패키지 네임 스페이스의 전체 목록을 유지 관리합니다 sys.path. 때 sys.path그가에 영향을 미치는 경우를 확인 변경 __path__이름 공간의, 그리고 그 다음 않는 경우 그 업데이트 __path__속성을.
Arthur Tacca

81

pkgutil 이라는 표준 모듈 이 있습니다.이 모듈을 사용하면 지정된 네임 스페이스에 모듈을 '추가'할 수 있습니다.

제공 한 디렉토리 구조로 :

Package-1/namespace/__init__.py
Package-1/namespace/module1/__init__.py
Package-2/namespace/__init__.py
Package-2/namespace/module2/__init__.py

당신은 모두 그 두 줄 넣어야 Package-1/namespace/__init__.py하고 Package-2/namespace/__init__.py(*)를 :

from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)

(*-이들 사이에 의존성을 언급하지 않는 한-어느 것이 먼저 인식되는지 알지 못합니다- 자세한 내용 은 PEP 420 참조 )

현상태대로 설명서를 말한다 :

패키지 이름 __path__sys.path따서 패키지의 모든 디렉토리 하위 디렉토리에 추가됩니다 .

이제부터는이 두 패키지를 독립적으로 배포 할 수 있습니다.


17
import __ ( 'pkg_resources'). declare_namespace (__ name ) 을 사용하는 장단점은 무엇입니까 ?
joeforker 2009

14
첫째, __import__일반 import 문으로 쉽게 바꿀 수 있으므로이 경우 나쁜 스타일로 간주됩니다. 요컨대 pkg_resources는 비표준 라이브러리입니다. setuptools와 함께 제공되므로 문제가 아닙니다. 빠른 인터넷 검색에 따르면 pkgutil이 2.5에서 도입되었으며 pkg_resources가 이전 버전보다 우선합니다. 그럼에도 불구하고 pkgutil은 공식적으로 인정되는 솔루션입니다. pkg_resources의 포함은, 사실, PEP 365에서 거부
마이크 Hordecki

3
PEP 382의 인용문 : 네임 스페이스 패키지에 대한 현재의 명령 방식은 네임 스페이스 패키지를 제공하기위한 약간 호환되지 않는 여러 메커니즘으로 이어졌습니다. 예를 들어, pkgutil은 * .pkg 파일을 지원합니다. setuptools는 그렇지 않습니다. 마찬가지로 setuptools는 zip 파일 검사를 지원하고 pkgutil은 그렇지 않은 반면 _namespace_packages 변수에 부분 추가를 지원합니다.
Drake Guan

7
이 두 라인은 두 파일에 넣어 야해 : Package-1/namespace/__init__.py 그리고 Package-2/namespace/__init__.py 우리가 먼저 나열되어있는 패키지 디렉토리 모르는 제공?
Bula

3
@ChristofferKarlsson 네, 요점입니다. 어느 것이 첫 번째인지 아는 경우 괜찮습니다. 그러나 실제 질문은 어떤 상황에서도 첫 번째가 될 것이라고 보장 할 수 있습니까?
Bula

5

이 섹션은 설명이 필요합니다.

간단히 말해서 네임 스페이스 코드를에 넣고 네임 스페이스 를 선언하도록 __init__.py업데이트 setup.py하면 자유롭게 갈 수 있습니다.


9
관련 링크가 작동하지 않을 경우 항상 링크의 관련 부분을 인용해야합니다.
Tinned_Tuna

2

이것은 오래된 질문이지만 최근 누군가 내 블로그에서 네임 스페이스 패키지에 대한 내 게시물이 여전히 관련이 있다고 언급 했으므로 여기에 링크하는 방법에 대한 실제적인 예를 제공하기 위해 여기에 링크 할 것이라고 생각했습니다.

https://web.archive.org/web/20150425043954/http://cdent.tumblr.com/post/216241761/python-namespace-packages-for-tiddlyweb

그것은 무슨 일이 일어나고 있는지에 대한 주요 내용을 담고 있습니다.

http://www.siafoo.net/article/77#multiple-distributions-one-virtual-package

__import__("pkg_resources").declare_namespace(__name__)트릭은 TiddlyWeb 에서 플러그인 관리를 주도 하고 있으며 지금까지는 잘 작동하고있는 것 같습니다.


-9

파이썬 네임 스페이스 개념이 앞뒤로 있지만 파이썬에서는 패키지를 모듈에 넣을 수 없습니다. 패키지는 다른 방식으로 모듈을 포함하지 않습니다.

파이썬 패키지는 단순히 __init__.py파일을 포함하는 폴더 입니다. 모듈은 확장명 PYTHONPATH이있는 패키지 (또는 직접)의 다른 파일입니다 .py. 따라서 귀하의 예에는 두 개의 패키지가 있지만 모듈이 정의되어 있지 않습니다. 패키지가 파일 시스템 폴더이고 모듈이 파일이라고 생각하면 패키지가 다른 방식이 아닌 모듈을 포함하는 이유를 알 수 있습니다.

따라서 예제에서 Package-1과 Package-2가 파일 시스템의 폴더 인 Python 경로에 있다고 가정하면 다음을 가질 수 있습니다.

Package-1/
  namespace/
  __init__.py
  module1.py
Package-2/
  namespace/
  __init__.py
  module2.py

이제 하나 개의 패키지가 namespace두 개의 모듈로 module1module2. 그리고 합당한 이유가 없다면 모듈을 폴더에 넣고 아래처럼 파이썬 경로에만 모듈을 가져야합니다.

Package-1/
  namespace/
  __init__.py
  module1.py
  module2.py

zope.x관련 패키지 묶음이 별도의 다운로드로 릴리스되는 것과 같은 것들에 대해 이야기하고 있습니다.
joeforker 2018

좋아, 그러나 달성하려는 효과는 무엇입니까? PYTHONPATH에 관련 패키지가 모두 들어있는 폴더가 있으면 파이썬 인터프리터가 별도의 노력없이 찾을 수 있습니다.
Tendayi Mawushe 2009

5
PYTHONPATH에 Package-1과 Package-2를 모두 추가하면 Python은 Package-1 / namespace / 만 볼 수 있습니다.
Søren Løvborg
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.