TL; DR:
ใน Python 3.3 คุณไม่ต้องทำอะไรเลยเพียงแค่ไม่ใส่__init__.pyในไดเรกทอรีแพ็คเกจของ namespace ของคุณและมันจะใช้งานได้ บน pre-3.3 เลือกpkgutil.extend_path()โซลูชันเหนือโซลูชันpkg_resources.declare_namespace()เนื่องจากเป็นการพิสูจน์ในอนาคตและเข้ากันได้กับแพ็คเกจเนมสเปซโดยนัยแล้ว
งูหลาม 3.3 เปิดตัวแพคเกจ namespace นัยดูPEP 420
ซึ่งหมายความว่าขณะนี้มีวัตถุสามประเภทที่สามารถสร้างโดยimport foo:
- โมดูลที่แสดงโดย
foo.pyไฟล์
- แพคเกจปกติแสดงโดยไดเรกทอรี
fooที่มี__init__.pyไฟล์
- แพ็กเกจเนมสเปซที่แสดงโดยหนึ่งหรือหลายไดเร็กทอรี
fooโดยไม่มี__init__.pyไฟล์ใด ๆ
แพ็คเกจเป็นโมดูลด้วย แต่ที่นี่ฉันหมายถึง "โมดูลที่ไม่ใช่แพ็คเกจ" เมื่อฉันพูดว่า "โมดูล"
ก่อนอื่นก็สแกนsys.pathหาโมดูลหรือแพ็คเกจปกติ หากสำเร็จจะหยุดการค้นหาและสร้างและเริ่มต้นโมดูลหรือแพ็กเกจ หากไม่พบโมดูลหรือแพ็กเกจปกติ แต่พบอย่างน้อยหนึ่งไดเร็กทอรีมันจะสร้างและเริ่มต้นแพ็กเกจเนมสเปซ
โมดูลและแพ็คเกจปกติได้__file__ตั้งค่าเป็น.pyไฟล์ที่สร้างขึ้น แพ็คเกจปกติและเนมสเปซได้__path__ตั้งค่าเป็นไดเรกทอรีหรือไดเรกทอรีที่สร้างขึ้น
เมื่อคุณทำimport foo.bar, การค้นหาดังกล่าวข้างต้นที่เกิดขึ้นเป็นครั้งแรกสำหรับfooแล้วถ้าแพคเกจที่ถูกพบในการค้นหาbarจะทำกับเป็นเส้นทางการค้นหาแทนfoo.__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__.pyมีextend_pathสาย (และpath1, path2และpath3อยู่ในของคุณsys.path) import package.foo, import package.barและimport package.bazจะทำงานทั้งหมด
pkg_resources.declare_namespace(__name__) ยังไม่ได้รับการอัพเดตเพื่อรวมแพ็คเกจเนมสเปซโดยนัย