एक पैकेजिंग प्रस्तावना:
इससे पहले कि आप संसाधन फ़ाइलों को पढ़ने के बारे में भी चिंता कर सकते हैं, पहला कदम यह सुनिश्चित करना है कि डेटा फ़ाइलों को पहली बार आपके वितरण में पैक किया जा रहा है - उन्हें सीधे स्रोत के पेड़ से पढ़ना आसान है, लेकिन महत्वपूर्ण हिस्सा बना रहा है सुनिश्चित करें कि ये संसाधन फ़ाइलें एक संस्थापित पैकेज में कोड से सुलभ हैं ।
अपनी परियोजना को इस तरह से संरचित करें, डेटा फ़ाइलों को पैकेज के भीतर एक उपनिर्देशिका में डालें :
.
├── package
│ ├── __init__.py
│ ├── templates
│ │ └── temp_file
│ ├── mymodule1.py
│ └── mymodule2.py
├── README.rst
├── MANIFEST.in
└── setup.py
आपको कॉल include_package_data=True
में पास होना चाहिए setup()
। मैनिफ़ेस्ट फ़ाइल की केवल तभी आवश्यकता होती है जब आप सेटपूल / डिस्टिलिल का उपयोग करना चाहते हैं और स्रोत वितरण का निर्माण करते हैं। यह सुनिश्चित करने के लिए कि templates/temp_file
इस उदाहरण प्रोजेक्ट संरचना के लिए पैक किया गया है, इस तरह की लाइन को प्रकट फ़ाइल में जोड़ें:
recursive-include package *
ऐतिहासिक क्रॉफ़्ट नोट: आधुनिक बिल्ड बैकेंड जैसे फ्लिट, कविता के लिए एक मैनिफ़ेस्ट फ़ाइल का उपयोग करने की आवश्यकता नहीं है , जिसमें डिफ़ॉल्ट रूप से पैकेज डेटा फ़ाइलें शामिल होंगी। इसलिए, यदि आप उपयोग कर रहे हैं pyproject.toml
और आपके पास कोई setup.py
फ़ाइल नहीं है, तो आप इसके बारे में सभी सामग्री को अनदेखा कर सकते हैं MANIFEST.in
।
अब, पैकेजिंग के साथ, पठन भाग पर ...
सिफ़ारिश करना:
मानक लाइब्रेरी pkgutil
APIs का उपयोग करें । यह पुस्तकालय कोड में इस तरह दिखने वाला है:
# within package/mymodule1.py, for example
import pkgutil
data = pkgutil.get_data(__name__, "templates/temp_file")
print("data:", repr(data))
text = pkgutil.get_data(__name__, "templates/temp_file").decode()
print("text:", repr(text))
यह zips में काम करता है। यह पायथन 2 और पायथन 3 पर काम करता है। इसे थर्ड-पार्टी निर्भरता की आवश्यकता नहीं है। मुझे वास्तव में किसी भी डाउनसाइड्स के बारे में पता नहीं है (यदि आप हैं, तो कृपया उत्तर पर टिप्पणी करें)।
बचने के बुरे तरीके:
खराब रास्ता # 1: स्रोत फ़ाइल से सापेक्ष पथ का उपयोग करना
यह वर्तमान में स्वीकृत उत्तर है। सबसे अच्छा, यह कुछ इस तरह दिखता है:
from pathlib import Path
resource_path = Path(__file__).parent / "templates"
data = resource_path.joinpath("temp_file").read_bytes()
print("data", repr(data))
इसमें गलत क्या है? आपके पास उपलब्ध फ़ाइलों और उपनिर्देशिकाओं की धारणा सही नहीं है। यह तरीका काम नहीं करता है अगर कोड को ज़िप या व्हील में पैक किया जाता है, और यह पूरी तरह से उपयोगकर्ता के नियंत्रण से बाहर हो सकता है कि क्या आपका पैकेज फाइल सिस्टम पर बिल्कुल भी नहीं निकाला जाता है।
खराब तरीका # 2: pkg_resources API का उपयोग करना
यह शीर्ष मतदान के उत्तर में वर्णित है। यह कुछ इस तरह दिखता है:
from pkg_resources import resource_string
data = resource_string(__name__, "templates/temp_file")
print("data", repr(data))
इसमें गलत क्या है? यह एक कहते हैं क्रम पर निर्भरता setuptools , जो अधिमानतः एक होना चाहिए स्थापित केवल समय निर्भरता। आयात करना और उपयोग करना pkg_resources
वास्तव में धीमा हो सकता है, क्योंकि कोड सभी स्थापित पैकेजों का एक कार्य सेट बनाता है, भले ही आप केवल अपने स्वयं के पैकेज संसाधनों में रुचि रखते थे । यह स्थापित समय पर एक बड़ी बात नहीं है (क्योंकि स्थापना एक बार बंद है), लेकिन यह रनटाइम पर बदसूरत है।
खराब तरीका # 3: importlib.resources API का उपयोग करना
यह वर्तमान में शीर्ष-मतदान जवाब में सिफारिश है। यह हाल ही में एक मानक पुस्तकालय परिवर्धन ( पायथन 3.7 में नया ) है, लेकिन एक बैकपोर्ट भी उपलब्ध है। यह इस तरह दिख रहा है:
try:
from importlib.resources import read_binary
from importlib.resources import read_text
except ImportError:
# Python 2.x backport
from importlib_resources import read_binary
from importlib_resources import read_text
data = read_binary("package.templates", "temp_file")
print("data", repr(data))
text = read_text("package.templates", "temp_file")
print("text", repr(text))
इसमें गलत क्या है? खैर, दुर्भाग्य से, यह काम नहीं करता ... अभी तक। यह अभी भी एक अधूरा एपीआई है, इसका उपयोग करके importlib.resources
आपको एक खाली फ़ाइल जोड़ने की आवश्यकता होगी templates/__init__.py
ताकि डेटा फाइलें एक उप-पैकेज के बजाय एक उप-पैकेज के भीतर रहेंगी। यह package/templates
सबडायरेक्ट को package.templates
अपने आप में एक आयात योग्य उप-पैकेज के रूप में भी उजागर करेगा । यदि यह कोई बड़ी बात नहीं है और यह आपको परेशान नहीं करता है, तो आप आगे बढ़ सकते हैं और __init__.py
वहां फ़ाइल जोड़ सकते हैं और संसाधनों तक पहुंचने के लिए आयात प्रणाली का उपयोग कर सकते हैं। हालाँकि, जब आप इस पर होते हैं, तो आप इसे my_resources.py
इसके बजाय एक फ़ाइल में बना सकते हैं , और बस मॉड्यूल में कुछ बाइट्स या स्ट्रिंग चर को परिभाषित करते हैं, फिर उन्हें पायथन कोड में आयात करते हैं। यह आयात प्रणाली यहाँ भारी भारोत्तोलन कर रही है।
उदाहरण परियोजना:
मैंने github पर एक उदाहरण परियोजना बनाई है और PyPI पर अपलोड की गई है , जो ऊपर चर्चा किए गए सभी चार दृष्टिकोणों को प्रदर्शित करता है। इसके साथ आज़माएँ:
$ pip install resources-example
$ resources-example
अधिक जानकारी के लिए https://github.com/wimglenn/resources-example देखें ।