मैं पायथन में एक नाम स्थान पैकेज कैसे बनाऊं?


141

पायथन में, एक नेमस्पेस पैकेज आपको कई परियोजनाओं के बीच पायथन कोड को फैलाने की अनुमति देता है। यह उपयोगी है जब आप संबंधित पुस्तकालयों को अलग-अलग डाउनलोड के रूप में जारी करना चाहते हैं। उदाहरण के लिए, निर्देशिका के साथ Package-1और Package-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.module1और import namespace.module2

एक नेमस्पेस पैकेज को परिभाषित करने का सबसे अच्छा तरीका क्या है कि एक से अधिक पायथन उत्पाद उस नाम स्थान में मॉड्यूल को परिभाषित कर सकते हैं?


5
यह मुझे लग रहा है जैसे मॉड्यूल 1 और मॉड्यूल 2 वास्तव में मॉड्यूल के बजाय सबपैकेज हैं। जैसा कि मैं इसे समझता हूं, एक मॉड्यूल मूल रूप से एक एकल फ़ाइल है। शायद subpkg1 और subpkg2 नाम के रूप में अधिक समझ में आता है?
एलन

जवाबों:


79

टी एल; डॉ:

Python 3.3 पर आपको कुछ भी करने की ज़रूरत नहीं है, बस __init__.pyअपने नेमस्पेस पैकेज निर्देशिकाओं में किसी को न डालें और यह सिर्फ काम करेगा। प्री-3.3 pkgutil.extend_path()पर, pkg_resources.declare_namespace()एक पर समाधान चुनें , क्योंकि यह भविष्य के सबूत है और पहले से ही निहित नाम स्थान पैकेज के साथ संगत है।


पायथन 3.3 अंतर्निहित नाम स्थान पैकेज पेश करता है, पीईपी 420 देखें ।

इसका मतलब है कि अब तीन प्रकार की वस्तुएं बनाई जा सकती हैं import foo:

  • एक foo.pyफ़ाइल द्वारा प्रदर्शित मॉड्यूल
  • एक नियमित पैकेज, एक निर्देशिका fooजिसमें एक __init__.pyफ़ाइल होती है
  • एक नेमस्पेस पैकेज, जो fooकिसी भी __init__.pyफाइल के बिना एक या अधिक निर्देशिकाओं द्वारा दर्शाया गया है

पैकेज भी मॉड्यूल हैं, लेकिन यहां मेरा मतलब है "नॉन-पैकेज मॉड्यूल" जब मैं कहता हूं "मॉड्यूल"।

पहले यह sys.pathएक मॉड्यूल या नियमित पैकेज के लिए स्कैन करता है । यदि यह सफल होता है, तो यह मॉड्यूल या पैकेज को खोजना और बनाना और बंद कर देता है। यदि इसे कोई मॉड्यूल या नियमित पैकेज नहीं मिला, लेकिन इसे कम से कम एक निर्देशिका मिली, तो यह एक नाम स्थान पैकेज बनाता है और आरंभ करता है।

मॉड्यूल और नियमित पैकेजों __file__को उस .pyफ़ाइल पर सेट किया गया है जिसे उन्होंने बनाया था। नियमित और नेमस्पेस पैकेज ने __path__उन निर्देशिकाओं या निर्देशिकाओं के लिए सेट किया है, जिनसे वे बनाए गए थे।

जब आप करते हैं import foo.bar, तो उपरोक्त खोज पहले होती है foo, उसके बाद यदि कोई पैकेज मिलता है, तो खोज के बजाय खोज पथ के barसाथ किया जाता है । यदि पाया जाता है, और बनाया जाता है और आरंभिक होता है।foo.__path__sys.pathfoo.barfoofoo.bar

तो नियमित पैकेज और नेमस्पेस पैकेज कैसे मिलाते हैं? आम तौर पर वे नहीं करते हैं, लेकिन पुराने pkgutilस्पष्ट नामस्थान पैकेज पद्धति को निहित नाम स्थान पैकेज शामिल करने के लिए बढ़ाया गया है।

यदि आपके पास एक मौजूदा नियमित पैकेज है __init__.pyजो इस प्रकार है:

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

... विरासत का व्यवहार किसी अन्य नियमित पैकेज को खोजे गए पथ पर जोड़ना है __path__। लेकिन पायथन 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__) निहित नामस्थान पैकेजों को शामिल करने के लिए अद्यतन नहीं किया गया है।


2
सेटपूल के बारे में क्या? क्या मुझे namespace_packagesविकल्प का उपयोग करना है? और __import__('pkg_resources').declare_namespace(__name__)बात?
कविंग-चिउ

3
मैं जोड़ने चाहिए namespace_packages=['package']में setup.py?
लॉरेंट LAPORTE

1
@clacke: साथ namespace_packages=['package'], जीमेल-इंफो में setup.py एक जोड़ देगा namespace_packages.txt। अभी भी प्रभाव नहीं जानते ...
लॉरेंट लैपर्ट

1
@ kawing-चिऊ के लाभ pkg_resources.declare_namespaceसे अधिक pkgutil.extend_pathहै कि यह निगरानी करना जारी रखेंगे है sys.path। इस तरह, यदि sys.pathनामस्थान में एक पैकेज के बाद पहली बार एक नया आइटम जोड़ा जाता है, तो उस नए पथ आइटम में नाम स्थान में पैकेज अभी भी लोड किए जाने में सक्षम हैं। ( __import__('pkg_resources')ओवर का उपयोग करने का एक लाभ import pkg_resourcesयह है कि आप अंत तक pkg_resourcesउजागर नहीं होते हैं my_namespace_pkg.pkg_resources।)
आर्थर टक्का

1
@clacke यह उस तरह से काम नहीं करता है (लेकिन इसका वैसा ही असर होता है जैसे कि होता है)। यह उस फ़ंक्शन और घड़ियों के साथ बनाए गए सभी पैकेज नामस्थानों की एक वैश्विक सूची रखता है sys.path। जब sys.pathपरिवर्तन यह जाँचता है कि __path__क्या यह किसी नामस्थान को प्रभावित करता है , और यदि ऐसा होता है तो यह उन __path__गुणों को अद्यतन करता है ।
आर्थर टाका

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
पेशेवरों और उस बनाम का उपयोग करने का विपक्ष क्या हैं आयात __ ( 'pkg_resources')। Declare_namespace (__ नाम )?
जोफॉर्कर

14
सबसे पहले, __import__इस मामले में खराब शैली को माना जाता है क्योंकि इसे आसानी से सादे आयात विवरण के साथ बदला जा सकता है। इस बिंदु पर, pkg_resources एक गैर-मानक लाइब्रेरी है। हालांकि यह सेट-अप के साथ आता है, इसलिए यह एक गैर-मुद्दा है, हालांकि। त्वरित googling से पता चलता है कि pkgutil 2.5 में पेश किया गया था और pkg_resource इसे पूर्वनिर्मित करता है। फिर भी, pkgutil एक पहचाना जाने वाला समाधान है। pkg_resources शामिल करना वास्तव में PEP 365 में अस्वीकार कर दिया गया था।
माइक होर्डेकी

3
PEP 382 से उद्धरण : नेमस्पेस पैकेज के लिए वर्तमान अनिवार्य दृष्टिकोण ने नेमस्पेस पैकेज प्रदान करने के लिए कई छोटे-असंगत तंत्रों को जन्म दिया है। उदाहरण के लिए, pkgutil * .pkg फ़ाइलों का समर्थन करता है; सेटप्टूल नहीं करता है। इसी तरह, सेटप्टूल निरीक्षण ज़िप फ़ाइलों का समर्थन करता है, और इसके _namespace_packages चर के कुछ हिस्सों को जोड़ने का समर्थन करता है, जबकि pkgutil नहीं करता है।
ड्रेक गान

7
इन दो पंक्तियों को दोनों फाइलों में नहीं डाला जाना चाहिए: Package-1/namespace/__init__.py और यह Package-2/namespace/__init__.py प्रदान करते हुए कि हमें पता नहीं है कि किस पैकेज को पहले सूचीबद्ध किया गया है?
तुला

3
@ChristofferKarlsson हाँ, यह बात है, यह सब ठीक है यदि आप जानते हैं कि कौन सा पहला है, लेकिन असली सवाल यह है कि क्या आप गारंटी दे सकते हैं कि यह किसी भी स्थिति में पहला होगा, अर्थात अन्य उपयोगकर्ताओं के लिए?
तुला

5

यह खंड बहुत आत्म-व्याख्यात्मक होना चाहिए।

संक्षेप में, नाम स्थान कोड डालें, नाम स्थान घोषित करने के लिए __init__.pyअपडेट setup.pyकरें, और आप जाने के लिए स्वतंत्र हैं।


9
आपको हमेशा किसी लिंक के संबंधित हिस्से को उद्धृत करना चाहिए, यदि संबंधित लिंक मृत हो जाता है।
टीनडेड

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एक्सटेंशन है। तो आपके उदाहरण में आपके पास दो पैकेज हैं लेकिन कोई भी मॉड्यूल परिभाषित नहीं है। यदि आप मानते हैं कि एक पैकेज एक फाइल सिस्टम फ़ोल्डर है और एक मॉड्यूल फाइल है, तो आप देखते हैं कि पैकेज में मॉड्यूल क्यों होते हैं और आसपास कोई अन्य तरीका नहीं है।

इसलिए आपके उदाहरण में पैकेज -1 और पैकेज -2 फाइल सिस्टम पर फोल्डर हैं, जिन्हें आपने पायथन पथ पर रखा है, आप निम्नलिखित हो सकते हैं:

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

अब आप एक पैकेज है namespaceदो मॉड्यूल के साथ module1और module2। और जब तक आपके पास एक अच्छा कारण नहीं है, तो आपको संभवतः मॉड्यूल को फ़ोल्डर में रखना चाहिए और नीचे दिए गए अजगर पथ पर केवल यही होना चाहिए:

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

मैं उन चीजों के बारे में बात कर रहा हूं, zope.xजहां संबंधित संकुल का एक गुच्छा अलग डाउनलोड के रूप में जारी किया गया है।
जोफॉर्कर 18

ठीक है, लेकिन क्या प्रभाव आप प्राप्त करने की कोशिश कर रहे हैं। यदि सभी PYTHONPATH पायथन दुभाषिया पर संबंधित पैकेज वाले फ़ोल्डर आपके लिए कोई अतिरिक्त प्रयास के साथ उन्हें आपके लिए पाएंगे।
तेंदुए मावुशे 19

5
यदि आप पैकेज -1 और पैकेज -2 दोनों को PYTHONPATH में जोड़ते हैं, तो केवल पैकेज -1 / नाम स्थान / पायथन द्वारा देखा जाएगा।
सोरेन लोर्बोर्ग
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.