पैकेज उपनिर्देशिका में एक्सेस डेटा


130

मैं उन मॉड्यूल के साथ एक अजगर पैकेज लिख रहा हूं जिन्हें एक ./data/उपनिर्देशिका में डेटा फ़ाइलों को खोलने की आवश्यकता है । अभी मेरे पास मेरी कक्षाओं और फ़ंक्शंस में हार्डकोड की गई फ़ाइलों के लिए रास्ते हैं। मैं अधिक मजबूत कोड लिखना चाहूंगा जो उपयोगकर्ता के सिस्टम पर स्थापित होने के बावजूद उपनिर्देशिका तक पहुंच सकता है।

मैंने कई तरह के तरीके आजमाए हैं, लेकिन अभी तक मुझे कोई किस्मत नहीं मिली है। ऐसा लगता है कि अधिकांश "वर्तमान निर्देशिका" कमांड सिस्टम के अजगर इंटरप्रेटर की निर्देशिका को लौटाते हैं, न कि मॉड्यूल की निर्देशिका को।

ऐसा लगता है जैसे यह एक तुच्छ, सामान्य समस्या होना चाहिए। फिर भी मैं इसका पता नहीं लगा सकता। समस्या का एक हिस्सा यह है कि मेरी डेटा फाइलें फाइलें नहीं हैं .py, इसलिए मैं आयात कार्यों और इस तरह का उपयोग नहीं कर सकता।

कोई सुझाव?

अभी मेरा पैकेज निर्देशिका जैसा दिखता है:

/
__init__.py
module1.py
module2.py
data/   
   data.txt

मैं का उपयोग करने की कोशिश कर रहा हूँ data.txtसे module*.py!


जवाबों:


24

आप __file__पैकेज के लिए रास्ता पाने के लिए इस तरह का उपयोग कर सकते हैं :

import os
this_dir, this_filename = os.path.split(__file__)
DATA_PATH = os.path.join(this_dir, "data", "data.txt")
print open(DATA_PATH).read()

44
यह काम नहीं करेगा यदि फाइलें एक वितरण (IE। अंडा) में हैं। डेटा फ़ाइल में पाने के लिए pkg_resources का उपयोग करें।
क्रिस

2
दरअसल, यह टूट गया है।
फेडरिको

1
इसके अलावा, __file__py2.exe के साथ काम नहीं करता है, क्योंकि मूल्य ज़िप फ़ाइल का पथ होगा।
पॉड

1
यह वास्तव में मेरे लिए काम किया। कोई दिक्कत नहीं हुई। मैं
जॉर्ज

1
यह वितरण (अंडे आदि) के मामले में काम नहीं करेगा।
आदर्श त्रिवेदी

166

ऐसा करने का मानक तरीका सेटपूलस पैकेज और pkg_resources है।

आप निम्न पदानुक्रम के अनुसार अपने पैकेज को लेट सकते हैं, और अपने डेटा संसाधनों को इंगित करने के लिए पैकेज सेटअप फ़ाइल को कॉन्फ़िगर कर सकते हैं, जैसा कि इस लिंक में है:

http://docs.python.org/distutils/setupscript.html#installing-package-data

आप इस लिंक के अनुसार pkg_resources का उपयोग करके उन फ़ाइलों को फिर से पा सकते हैं और उनका उपयोग कर सकते हैं:

http://peak.telecommunity.com/DevCenter/PkgResources#basic-resource-access

import pkg_resources

DATA_PATH = pkg_resources.resource_filename('<package name>', 'data/')
DB_FILE = pkg_resources.resource_filename('<package name>', 'data/sqlite.db')

7
नहीं होगा pkg_resources पर एक रन-टाइम निर्भरता बनाने setuptools ? उदाहरण के लिए, मैं एक डेबियन पैकेज को पुनर्वितरित करता हूं तो मैं python-setuptoolsउसके लिए सिर्फ निर्भर क्यों रहूंगा ? अभी तक __file__मेरे लिए ठीक काम करता है।
जूल 12'13

4
यह बेहतर क्यों है: संसाधन
प्रबंधक

4
शानदार सुझाव, धन्यवाद। मैं एक मानक फ़ाइल खुला का उपयोग कर लागू कियाfrom pkg_resources import resource_filename open(resource_filename('data', 'data.txt'), 'rb')
eageranalyst

5
जब यह स्थापित नहीं है तो पैकेज का उपयोग करने के लिए यह कैसे काम करेगा? बस स्थानीय स्तर पर परीक्षण मेरा मतलब है
Claudiu

11
अजगर 3.7 में, इस उद्देश्य (प्रदर्शन समस्याओं के कारण) के लिए importlib.resourcesप्रतिस्थापित करता है pkg_resources
बेंजामिन

13

आज काम कर रहे एक समाधान प्रदान करने के लिए। निश्चित रूप से इस एपीआई का उपयोग उन सभी पहियों को सुदृढ़ नहीं करने के लिए करें।

एक सच्चे फाइलसिस्टम फ़ाइलनाम की जरूरत है। ज़िपित अंडों को कैश डायरेक्टरी में निकाला जाएगा:

from pkg_resources import resource_filename, Requirement

path_to_vik_logo = resource_filename(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png")

निर्दिष्ट संसाधन के लिए एक पठनीय फ़ाइल जैसी वस्तु लौटाएं; यह एक वास्तविक फ़ाइल, एक स्ट्रिंग, या कुछ समान वस्तु हो सकती है। धारा "बाइनरी मोड" में है, इस अर्थ में कि संसाधन में जो भी बाइट्स हैं, उन्हें इस रूप में पढ़ा जाएगा।

from pkg_resources import resource_stream, Requirement

vik_logo_as_stream = resource_stream(Requirement.parse("enb.portals"), "enb/portals/reports/VIK_logo.png")

पैकेज डिस्कवरी और संसाधन एक्सेस pkg_resources का उपयोग करते हुए


10

एक उत्तर बनाने में अक्सर कोई मतलब नहीं होता है कि विवरण कोड जो काम नहीं करता है, लेकिन मैं इसे अपवाद मानता हूं। पायथॉन 3.7 ने कहा importlib.resourcesकि इसे प्रतिस्थापित करना चाहिए pkg_resources। यह उन पैकेजों में फ़ाइलों तक पहुँचने के लिए काम करेगा जिनके नाम में स्लैश नहीं हैं , अर्थात

foo/
    __init__.py
    module1.py
    module2.py
    data/   
       data.txt
    data2.txt

उदाहरण के लिए आप data2.txtपैकेज के अंदर पहुँच सकते हैंfoo

importlib.resources.open_binary('foo', 'data2.txt')

लेकिन यह एक अपवाद के साथ विफल होगा

>>> importlib.resources.open_binary('foo', 'data/data.txt')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3.7/importlib/resources.py", line 87, in open_binary
    resource = _normalize_path(resource)
  File "/usr/lib/python3.7/importlib/resources.py", line 61, in _normalize_path
    raise ValueError('{!r} must be only a file name'.format(path))
ValueError: 'data/data2.txt' must be only a file name

इसे एक पैकेज के रूप __init__.pyमें रखकर dataऔर फिर इसका उपयोग करके तय नहीं किया जा सकता है :

importlib.resources.open_binary('foo.data', 'data.txt')

इस व्यवहार का कारण "यह डिजाइन द्वारा है" ; लेकिन डिजाइन बदल सकता है ...


क्या आपके पास यूट्यूब वीडियो की तुलना में "यह डिज़ाइन द्वारा है" के लिए बेहतर लिंक है - अधिमानतः पाठ के साथ?
gerrit

@ एगरिट 2 में टेक्स्ट होता है। "This was a deliberate choice, but I think you have a valid use case. @brettcannon what do you think? And if we allow this, should we make sure it gets into Python 3.7?"
अंती हापाला

8

आपको अपने पूरे मॉड्यूल के लिए एक नाम की आवश्यकता है, आपको दी गई निर्देशिका ट्री उस विवरण को सूचीबद्ध नहीं करती है, मेरे लिए यह काम किया है:

import pkg_resources
print(    
    pkg_resources.resource_filename(__name__, 'data/data.txt')
)

पैक किए गए डेटा फ़ाइलों के साथ एक नाम मिलान के आधार पर फ़ाइलों को हल करने के लिए उल्लेखनीय रूप से सेटप्टूल दिखाई नहीं देते हैं, इसलिए आप गुनना है जिसमें data/उपसर्ग को शामिल करना है चाहे कितना भी हो। os.path.join('data', 'data.txt)यदि आपको वैकल्पिक निर्देशिका विभाजकों की आवश्यकता है, तो आप इसका उपयोग कर सकते हैं , आम तौर पर मुझे हार्ड-कोडित यूनिक्स शैली निर्देशिका विभाजकों के साथ कोई संगतता समस्या नहीं मिलती है।


docs.python.org/3.6/distutils/… > ध्यान दें कि सेटअप स्क्रिप्ट में दिए गए किसी भी पथनाम (फ़ाइल या निर्देशिका) को यूनिक्स सम्मेलन का उपयोग करके लिखा जाना चाहिए, अर्थात स्लैश-अलग। Distutils वास्तव में pathname का उपयोग करने से पहले इस प्लेटफ़ॉर्म-न्यूट्रल प्रतिनिधित्व को आपके वर्तमान प्लेटफ़ॉर्म में जो भी उचित हो, परिवर्तित करने का ध्यान रखेगा। यह आपके सेटअप स्क्रिप्ट को ऑपरेटिंग सिस्टम में पोर्टेबल बनाता है, जो निश्चित रूप से डिस्टुटिल्स के प्रमुख लक्ष्यों में से एक है। इस भावना में, इस दस्तावेज़ के सभी मार्गनाम स्लैश-पृथक हैं।
चांग्येंग फेंग

6

मुझे लगता है कि मैंने एक जवाब का शिकार किया।

मैं एक मॉड्यूल data_path.py बनाता हूं, जिसे मैं अपने अन्य मॉड्यूल में आयात करता हूं:

data_path = os.path.join(os.path.dirname(__file__),'data')

और फिर मैं अपनी सभी फाइलें खोल देता हूं

open(os.path.join(data_path,'filename'), <param>)

2
यह तब काम करने में विफल होगा जब संसाधन एक संग्रह वितरण (जैसे ज़िप्ड अंडा) में हो। कुछ इस तरह पसंद करें:pkg_resources.resource_string('pkg_name', 'data/file.txt')
akostis

@ankostis setuptools संग्रह को निकालने के लिए काफी चतुर है अगर यह पता लगाता है कि आपने __file__कहीं इस्तेमाल किया है। मेरे मामले में मैं एक पुस्तकालय का उपयोग करता हूं जो वास्तव में पथ चाहता है और धाराएं नहीं। बेशक, मैं फ़ाइलों को अस्थायी रूप से डिस्क पर लिख सकता था लेकिन आलसी होने के नाते मैं बस सेटपूल की सुविधा का उपयोग करता हूं।
लेटमाईक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.