TL; DR:
Trên Python 3.3 bạn không phải làm gì cả, chỉ cần không đặt bất kỳ thứ gì __init__.pyvào thư mục gói không gian tên của bạn và nó sẽ chỉ hoạt động. Vào trước 3.3, hãy chọn pkgutil.extend_path()giải pháp thay vì giải pháp pkg_resources.declare_namespace()tương lai và đã tương thích với các gói không gian tên ẩn.
Python 3.3 giới thiệu các gói không gian tên ẩn, xem PEP 420 .
Điều này có nghĩa là hiện có ba loại đối tượng có thể được tạo bởi import foo:
- Một mô-đun được đại diện bởi một
foo.pytập tin
- Một gói thông thường, được đại diện bởi một thư mục
foochứa một __init__.pytệp
- Một gói không gian tên, được đại diện bởi một hoặc nhiều thư mục
foomà không có bất kỳ __init__.pytệp nào
Các gói cũng là các mô-đun, nhưng ở đây tôi có nghĩa là "mô-đun không gói" khi tôi nói "mô-đun".
Đầu tiên, nó quét sys.pathmột mô-đun hoặc gói thông thường. Nếu thành công, nó dừng tìm kiếm và tạo và kích hoạt mô-đun hoặc gói. Nếu nó không tìm thấy mô-đun hoặc gói thông thường, nhưng nó tìm thấy ít nhất một thư mục, nó sẽ tạo và khởi tạo gói không gian tên.
Các mô-đun và gói thông thường đã __file__được đặt thành .pytệp mà chúng được tạo từ đó. Các gói thông thường và không gian tên đã __path__được đặt thành thư mục hoặc thư mục mà chúng được tạo từ đó.
Khi bạn thực hiện import foo.bar, tìm kiếm ở trên xảy ra trước tiên foo, sau đó nếu một gói được tìm thấy, việc tìm kiếm barđược thực hiện với foo.__path__tư cách là đường dẫn tìm kiếm thay vì sys.path. Nếu foo.barđược tìm thấy, foovà foo.barđược tạo và khởi tạo.
Vậy làm thế nào để các gói thông thường và các gói không gian tên trộn lẫn? Thông thường họ không, nhưng pkgutilphương thức gói không gian tên rõ ràng cũ đã được mở rộng để bao gồm các gói không gian tên ẩn.
Nếu bạn có một gói thông thường hiện có __init__.pynhư thế này:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
... hành vi kế thừa là thêm bất kỳ gói thông thường nào khác trên đường dẫn tìm kiếm vào nó __path__. Nhưng trong Python 3.3, nó cũng thêm các gói không gian tên.
Vì vậy, bạn có thể có cấu trúc thư mục sau:
├── path1
│ └── package
│ ├── __init__.py
│ └── foo.py
├── path2
│ └── package
│ └── bar.py
└── path3
└── package
├── __init__.py
└── baz.py
... và miễn là cả hai __init__.pycó các extend_pathdòng (và path1, path2và path3nằm trong của bạn sys.path) import package.foo, import package.barvà import package.baztất cả sẽ hoạt động.
pkg_resources.declare_namespace(__name__) đã không được cập nhật để bao gồm các gói không gian tên ẩn.