প্যাকেজ সাব ডিরেক্টরিতে ডেটা অ্যাক্সেস করুন


130

আমি মডিউলগুলির সাথে পাইথন প্যাকেজটি লিখছি যার একটি ./data/সাব-ডিরেক্টরিতে ডেটা ফাইল খোলার প্রয়োজন । এই মুহুর্তে আমার ক্লাস এবং ফাংশনগুলিতে হার্ডকোডযুক্ত ফাইলগুলির পথ রয়েছে। আমি আরও দৃust় কোড লিখতে চাই যা ব্যবহারকারীর সিস্টেমে এটি ইনস্টল থাকা নির্বিশেষে সাব-ডিরেক্টরিটি অ্যাক্সেস করতে পারে।

আমি বিভিন্ন পদ্ধতি চেষ্টা করেছি, তবে এখনও পর্যন্ত আমার ভাগ্য হয়নি। দেখে মনে হয় বেশিরভাগ "বর্তমান ডিরেক্টরি" কমান্ড সিস্টেমের পাইথন ইন্টারপ্রেটারের ডিরেক্টরি প্রদর্শন করে, মডিউলটির ডিরেক্টরি নয় not

এটি মনে হচ্ছে এটি একটি তুচ্ছ, সাধারণ সমস্যা হওয়া উচিত। তবুও আমি এটিকে বের করে আনতে পারি না। সমস্যার অংশ হ'ল আমার ডেটা ফাইলগুলি ফাইল নয় .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
ফাইলগুলি যদি কোনও বিতরণের (আই। ডিম) হয় তবে এটি কাজ করবে না। ডেটা ফাইলটিতে পেতে pkg_res્રોস ব্যবহার করুন।
ক্রিস

2
আসলে, এটি ভেঙে গেছে।
ফেডেরিকো

1
এছাড়াও __file__পাইপেক্সে নিয়ে কাজ করে না, কারণ মানটি জিপ ফাইলের পথ হয়ে যাবে।
পোড

1
এটি আসলে আমার পক্ষে কাজ করেছিল। কোনও সমস্যা হয়নি। আমি পাইথনটি ৩.6 ব্যবহার করছি
জোর্হে

1
বিতরণ (ডিম ইত্যাদির ক্ষেত্রে) এটি কাজ করবে না।
আদর্শ ত্রিবেদী

166

এটি করার স্ট্যান্ডার্ড উপায় হ'ল সেটআপলুলস প্যাকেজ এবং পিকেজি_সোর্সগুলি।

আপনি নীচের শ্রেণিবিন্যাস অনুসারে আপনার প্যাকেজটি রেখে দিতে পারেন এবং এই লিঙ্কটি অনুসারে প্যাকেজ সেটআপ ফাইলটিকে এটি আপনার ডেটা সংস্থান হিসাবে চিহ্নিত করতে পারেন:

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

তারপরে আপনি এই লিঙ্কটি অনুসারে pkg_res્રોস ব্যবহার করে সেই ফাইলগুলি পুনরায় সন্ধান এবং ব্যবহার করতে পারেন:

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__আমার জন্য কাজ করে।
mlt

4
কেন এটি আরও ভাল: রিসোর্স ম্যানেজার শ্রেণি প্যাকেজ সংস্থানগুলিতে অভিন্ন অ্যাক্সেস সরবরাহ করে, সেগুলি সংস্থানগুলি ফাইল এবং ডিরেক্টরি হিসাবে উপস্থিত থাকে বা কোনও প্রকারের সংরক্ষণাগারে সংকুচিত হয়
vrdhn

4
উজ্জ্বল পরামর্শ, ধন্যবাদ। আমি একটি আদর্শ ফাইল খোলা প্রয়োগ করে প্রয়োগ করেছিfrom pkg_resources import resource_filename open(resource_filename('data', 'data.txt'), 'rb')
২age

5
এটি ইনস্টল না হয়ে প্যাকেজটি ব্যবহার করার জন্য কীভাবে কাজ করবে? কেবল স্থানীয়ভাবে আমার পরীক্ষা করা হচ্ছে
ক্লাদিউ

11
অজগর 3.7 এ, এই উদ্দেশ্যে importlib.resourcesপ্রতিস্থাপন করে pkg_resources(পারফরম্যান্স সমস্যার কারণে)।
বেনজিমিন

13

আজ কাজ করে একটি সমাধান সরবরাহ করার জন্য। এই সমস্ত চাকাটি পুনরায় উদ্ভাবন না করতে অবশ্যই এই API টি ব্যবহার করুন।

একটি সত্য ফাইল সিস্টেমের নাম প্রয়োজন। জিপড ডিমগুলি ক্যাশে ডিরেক্টরিতে নেওয়া হবে:

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_res્રોস ব্যবহার করে প্যাকেজ আবিষ্কার এবং রিসোর্স অ্যাক্সেস


10

একটি উত্তর দেওয়ার ক্ষেত্রে প্রায়শই উল্লেখ করা যায় না যে বিশদ কোডটি যেভাবে কাজ করে না , তবে আমি এটি একটি ব্যতিক্রম বলে বিশ্বাস করি। পাইথন 3.7 যোগ করেছে importlib.resourcesযা প্রতিস্থাপনের কথা রয়েছে pkg_resources। এটি প্যাকেজগুলির মধ্যে ফাইলগুলির অ্যাক্সেসের জন্য কাজ করবে যার নামগুলিতে স্ল্যাশ নেই ie

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')

এই আচরণের কারণ "এটি ডিজাইনের মাধ্যমে" ; কিন্তু নকশা পরিবর্তন হতে পারে ...


আপনার কাছে কোনও ইউটিউব ভিডিওর চেয়ে "এটি ডিজাইনের মাধ্যমে" এর চেয়ে আরও ভাল লিঙ্ক রয়েছে - পাঠ্য সহ আরও একটি?
অঙ্কিত

@ দ্বিতীয় 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/… > নোট করুন যে সেটআপ স্ক্রিপ্টে সরবরাহিত কোনও পাথ-নাম (ফাইল বা ডিরেক্টরি) ইউনিক্স কনভেনশন, অর্থাৎ স্ল্যাশ-বিচ্ছিন্ন ব্যবহার করে লেখা উচিত। ডিস্টিউটিসরা এই প্ল্যাটফর্ম-নিরপেক্ষ প্রতিনিধিত্বকে সত্যই পথের নাম ব্যবহার করার আগে আপনার বর্তমান প্ল্যাটফর্মে উপযুক্ত যে কোনও ক্ষেত্রে রূপান্তর করার যত্ন নেবে। এটি আপনার সেটআপ স্ক্রিপ্টটিকে অপারেটিং সিস্টেমগুলিতে পোর্টেবল করে তোলে, যা অবশ্যই ডিস্ট্রুটিলসের অন্যতম প্রধান লক্ষ্য। এই স্পিরিটে, এই দস্তাবেজের সমস্ত পাথের নামগুলি স্ল্যাশ-বিচ্ছিন্ন।
ছ্যাঙ্গিউহেং

6

আমি মনে করি আমি একটি উত্তর শিকার করেছি।

আমি একটি মডিউল ডেটা_পথ.পি তৈরি করি যা আমি আমার অন্যান্য মডিউলগুলিতে এতে আমদানি করি:

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')
ankostis

@ কোঙ্কটিস সেটআপলগুলি সংরক্ষণাগারটি বের করার জন্য যথেষ্ট চালাক তবে যদি এটি সনাক্ত করে যে আপনি __file__কোথাও ব্যবহার করেছেন । আমার ক্ষেত্রে আমি একটি লাইব্রেরি ব্যবহার করি যা সত্যই স্ট্রিমগুলি না করে পথ চায় wants অবশ্যই আমি ফাইলগুলিকে অস্থায়ীভাবে ডিস্কে লিখতে পারি তবে অলস হয়ে আমি কেবল সেটআপলগুলির বৈশিষ্ট্যটি ব্যবহার করি।
letmaik
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.