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__.py
và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.py
tập tin
- Một gói thông thường, được đại diện bởi một thư mục
foo
chứa một __init__.py
tệ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
foo
mà không có bất kỳ __init__.py
tệ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.path
mộ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 .py
tệ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, foo
và 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 pkgutil
phươ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__.py
như 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__.py
có các extend_path
dòng (và path1
, path2
và path3
nằm trong của bạn sys.path
) import package.foo
, import package.bar
và import package.baz
tấ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.