বিলিয়নতম সময়ের জন্য আপেক্ষিক আমদানি


716

আমি এখানে ছিলাম:

এবং প্রচুর ইউআরএল যা আমি অনুলিপি করিনি, কিছু এসও-তে, কিছু অন্য সাইটে, যখন আমি যখন ভেবেছিলাম যে সমাধানটি দ্রুত করব।

চিরকালীন পুনরাবৃত্তি হওয়া প্রশ্নটি: উইন্ডোজ 7, ​​32-বিট পাইথন 2.7.3 এর সাথে আমি কীভাবে এই "নন-প্যাকেজে আপেক্ষিক আমদানির চেষ্টা করা" বার্তাটি সমাধান করব? আমি প্যাকেজ -0328 এ প্যাকেজের সঠিক প্রতিলিপি তৈরি করেছি:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
        moduleY.py
    subpackage2/
        __init__.py
        moduleZ.py
    moduleA.py

কনসোল থেকে আমদানি করা হয়েছিল।

আমি তাদের উপযুক্ত মডিউলগুলিতে স্প্যাম এবং ডিমের মতো ফাংশন তৈরি করেছি। স্বাভাবিকভাবেই, এটি কার্যকর হয়নি। উত্তরটি আমার তালিকাভুক্ত চতুর্থ ইউআরএলটিতে আপাতদৃষ্টিতে রয়েছে তবে এটি আমার কাছে সমস্ত প্রাক্তন ছাত্র। আমি যে URL টি দেখেছিলাম তার একটিতে এই প্রতিক্রিয়া ছিল:

আপেক্ষিক আমদানিগুলি প্যাকেজ শ্রেণিবিন্যাসে মডিউলটির অবস্থান নির্ধারণ করতে মডিউলটির নাম বৈশিষ্ট্য ব্যবহার করে। যদি মডিউলটির নামটিতে কোনও প্যাকেজ সম্পর্কিত তথ্য না থাকে (যেমন এটি 'মেইন' তে সেট করা থাকে) তবে আপেক্ষিক আমদানিগুলি সমাধান করা হবে যেন মডিউলটি ফাইল সিস্টেমে মডিউলটি প্রকৃতপক্ষে কোথায় থাকে তা নির্বিশেষে একটি শীর্ষ স্তরের মডিউল।

উপরের প্রতিক্রিয়া আশাব্যঞ্জক দেখায় তবে এটি আমার কাছে সমস্ত হায়ারোগ্লিফ। সুতরাং আমার প্রশ্ন, আমি কীভাবে পাইথনকে "নন-প্যাকেজে আপেক্ষিক আমদানির চেষ্টা" করব না? অনুমিতভাবে জড়িত একটি উত্তর আছে যা।

কেউ দয়া করে আমাকে বলতে পারেন কেন পাইথন সেই ত্রুটি বার্তা দেয়, "নন-প্যাকেজ" এর অর্থ কী, আপনি কেন এবং কীভাবে একটি 'প্যাকেজ' সংজ্ঞায়িত করেন এবং একটি কিন্ডারগার্টেনারের পক্ষে বোঝার জন্য যথাযথ উত্তর যথেষ্ট সহজভাবে দেওয়া হয়েছে


5
আপনি প্রদর্শিত ফাইলগুলি কীভাবে ব্যবহার করার চেষ্টা করছেন? আপনি কি কোড চালাচ্ছেন?
ব্রেণবার্ন

পাইথন.অর্গ.দেব / পেপস / পেপ-0328 দেখুন । আমি আমার পোস্টে বর্ণিত প্যাকেজ ফর্ম্যাটটি ব্যবহার করেছি। Init .py ফাইল খালি আছে। মডিউলওয়াই.পি-এর রয়েছে def spam(): pass, মডিউলএ.পি def eggs(): pass। আমি "কিছু কিছু আমদানি" আদেশ থেকে একটি দম্পতিকে কার্যকর করার চেষ্টা করেছি, কিন্তু তারা কার্যকর হয়নি work আবার, পিপ -0328 দেখুন।

6
আমার উত্তর দেখুন। আপনি কী করছেন তা আপনি এখনও পুরোপুরি পরিষ্কার করেননি, তবে আপনি যদি from .something import somethingইন্টারেক্টিভ দোভাষীর সাথে করার চেষ্টা করছেন , এটি কার্যকর হবে না। আপেক্ষিক আমদানি কেবলমাত্র মডিউলগুলির মধ্যে ব্যবহার করা যেতে পারে, ইন্টারেক্টিভভাবে নয়।
ব্রেণবার্ন

105
এই মন্তব্য হিসাবে "বিলিয়ন" মানুষ - ঠিক এই 83,136 - এই প্রশ্নটি অনুসন্ধান করতে আমদানিতে যথেষ্ট অসুবিধা হচ্ছে যে কেবল সত্য; আমরা কেবল এই সিদ্ধান্তে পৌঁছাতে পারি যে পাইথন আমদানিগুলি বেশিরভাগ প্রোগ্রামার না হলেও অনেকের জন্য স্ব-স্বজ্ঞাত। গাইড, সম্ভবত আপনার এটি গ্রহণ করা উচিত এবং আমদানি ব্যবস্থাটি নতুন করে ডিজাইনের জন্য একটি কমিটির কাছে অনুরোধ করা উচিত। সর্বনিম্ন, x.py এবং z.py একই ডিরেক্টরিতে থাকলে এই বাক্য গঠনটি কাজ করা উচিত। যথা, যদি x.py এর স্টেটমেন্ট থাকে, ".z আমদানি MyZebraClass থেকে" x এর প্রধান হিসাবে চালিত হয় তবে x ইভিএন আমদানি করা উচিত ! কেন এত কঠিন যে?
স্টিভ এল

4
এই থ্রেডের বেশিরভাগ অংশ পড়ার পরে, যদিও এই প্রশ্নের উত্তর না হলেও, "কেবল নিরঙ্কুশ আমদানি ব্যবহার করুন" এর সমাধান বলে মনে হচ্ছে ...
কোডজকি

উত্তর:


1043

স্ক্রিপ্ট বনাম মডিউল

এখানে একটি ব্যাখ্যা। সংক্ষিপ্ত সংস্করণটি হ'ল সরাসরি পাইথন ফাইল চালানো এবং অন্য কোথাও থেকে ফাইলটি আমদানির মধ্যে একটি বড় পার্থক্য রয়েছে। কোন ফাইলটি কোন ডিরেক্টরিতে রয়েছে তা জেনে যাওয়া পাইথন কোন প্যাকেজটিকে প্যাকেজ বলে মনে করে তা নির্ধারণ করে না That এটি নির্ভর করে যে আপনি কীভাবে পাইথনে ফাইলটি লোড করবেন (চালিয়ে বা আমদানির মাধ্যমে)।

পাইথন ফাইল লোড করার দুটি উপায় রয়েছে: শীর্ষ স্তরের স্ক্রিপ্ট হিসাবে বা মডিউল হিসাবে। আপনি যদি সরাসরি এটি প্রয়োগ করেন তবে একটি ফাইল শীর্ষ স্তরের স্ক্রিপ্ট হিসাবে লোড করা হয়, উদাহরণস্বরূপ python myfile.pyকমান্ড লাইনে টাইপ করে। আপনি python -m myfileযদি এটি করেন তবে এটি মডিউল হিসাবে লোড করা হয় বা importঅন্য কোনও ফাইলে কোনও বিবৃতি দেওয়ার সময় এটি লোড হয়। একসাথে কেবলমাত্র একটি শীর্ষ স্তরের স্ক্রিপ্ট থাকতে পারে; শীর্ষ স্তরের স্ক্রিপ্টটি পাইথন ফাইল যা আপনি জিনিস শুরু করতে দৌড়েছিলেন।

নামকরণ

যখন কোনও ফাইল লোড হয়, তখন তাকে একটি নাম দেওয়া হয় (যা এর __name__বৈশিষ্ট্যে সঞ্চিত থাকে )। এটি শীর্ষ-স্তরের স্ক্রিপ্ট হিসাবে লোড করা থাকলে, এর নাম __main__। যদি এটি মডিউল হিসাবে লোড করা হয় তবে এর নাম ফাইল নাম, কোনও প্যাকেজ / সাব-প্যাকেজগুলির নামের আগে এটি বিন্দু দ্বারা পৃথক।

উদাহরণস্বরূপ আপনার উদাহরণে:

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

যদি আপনি আমদানি করেন moduleX(দ্রষ্টব্য: আমদানি করা , সরাসরি চালানো হয় না), এর নাম হবে package.subpackage1.moduleX। আপনি যদি আমদানি করেন তবে moduleAএর নাম হবে package.moduleA। তবে আপনি যদি সরাসরি moduleX কমান্ড লাইন থেকে চালনা করেন তবে এর নামটি পরিবর্তিত হবে __main__এবং আপনি যদি সরাসরি moduleAকমান্ড লাইন থেকে চালান তবে এর নাম হবে __main__। যখন কোনও মডিউলটি শীর্ষ স্তরের স্ক্রিপ্ট হিসাবে চালানো হয়, তখন এটির স্বাভাবিক নামটি হারা হয় এবং পরিবর্তে এর নাম হয় __main__

এতে থাকা প্যাকেজটির মাধ্যমে নয় একটি মডিউল অ্যাক্সেস করা হচ্ছে

একটি অতিরিক্ত কুঁচকে আছে: মডিউলটির নাম এটি যে ডিরেক্টরিতে রয়েছে সেখান থেকে "সরাসরি" আমদানি করা হয়েছিল বা প্যাকেজের মাধ্যমে আমদানি করা হয়েছে কিনা তার উপর নির্ভর করে। আপনি কেবলমাত্র ডিরেক্টরিতে পাইথন চালনা করলে, এবং একই ডিরেক্টরিতে (বা এর একটি উপ-ডিরেক্টরি) কোনও ফাইল আমদানির চেষ্টা করার পরে এটি কেবলমাত্র তত্ক্ষণিক হয়। উদাহরণস্বরূপ, আপনি যদি পাইথন ইন্টারপ্রেটারিকে ডিরেক্টরিতে শুরু করেন package/subpackage1এবং করেন তবে import moduleXএর নামটি moduleXকেবল হবে moduleX, না হবে package.subpackage1.moduleX। কারণ পাইথন তার অনুসন্ধানের পথে প্রারম্ভকালে বর্তমান ডিরেক্টরিটি যুক্ত করে; যদি এটি বর্তমান ডিরেক্টরিতে থাকা-হওয়া-আমদানি করা মডিউলটি খুঁজে পায়, তবে তা জানতে পারবে না যে ডিরেক্টরিটি কোনও প্যাকেজের অংশ, এবং প্যাকেজ তথ্য মডিউলটির নামের অংশ হয়ে উঠবে না।

একটি বিশেষ ক্ষেত্রে হ'ল যদি আপনি ইন্টারপ্রিটার ইন্টারেক্টিভভাবে চালনা করেন (যেমন, কেবল pythonফ্লাইতে পাইথন কোডটি টাইপ করুন এবং প্রবেশ করা শুরু করুন)। এক্ষেত্রে সেই ইন্টারেক্টিভ সেশনের নাম __main__

আপনার ত্রুটি বার্তার জন্য এখন এখানে গুরুত্বপূর্ণ বিষয়: মডিউলটির যদি কোনও বিন্দু না থাকে তবে এটি কোনও প্যাকেজের অংশ হিসাবে বিবেচিত হবে না । ফাইলটি আসলে ডিস্কে রয়েছে তা বিবেচ্য নয়। এটির জন্য যা গুরুত্বপূর্ণ তা হ'ল এটির নাম কী এবং আপনি কীভাবে এটি লোড করেছিলেন তার নাম নির্ভর করে।

আপনি আপনার প্রশ্নের অন্তর্ভুক্ত উদ্ধৃতি দেখুন:

আপেক্ষিক আমদানিগুলি প্যাকেজ শ্রেণিবিন্যাসে মডিউলটির অবস্থান নির্ধারণ করতে মডিউলটির নাম বৈশিষ্ট্য ব্যবহার করে। যদি মডিউলটির নামটিতে কোনও প্যাকেজ সম্পর্কিত তথ্য না থাকে (যেমন এটি 'মেইন' তে সেট করা থাকে) তবে আপেক্ষিক আমদানিগুলি সমাধান করা হবে যেন মডিউলটি ফাইল সিস্টেমে মডিউলটি প্রকৃতপক্ষে কোথায় থাকে তা নির্বিশেষে একটি শীর্ষ স্তরের মডিউল।

আপেক্ষিক আমদানি ...

আপেক্ষিক আমদানি প্যাকেজে কোথায় রয়েছে তা নির্ধারণ করতে মডিউলটির নাম ব্যবহার করে । আপনি যখন কোনও আপেক্ষিক আমদানির মতো ব্যবহার করেন from .. import foo, তখন বিন্দুগুলি প্যাকেজ শ্রেণিবিন্যাসের কয়েকটি স্তরের পদক্ষেপের নির্দেশ দেয়। উদাহরণস্বরূপ, যদি আপনার বর্তমান মডিউলটির নাম হয় package.subpackage1.moduleXতবে ..moduleAতার অর্থ হবে package.moduleA। একটি জন্য from .. importকাজ করার জন্য, মডিউল নাম হিসাবে রয়েছে অনেক বিন্দু হিসাবে অন্তত থাকতে হবে importবিবৃতি।

... একটি প্যাকেজে কেবল আপেক্ষিক

তবে, আপনার মডিউলটির নামটি থাকলে __main__এটি কোনও প্যাকেজে বিবেচিত হবে না। এর নামের কোনও বিন্দু নেই এবং তাই আপনি এর from .. importভিতরে বিবৃতি ব্যবহার করতে পারবেন না । আপনি যদি এটির চেষ্টা করে থাকেন তবে আপনি "নন-প্যাকেজটিতে আপেক্ষিক-আমদানি" ত্রুটি পাবেন।

স্ক্রিপ্টগুলি আপেক্ষিক আমদানি করতে পারে না

আপনি সম্ভবত যা করেছেন তা হ'ল আপনি চালনার চেষ্টা করেছেন moduleXবা কমান্ড লাইন থেকে সেরকমই। আপনি যখন এটি করেছিলেন, এর নামটি সেট করা হয়েছিল __main__, যার অর্থ এটির মধ্যে আপেক্ষিক আমদানি ব্যর্থ হবে, কারণ এর নামটি এটি প্রকাশ করে না যে এটি কোনও প্যাকেজে রয়েছে। নোট করুন যে আপনি যদি মডিউল যেখানে একই ডিরেক্টরি থেকে পাইথন চালনা করেন এবং তারপর সেই মডিউলটি আমদানির চেষ্টা করেন, কারণ উপরে বর্ণিত হিসাবে পাইথন বর্তমান ডিরেক্টরিটিতে মডিউলটি উপলব্ধি না করে "খুব তাড়াতাড়ি" খুঁজে পাবেন is একটি প্যাকেজের অংশ।

এছাড়াও মনে রাখবেন যে আপনি যখন ইন্টারেক্টিভ দোভাষীটি চালাবেন, সেই ইন্টারেক্টিভ সেশনের "নাম" সর্বদা থাকে __main__। সুতরাং আপনি সরাসরি ইন্টারেক্টিভ সেশন থেকে আপেক্ষিক আমদানি করতে পারবেন না । আপেক্ষিক আমদানি কেবলমাত্র মডিউল ফাইলের মধ্যেই ব্যবহারের জন্য।

দুটি সমাধান:

  1. আপনি যদি সত্যিই moduleXসরাসরি চালাতে চান তবে আপনি এখনও এটি কোনও প্যাকেজের অংশ হিসাবে বিবেচনা করতে চান, আপনি এটি করতে পারেন python -m package.subpackage1.moduleX-mপাইথন বলে না টপ লেভেল স্ক্রিপ্ট হিসাবে, একটি মডিউল যেমন লোড করা হয়নি।

  2. অথবা সম্ভবত আপনি আসলে চালনা করতে চান না moduleX, আপনি কেবল কিছু অন্যান্য স্ক্রিপ্ট চালাতে চান, বলুন myfile.py, এটি ভিতরে ফাংশন ব্যবহার করে moduleX। যদি তাই হয়ে থাকে, করা myfile.py অন্য কোথাও - না ভিতরে packageডিরেক্টরির - এবং এটি চালানোর জন্য। যদি ভিতরে myfile.pyআপনি যেমন from package.moduleA import spamকাজ করেন তবে তা ঠিকঠাক কাজ করবে।

মন্তব্য

  • এই উভয় সমাধানের জন্য, প্যাকেজ ডিরেক্টরিটি ( packageউদাহরণস্বরূপ) পাইথন মডিউল অনুসন্ধানের পথ ( sys.path) থেকে অ্যাক্সেসযোগ্য । যদি এটি না হয় তবে আপনি কোনওভাবেই প্যাকেজে নির্ভরযোগ্যভাবে ব্যবহার করতে পারবেন না।

  • পাইথন ২.6 থেকে, প্যাকেজ-রেজোলিউশন উদ্দেশ্যে মডিউলটির "নাম" কেবল তার __name__বৈশিষ্ট্য দ্বারা নয় বৈশিষ্ট্য দ্বারা নির্ধারিত হয় __package__। এজন্য আমি __name__মডিউলটির "নাম" উল্লেখ করতে সুস্পষ্ট প্রতীক ব্যবহার করা এড়াচ্ছি । যেহেতু পাইথন 2.6 একটি মডিউল এর "নাম" কার্যকরভাবে হয় __package__ + '.' + __name__, বা শুধু __name__যদি __package__হয় None।)


62
Its name has no dots, and therefore you cannot use from .. import statements inside it. If you try to do so, you will get the "relative-import in non-package" error.এটি মূলত বিরক্তিকর। বর্তমান ডিরেক্টরিটি দেখার পক্ষে এত কঠিন কী? পাইথন এটি সক্ষম হতে হবে। এটি কি সংস্করণ 3x এ ঠিক করা হয়েছে?

7
@ স্টপফোরজটিংমাইকাউন্টস ... কোনও ফাইলের অভ্যন্তরে আপনি এটি করতে __package__ = 'package.subpackage1'বা পছন্দ করতে পারেন। তারপরে সেই ফাইলটি কেবল সর্বদা চালানো হলেও সর্বদা সেই প্যাকেজের অংশ হিসাবে বিবেচিত হবে । আপনার সম্পর্কে যদি আপনার অন্য প্রশ্ন থাকে তবে __package__একটি আলাদা প্রশ্ন জিজ্ঞাসা করতে পারেন কারণ আমরা এখানে আপনার মূল প্রশ্নটি বন্ধ করে দিচ্ছি।
ব্রেণবার্ন

108
পাইথন সম্পর্কিত সমস্ত আমদানি প্রশ্নের উত্তর এটি হওয়া উচিত। এটি ডক্সেও হওয়া উচিত, এমনকি।
এডসৌফি

10
দেখুন python.org/dev/peps/pep-0366 - "নোট যে এই boilerplate, যথেষ্ট শুধুমাত্র যদি শীর্ষ পর্যায়ে প্যাকেজ ইতিমধ্যে sys.path মাধ্যমে অ্যাক্সেসযোগ্য অতিরিক্ত কোড যে নিপূণভাবে ব্যবহার করেন sys.path সরাসরি মৃত্যুদন্ড জন্য অর্ডার প্রয়োজন হবে। ইতিমধ্যে শীর্ষস্থানীয় প্যাকেজটি আমদানিযোগ্য না হয়ে কাজ করার জন্য। - এই "অতিরিক্ত কোড" আসলে বেশ দীর্ঘ এবং সহজেই চালানোর জন্য প্যাকেজে অন্য কোথাও সংরক্ষণ করা যায় না বলে এটি আমার কাছে সবচেয়ে ঝামেলার বিষয়।
মাইকেল স্কট কুথবার্ট

14
এই উত্তরটি সম্পর্কিত __name__এবং সম্পর্কে কয়েকটি গুরুত্বপূর্ণ বিবরণে বন্ধ রয়েছে sys.path। বিশেষত, সাথে python -m pkg.mod, __name__সেট করা হয় __main__, নয় pkg.mod; এই ক্ষেত্রে __package__পরিবর্তে আপেক্ষিক আমদানি সমাধান করা হয় __name__। এছাড়াও, পাইথন sys.pathচলমান চলমান ডিরেক্টরিটির পরিবর্তে স্ক্রিপ্টের ডিরেক্টরি যুক্ত করে python path/to/script.py; এটি sys.pathসহ অন্যান্য অন্যান্য উপায়ে চলাকালীন বর্তমান ডিরেক্টরিটি যুক্ত করে python -m pkg.mod
ব্যবহারকারী 2357112 মনিকা 19

42

পাইথনের মধ্যে এটি আসলেই একটি সমস্যা। বিভ্রান্তির উত্স হ'ল লোকে ভুলভাবে আপেক্ষিক আমদানিকে পাথ আপেক্ষিক হিসাবে গ্রহণ করে যা তা নয়।

উদাহরণস্বরূপ আপনি যখন faa.py লিখবেন :

from .. import foo

এটির অর্থ কেবল তখনই থাকে যখন faa.py প্যাকেজের অংশ হিসাবে কার্যকর করার সময় অজগর দ্বারা সনাক্ত এবং লোড করা হত । সেক্ষেত্রে, faa.py এর জন্য মডিউলটির নাম উদাহরণস্বরূপ some_packagename.faa হবে । যদি পাইথনটি চালিত হয় কেবল বর্তমান ডিরেক্টরিতে ফাইলটি লোড করা হয়, তবে এর নামটি কোনও প্যাকেজকে উল্লেখ করবে না এবং শেষ পর্যন্ত আপেক্ষিক আমদানি ব্যর্থ হবে।

বর্তমান ডিরেক্টরিতে মডিউলগুলি উল্লেখ করার একটি সহজ সমাধান হ'ল এটি ব্যবহার করা:

if __package__ is None or __package__ == '':
    # uses current directory visibility
    import foo
else:
    # uses current package visibility
    from . import foo

5
সঠিক সমাধানটি হ'ল from __future__ import absolute_importএবং ব্যবহারকারীকে আপনার কোডটি সঠিকভাবে ব্যবহার করতে বাধ্য করুন ... যাতে আপনি সর্বদা করতে পারেনfrom . import foo
গিয়াকোমো আলজিটা

@ গিয়াকোমো: আমার সমস্যার একদম সঠিক উত্তর। ধন্যবাদ!
ফেবিও

8

এখানে একটি সাধারণ রেসিপি, উদাহরণ হিসাবে ফিট করার জন্য পরিবর্তিত হয়েছে যে আমি এখনই প্যাকেজ হিসাবে রচিত পাইথন লাইব্রেরিগুলি ব্যবহার করার জন্য ব্যবহার করছি, এতে আন্তঃনির্ভরশীল ফাইল রয়েছে, যেখানে আমি সেগুলির অংশগুলিকে টুকরোজের পরীক্ষা করতে সক্ষম হতে চাই। আসুন lib.fooএটিকে কল করুন এবং বলুন যে এটির lib.fileAজন্য ক্রিয়াকলাপ f1এবং f2এবং lib.fileBশ্রেণীর অ্যাক্সেস প্রয়োজন Class3

এটি printকীভাবে কাজ করে তা বর্ণনা করার জন্য আমি কয়েকটি কল অন্তর্ভুক্ত করেছি । অনুশীলনে আপনি সেগুলি মুছে ফেলতে চান (এবং সম্ভবত from __future__ import print_functionলাইনটিও)।

আমাদের যখন সত্যই প্রবেশ করতে হবে তখন এই নির্দিষ্ট উদাহরণটি প্রদর্শন করা খুব সহজ sys.path। (দেখুন লার্স 'উত্তর একটি মামলা যেখানে আমরা জন্য না এটি প্রয়োজন, আমরা প্যাকেজ ডিরেক্টরি দুই বা ততোধিক মাত্রার আছে, এবং তারপর আমরা ব্যবহার যখন os.path.dirname(os.path.dirname(__file__))-কিন্তু এটা সত্যিই নেই আঘাত পারেন এখানে।) এটি ছাড়া এই কাজটি করা নিরাপদ যথেষ্ট if _i in sys.pathপরীক্ষা। তবে, যদি প্রতিটি আমদানি করা ফাইল একই পথটি সন্নিবেশ করে instance উদাহরণস্বরূপ, যদি উভয়ই fileAএবং fileBপ্যাকেজ থেকে ইউটিলিটিগুলি আমদানি করতে চায় - এই sys.pathপথটি বেশ কয়েকবার একই পথ দিয়ে আপ করে, তাই if _i not in sys.pathবয়লারপ্লেটে থাকা ভাল।

from __future__ import print_function # only when showing how this works

if __package__:
    print('Package named {!r}; __name__ is {!r}'.format(__package__, __name__))
    from .fileA import f1, f2
    from .fileB import Class3
else:
    print('Not a package; __name__ is {!r}'.format(__name__))
    # these next steps should be used only with care and if needed
    # (remove the sys.path manipulation for simple cases!)
    import os, sys
    _i = os.path.dirname(os.path.abspath(__file__))
    if _i not in sys.path:
        print('inserting {!r} into sys.path'.format(_i))
        sys.path.insert(0, _i)
    else:
        print('{!r} is already in sys.path'.format(_i))
    del _i # clean up global name space

    from fileA import f1, f2
    from fileB import Class3

... all the code as usual ...

if __name__ == '__main__':
    import doctest, sys
    ret = doctest.testmod()
    sys.exit(0 if ret.failed == 0 else 1)

এখানে ধারণাটি হ'ল (এবং লক্ষ্য করুন যে এই সমস্ত পাইথন 2.7 এবং পাইথন 3.x জুড়ে একই কাজ করে):

  1. সাধারণ কোড থেকে নিয়মিত প্যাকেজ আমদানি হিসাবে import libবা from lib import fooহিসাবে চালানো __packageহয় libএবং __name__হয় lib.foo। আমরা প্রথম কোডের পথটি গ্রহণ করি, এর থেকে আমদানি করা .fileAইত্যাদি

  2. যদি হিসাবে চালানো python lib/foo.py, __package__কোনটি হতে পারে এবং __name__হতে হবে __main__

    আমরা দ্বিতীয় কোডের পথটি নিই। libনির্দেশিকা ইতিমধ্যেই থাকবে sys.pathতাই এটি যোগ করার জন্য কোন প্রয়োজন নেই। আমরা fileAইত্যাদি থেকে আমদানি করি

  3. মধ্যে চালানো হলে libডিরেক্টরির যেমন python foo.py, ব্যবহার ক্ষেত্রে 2 জন্য সমান।

  4. যদি libডিরেক্টরিটি ডিরেক্টরি হিসাবে চালানো হয় python -m fooতবে আচরণটি 2 এবং 3 কেসের সমান হয় তবে libডিরেক্টরিতে যাওয়ার পথটি নেই sys.path, তাই আমরা এটি আমদানির আগে যুক্ত করি। একই সাথে প্রযোজ্য যদি আমরা পাইথন চালাই এবং তারপরে import foo

    (যেহেতু . এখানে রয়েছে sys.path, আমাদের এখানে পাথের নিখুঁত সংস্করণ যুক্ত করার দরকার নেই This একটি গভীর প্যাকেজ নেস্টিং কাঠামো, যেখানে আমরা করতে চাই সেখানে from ..otherlib.fileC import ...একটি পার্থক্য রয়েছে you're আপনি যদি এটি না করে থাকেন তবে আপনি করতে পারেন সমস্ত sys.pathম্যানিপুলেশন সম্পূর্ণভাবে বাদ দিন ))

মন্তব্য

এখনও একটা কোলাহল আছে। যদি আপনি এই পুরো জিনিসটি বাইরে থেকে চালান:

$ python2 lib.foo

বা:

$ python3 lib.foo

আচরণের বিষয়বস্তুর উপর নির্ভর করে lib/__init__.py। যদি তা বিদ্যমান থাকে এবং খালি থাকে তবে সমস্ত কিছু ঠিক আছে:

Package named 'lib'; __name__ is '__main__'

তবে যদি lib/__init__.py নিজে আমদানি করে routineযাতে এটি routine.nameসরাসরি রফতানি করতে পারে তবে lib.nameআপনি পাবেন:

$ python2 lib.foo
Package named 'lib'; __name__ is 'lib.foo'
Package named 'lib'; __name__ is '__main__'

এটি হল, প্যাকেজটির মাধ্যমে মডিউলটি একবারে আমদানি হয়ে যায় এবং তারপরে আবার __main__যাতে এটি আপনার mainকোড চালায় । পাইথন ৩.6 এবং পরে এটি সম্পর্কে সতর্ক করুন:

$ python3 lib.routine
Package named 'lib'; __name__ is 'lib.foo'
[...]/runpy.py:125: RuntimeWarning: 'lib.foo' found in sys.modules
after import of package 'lib', but prior to execution of 'lib.foo';
this may result in unpredictable behaviour
  warn(RuntimeWarning(msg))
Package named 'lib'; __name__ is '__main__'

সাবধানবাণী নতুন, কিন্তু সতর্ক-সম্পর্কে আচরণ নয়। এটি কেউ কেউ ডাবল আমদানি ফাঁদ বলে ডাকে । (অতিরিক্ত তথ্যের জন্য 27487 সংখ্যাটি দেখুন )) নিক কোঘলান বলেছেন:

এই পরবর্তী ফাঁদটি পাইথনের সমস্ত বর্তমান সংস্করণে উপস্থিত রয়েছে, যার মধ্যে 3..৩ রয়েছে, এবং নিম্নলিখিত সাধারণ গাইডলাইনে সংক্ষিপ্তসার পাওয়া যায়: "কখনও পাইথন পথে কোনও প্যাকেজ ডিরেক্টরি বা কোনও প্যাকেজের ভিতরে কোনও ডিরেক্টরি যুক্ত করবেন না"।

নোট করুন যে আমরা এখানে এই নিয়ম লঙ্ঘন করার সময়, কেবল তখনই এটি করি যখন ফাইলটি লোড হচ্ছে প্যাকেজের অংশ হিসাবে লোড করা হচ্ছে না এবং আমাদের পরিবর্তনটি বিশেষত আমাদের সেই প্যাকেজের অন্যান্য ফাইলগুলিতে অ্যাক্সেস করার অনুমতি দেওয়ার জন্য ডিজাইন করা হয়েছে। (এবং যেমনটি আমি উল্লেখ করেছি, সম্ভবত একক স্তরের প্যাকেজগুলির জন্য আমাদের মোটেও এটি করা উচিত নয়)) আমরা যদি অতিরিক্ত পরিষ্কার হতে চাই, তবে আমরা এটিকে আবার লিখতে পারি, যেমন:

    import os, sys
    _i = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    if _i not in sys.path:
        sys.path.insert(0, _i)
    else:
        _i = None

    from sub.fileA import f1, f2
    from sub.fileB import Class3

    if _i:
        sys.path.remove(_i)
    del _i

এটি হ'ল আমরা sys.pathআমাদের আমদানিগুলি অর্জনের জন্য যথেষ্ট দীর্ঘ পরিবর্তন করেছি, তারপরে এটি পুনরায় রাখি ( _iযদি একটি অনুলিপি মুছে ফেলা হয় এবং কেবলমাত্র আমরা একটি অনুলিপি যোগ করি _i)।


7

তাই আরও অনেকের সাথে এই সম্পর্কে তদন্ত করার পরে, আমি এই নিবন্ধে ডোরিয়ান বি দ্বারা পোস্ট করা একটি নোট পেয়েছিলাম যা আমার যে নির্দিষ্ট সমস্যাটি ছিল সেখানেই সমাধান করেছিল যেখানে আমি একটি ওয়েব পরিষেবাদির সাহায্যে মডিউল এবং ক্লাস বিকাশ করব but আমি কোডিং হিসাবে পিসচার্মে ডিবাগার সুবিধাগুলি ব্যবহার করে সেগুলি পরীক্ষা করতে সক্ষম। একটি স্ব-অন্তর্ভুক্ত শ্রেণিতে পরীক্ষা চালানোর জন্য, আমি আমার ক্লাস ফাইলটির শেষে নিম্নলিখিতগুলি অন্তর্ভুক্ত করব:

if __name__ == '__main__':
   # run test code here...

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

# import any site-lib modules first, then...
import sys
parent_module = sys.modules['.'.join(__name__.split('.')[:-1]) or '__main__']
if __name__ == '__main__' or parent_module.__name__ == '__main__':
    from codex import Codex # these are in same folder as module under test!
    from dblogger import DbLogger
else:
    from .codex import Codex
    from .dblogger import DbLogger

যদি বিবৃতিটি পরীক্ষা করে দেখেছে যে আমরা এই মডিউলটিকে প্রধান হিসাবে চালাচ্ছি বা এটি অন্য মডিউলে ব্যবহৃত হচ্ছে যা প্রধান হিসাবে পরীক্ষিত হচ্ছে । সম্ভবত এটি সুস্পষ্ট, তবে উপরে আপেক্ষিক আমদানি সংক্রান্ত সমস্যার কারণে হতাশ অন্য কেউ যদি এটি ব্যবহার করতে পারে তবে আমি এই নোটটি এখানে প্রস্তাব করছি।


1
এটি আসলে এটি সমাধান করে। তবে এটি আসলেই বাজে। কেন এটি ডিফল্ট আচরণ নয় ?!
লো টোলমেনকে

4

এখানে একটি সমাধান রয়েছে যা আমি সুপারিশ করব না, তবে এমন কিছু পরিস্থিতিতে কার্যকর হতে পারে যেখানে মডিউলগুলি কেবল তৈরি করা হয়নি:

import os
import sys
parent_dir_name = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
sys.path.append(parent_dir_name + "/your_dir")
import your_script
your_script.a_function()

2

আমার একইরকম সমস্যা হয়েছিল যেখানে আমি পাইথন মডিউল অনুসন্ধানের পথটি পরিবর্তন করতে চাইনি এবং একটি স্ক্রিপ্ট থেকে তুলনামূলকভাবে একটি মডিউল লোড করার প্রয়োজন ছিল ( ব্রেণবার্ন উপরে বর্ণিতভাবে বর্ণনা করার সাথে সাথে "স্ক্রিপ্টগুলি সকলের সাথে সম্পর্কযুক্ত আমদানি করতে পারে না" )।

সুতরাং আমি নিম্নলিখিত হ্যাক ব্যবহার। দুর্ভাগ্যক্রমে, এটি impমডিউলটির উপর নির্ভর করে যা সংস্করণ ৩.৪ থেকে অবহেলিত হয়ে গেছে তার পক্ষে বাদ দেওয়া হয়েছে importlib। ( importlibএটিও কি সম্ভব , আমি জানি না।) তবুও, হ্যাক আপাতত কাজ করে।

সদস্যদের অ্যাক্সেস করার জন্য উদাহরণ moduleXমধ্যে subpackage1একটি স্ক্রিপ্ট বসবাসকারী থেকে subpackage2ফোল্ডার:

#!/usr/bin/env python3

import inspect
import imp
import os

def get_script_dir(follow_symlinks=True):
    """
    Return directory of code defining this very function.
    Should work from a module as well as from a script.
    """
    script_path = inspect.getabsfile(get_script_dir)
    if follow_symlinks:
        script_path = os.path.realpath(script_path)
    return os.path.dirname(script_path)

# loading the module (hack, relying on deprecated imp-module)
PARENT_PATH = os.path.dirname(get_script_dir())
(x_file, x_path, x_desc) = imp.find_module('moduleX', [PARENT_PATH+'/'+'subpackage1'])
module_x = imp.load_module('subpackage1.moduleX', x_file, x_path, x_desc)

# importing a function and a value
function = module_x.my_function
VALUE = module_x.MY_CONST

ফেডারিকো দ্বারা উল্লিখিত মডিউলগুলি লোড করার জন্য ব্যবহৃত সিএস.পথকে সংশোধন করার জন্য একটি পরিচ্ছন্ন দৃষ্টিভঙ্গি মনে হচ্ছে।

#!/usr/bin/env python3

if __name__ == '__main__' and __package__ is None:
    from os import sys, path
    # __file__ should be defined in this case
    PARENT_DIR = path.dirname(path.dirname(path.abspath(__file__)))
   sys.path.append(PARENT_DIR)
from subpackage1.moduleX import *

এটি দেখতে আরও ভাল লাগছে ... খুব খারাপ এটির জন্য আপনাকে ফাইলে মূল পিতামাতার নাম এম্বেড করা প্রয়োজন ... সম্ভবত এটি ইমপোর্টলিব দিয়ে উন্নত করা যেতে পারে। সম্ভবত আমদানি করা এমনকি সাধারণ ব্যবহারের ক্ষেত্রে আপেক্ষিক আমদানি "কেবলমাত্র কাজ" করতে বানরপ্যাচ করা যেতে পারে। আমি এটি একটি ফাটল নিতে হবে।
অ্যান্ড্রু ওয়াগনার

যদিও পাইথনটি ২.7.১৪ ব্যবহার করছি। এই মত কিছু এখনও কাজ করবে?
ব্যবহারকারী 3474042

আমি কেবল পাইথন ২.7.১০ এ উভয় পদ্ধতির পরীক্ষা করেছি এবং তারা আমার পক্ষে ভাল কাজ করেছে। যদি সত্যতা হয়, আপনি 2.7 তে অবহেলিত ইমপ মডিউলটির সমস্যা নেই, তাই আরও ভাল।
লার্স

2

__name__ পরিবর্তিত প্রশ্নাবলীর কোডটি বিশ্বব্যাপী নেমস্পেসে চালিত হয় বা আমদানীকৃত মডিউলের অংশ হিসাবে depending

কোডটি যদি গ্লোবাল স্পেসে চলমান না হয় __name__তবে মডিউলটির নাম হবে। যদি এটি বিশ্বব্যাপী নেমস্পেসে চলমান থাকে - উদাহরণস্বরূপ, আপনি যদি এটি কোনও কনসোলে টাইপ করেন, বা মডিউলটি স্ক্রিপ্ট হিসাবে চালান তবে python.exe yourscriptnamehere.pyতা __name__হয়ে যায় "__main__"

আপনি কোডালটি if __name__ == '__main__'গ্লোবাল নেমস্পেস থেকে চালিত হচ্ছে কিনা তা পরীক্ষা করতে ব্যবহৃত হয় যা দিয়ে আপনি অজগর কোডটি দেখতে পাবেন - যা আপনাকে একটি মডিউল দেয় যা স্ক্রিপ্ট হিসাবে দ্বিগুণ হয়।

আপনি কি কনসোল থেকে এই আমদানিগুলি করার চেষ্টা করেছিলেন?


আহ, তাই আপনি উল্লেখ - মি। এটি আপনার মডিউলটিকে স্ক্রিপ্ট হিসাবে সম্পাদন করতে সক্ষম করে - যদি আপনি সেখানে __name__ == '__main__' থাকে তবে আপনি দেখতে পাবেন যে এটি '__main__' - মিটার কারণে। কেবলমাত্র আপনার মডিউলটিকে অন্য মডিউলে আমদানি করার চেষ্টা করুন এটি শীর্ষ স্তর নয় ... এটি আপনাকে আপেক্ষিক আমদানি করতে দেয়
থিওডক্স

সক্রিয় ফাইলটি সঠিক মডিউল হওয়ায় আমি কনসোল থেকে এই আমদানিগুলি করার চেষ্টা করেছি।

@ স্টপফরজেটিংমাইকাউন্টস ...: "অ্যাক্টিভ ফাইল" বলতে কী বোঝ?
ব্রেনবারন

আমি সিসক্রিপ্টার ব্যবহার করি। আমি moduleX.py ছিল যখন আমি এই আমদানির দৌড়াতে .moduleY আমদানি স্প্যাম থেকে এবং থেকে। মডিউলওয়াই আমদানি করুন।

আমদানি করবেন না। ModuleY মডিউল Y.spam () এর পরে?
থিওডক্স

2

@ ব্রেনবারনের উত্তরটি সবই বলেছে, তবে আপনি যদি আমার মতো হন তবে এটি বুঝতে কিছুটা সময় নিতে পারে। এখানে আমার কেস এবং @ ব্রেইনবার্নের উত্তর এটিতে কীভাবে প্রযোজ্য তা সম্ভবত আপনাকে সহায়তা করবে।

কেস

package/
    __init__.py
    subpackage1/
        __init__.py
        moduleX.py
    moduleA.py

আমাদের পরিচিত উদাহরণটি ব্যবহার করে এবং এতে যুক্ত করুন যে মডিউলএক্স.পি.এর .. মডুলএএ সম্পর্কিত আপেক্ষিক আমদানি রয়েছে। প্রদত্ত যে আমি সাব-প্যাকেজ 1 ডিরেক্টরিতে একটি পরীক্ষার স্ক্রিপ্ট লেখার চেষ্টা করেছি যা মডিউলএক্স আমদানি করেছিলাম তবে তারপরে ওপি দ্বারা বর্ণিত ভয়ঙ্কর ত্রুটি পেয়েছি।

সমাধান

পরীক্ষার স্ক্রিপ্টটিকে প্যাকেজ এবং আমদানি প্যাকেজ হিসাবে একই স্তরে নিয়ে যান ubsubpackage1.moduleX

ব্যাখ্যা

হিসাবে ব্যাখ্যা করা হয়েছে, আপাতত আমদানি বর্তমান নামের তুলনায় করা হয়। যখন আমার পরীক্ষার স্ক্রিপ্ট একই ডিরেক্টরি থেকে মডিউলএক্স আমদানি করে, তখন মডিউলটির ভিতরে মডিউলটির নাম মডিউলএক্স হয়। এটি যখন কোনও আপেক্ষিক আমদানির মুখোমুখি হয় তখন দোভাষী প্যাকেজ শ্রেণিবিন্যাসের ব্যাকআপ নিতে পারবেন না কারণ এটি ইতিমধ্যে শীর্ষে রয়েছে

আমি যখন উপরে থেকে মডিউলএক্স আমদানি করি, তখন মডিউলএক্সের নাম প্যাকেজ.সুবপ্যাকেজ ১.মডিউলএক্স এবং আপেক্ষিক আমদানি পাওয়া যায়


আশা করছি আপনি এই সম্পর্কে আমাকে গাইড করতে পারেন। নিম্নলিখিত লিঙ্কে, আপনি কেস 3 এ যান, এটি বলে যে সমাধান 1 সম্ভব নয়। দয়া করে আপনি এটি পরীক্ষা করতে পারেন এবং আমাকে জানান। এটি আমাকে প্রচুর পরিমাণে সহায়তা করবে। chrisyeh96.github.io/2017/08/08/…
পরিবর্তনশীল

@ পরিবর্তনশীল লিঙ্কে একটি টাইপো আছে এবং আমাকে সম্পাদনা করার অনুমতি নেই। 3 কেস দেখেছেন এবং ঠিক আপনি যা পেয়েছেন তা অনুসরণ করেননি। অজগর 2-এ আমি যখন উদাহরণটি চেষ্টা করেছি তখন এমন কোনও সমস্যা হয়নি যা আমাকে মনে করে যে আমি কিছু মিস করেছি। হতে পারে আপনার একটি নতুন প্রশ্ন পোস্ট করা উচিত তবে এর একটি পরিষ্কার উদাহরণ দেওয়া দরকার। কেস 4 আমি এখানে আমার উত্তরে যা বলছি তার উপরে স্পর্শ করে: আপেক্ষিক আমদানির জন্য আপনি কোনও ডিরেক্টরিতে যেতে পারবেন না তবে অনুবাদক পিতামাতার ডিরেক্টরিতে শুরু করুন
ব্র্যাড ড্রে

ধন্যবাদ আমি অজগর 3 উল্লেখ করছি এবং এখানে প্রশ্নটি stackoverflow.com/questions/58577767/…
চলক

1

আপেক্ষিক আমদানিগুলি প্যাকেজ শ্রেণিবিন্যাসে মডিউলটির অবস্থান নির্ধারণ করতে মডিউলটির নাম বৈশিষ্ট্য ব্যবহার করে। যদি মডিউলটির নামটিতে কোনও প্যাকেজ সম্পর্কিত তথ্য না থাকে (যেমন এটি 'মেইন' তে সেট করা থাকে) তবে আপেক্ষিক আমদানিগুলি সমাধান করা হবে যেন মডিউলটি ফাইল সিস্টেমে মডিউলটি প্রকৃতপক্ষে কোথায় থাকে তা নির্বিশেষে একটি শীর্ষ স্তরের মডিউল।

পিপিআই-তে একটু অজগর প্যাকেজ লিখেছিলেন যা এই প্রশ্নের দর্শকদের সহায়তা করতে পারে। প্যাকেজটি কার্যকরভাবে কাজ করে যদি কেউ প্যাকেজ / প্রকল্পের মধ্যে থেকে সরাসরি আমদানি করা ফাইলের ডিরেক্টরিতে না হয়ে উপরের স্তরের প্যাকেজগুলি যুক্ত আমদানিকৃত পাইথন ফাইলগুলি চালাতে সক্ষম হতে চায়। https://pypi.org/project/import-anywhere/


-2

পাইথন আমার কাছে ফিরে না আসার জন্য "নন-প্যাকেজে আপেক্ষিক আমদানির চেষ্টা করা"। প্যাকেজ /

Init .py subpackage1 / Init .py moduleX.py moduleY.py subpackage2 / Init .py moduleZ.py moduleA.py

আপনি যদি প্যারেন্ট ফাইলটিতে আপেক্ষিক আমদানি প্রয়োগ করছেন তবেই এই ত্রুটি ঘটে। উদাহরণস্বরূপ পিতা বা মাতা ফাইল আগে থেকেই ফেরৎ প্রধান পরে আপনি কোড "মুদ্রণ ( নাম )" moduleA.py মধ্যে .so এই ফাইলটি আগে থেকেই প্রধানএটি আর কোনও প্যারেন্ট প্যাকেজ ফিরিয়ে দিতে পারে না। প্যাকেজ subpackage1 এবং subpackage2 এর ফাইলগুলিতে আপেক্ষিক আমদানি প্রয়োজন যা আপনি ".." ব্যবহার করতে প্যারেন্ট ডিরেক্টরি বা মডিউলটি উল্লেখ করতে পারেন ut তবে পিতামাতাই যদি ইতিমধ্যে শীর্ষ স্তরের প্যাকেজ থাকে তবে এটি প্যারেন্ট ডিরেক্টরি (প্যাকেজ) এর বেশি যেতে পারে না। এই জাতীয় ফাইল যেখানে আপনি পিতামাতার কাছে আপেক্ষিক আমদানির আবেদন করছেন কেবলমাত্র পরম আমদানির প্রয়োগের সাথেই কাজ করতে পারে। আপনি যদি প্যাকেজ প্যাকেজে অবলম্বন আমদানি ব্যবহার করেন তবে কোন ত্রুটি আসবে না কারণ পাইথন পাথের ধারণার কারণে আপনার ফাইলটি উপ-প্যাকেজে থাকলেও কে প্যাকেজের শীর্ষ স্তরে রয়েছে যিনি প্রকল্পের শীর্ষ স্তরের সংজ্ঞা দেয়?

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.