__ ভবিষ্যত___ থেকে আমদানি পরম_দর্শন আসলে কী করে?


163

আমি পাইথনের নিখুঁত আমদানি সম্পর্কিত একটি প্রশ্নের উত্তর দিয়েছি , যা আমি ভেবেছিলাম পাইথন ২.৫ চেঞ্জলগ পড়ার সাথে সাথে পিইপি সহ আমি বুঝতে পেরেছি । যাইহোক, পাইথন 2.5 ইনস্টল করার পরে এবং সঠিকভাবে ব্যবহারের উদাহরণ তৈরি করার চেষ্টা করার পরে from __future__ import absolute_importআমি বুঝতে পারি যে জিনিসগুলি এত পরিষ্কার নয় so

উপরের লিঙ্কযুক্ত চেঞ্জলগ থেকে সরাসরি, এই বিবৃতিটি পরম আমদানি পরিবর্তনের আমার বোঝার সঠিকভাবে সংক্ষিপ্তসার করেছে:

ধরা যাক আপনার এইরকম একটি প্যাকেজ ডিরেক্টরি রয়েছে:

pkg/
pkg/__init__.py
pkg/main.py
pkg/string.py

এই নামে একটি প্যাকেজ সংজ্ঞায়িত pkgধারণকারী pkg.mainএবং pkg.stringsubmodules।

মেইন.পি মডিউলটিতে কোডটি বিবেচনা করুন। যদি বিবৃতি কার্যকর করে তবে কী হবে import string? পাইথন ২.৪ এবং তার আগে, এটি প্যাকেজ ডিরেক্টরিতে প্রথমে আপেক্ষিক আমদানি সম্পাদন করবে, pkg / string.py সন্ধান করবে, pkg.stringমডিউল হিসাবে সেই ফাইলের বিষয়বস্তু আমদানি করে এবং মডিউলটি মডিউলটির নামের জায়গাতে নামের "string"সাথে আবদ্ধ pkg.main

সুতরাং আমি এই সঠিক ডিরেক্টরি কাঠামো তৈরি করেছি:

$ ls -R
.:
pkg/

./pkg:
__init__.py  main.py  string.py

__init__.pyএবং string.pyখালি। main.pyনিম্নলিখিত কোড রয়েছে:

import string
print string.ascii_uppercase

প্রত্যাশিত হিসাবে পাইথন 2.5 দিয়ে এটি চালানো ব্যর্থ হয় AttributeError:

$ python2.5 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

যাইহোক, আরও ২.৫ চেঞ্জলগের পাশাপাশি, আমরা এটি দেখতে পেয়েছি (জোর দেওয়া হয়েছে):

পাইথন 2.5 তে, আপনি importকোনও from __future__ import absolute_importনির্দেশিকা ব্যবহার করে নিখুঁত আমদানিতে আচরণের স্যুইচ করতে পারেন । এই পরম-আমদানি আচরণটি ভবিষ্যতের সংস্করণে সম্ভবত ডিফল্ট হয়ে উঠবে (সম্ভবত পাইথন ২.7)। একবার পরম আমদানি ডিফল্ট হয়ে গেলে import stringসর্বদা মানক পাঠাগারের সংস্করণটি খুঁজে পাবেন।

আমি এইভাবে তৈরি করেছি pkg/main2.py, main.pyতবে ভবিষ্যতের অতিরিক্ত আমদানির নির্দেশের সাথে একই । এটি এখন এটির মতো দেখাচ্ছে:

from __future__ import absolute_import
import string
print string.ascii_uppercase

পাইথন 2.5 দিয়ে এটি চালানো তবে ... এর সাথে ব্যর্থ হয় AttributeError:

$ python2.5 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

এই সুন্দর স্পষ্টাস্পষ্টি বিবৃতি যে contradicts import stringহবে সবসময় পরম আমদানির সক্রিয় এসটিডি-liberal এর সংক্ষিপ্ত রূপ সংস্করণ খুঁজে পেতে। আরও কি, পরম্পরায় আমদানিগুলি "নতুন ডিফল্ট" আচরণে পরিণত হওয়ার তফসিল সত্ত্বেও, আমি পাইথন ২.7 উভয়ই __future__নির্দেশের সাথে বা ছাড়াই এই একই সমস্যায় পড়েছি :

$ python2.7 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

$ python2.7 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print string.ascii_uppercase
AttributeError: 'module' object has no attribute 'ascii_uppercase'

পাশাপাশি পাইথন ৩.৫ এর সাথে বা তার বাইরেও (ধরে নিবেন printউভয় ফাইলে স্টেটমেন্টটি পরিবর্তিত হয়েছে):

$ python3.5 pkg/main.py
Traceback (most recent call last):
  File "pkg/main.py", line 2, in <module>
    print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'

$ python3.5 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 3, in <module>
    print(string.ascii_uppercase)
AttributeError: module 'string' has no attribute 'ascii_uppercase'

আমি এর অন্যান্য প্রকরণ পরীক্ষা করেছি। পরিবর্তে string.pyনামে একজন ডিরেক্টরির -, আমি একটি খালি মডিউল তৈরি করেছেন stringশুধুমাত্র একটি খালি ধারণকারী __init__.py- এবং পরিবর্তে থেকে আমদানির জারি এর main.py, আমি cd'থেকে ঘ pkgএবং REPL থেকে সরাসরি চালানো আমদানির। এই প্রকরণগুলির কোনওটিই (বা এগুলির কোনও সংমিশ্রণ) উপরের ফলাফলগুলিতে কোনও পরিবর্তন হয়নি। __future__নির্দেশিকা এবং নিখুঁত আমদানি সম্পর্কে যা পড়েছি তা দিয়ে আমি এটি পুনরায় মিলাতে পারি না ।

আমার কাছে মনে হয় এটি নিম্নলিখিত দ্বারা সহজেই স্পষ্ট হয়ে যায় (এটি পাইথন 2 ডক্সের থেকে তবে এটি পাইথন 3 এর জন্য একই ডক্সে এই বিবৃতি অপরিবর্তিত রয়েছে):

sys.path

(...)

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

তাহলে আমি কী মিস করছি? কেন __future__বিবৃতি আপাতদৃষ্টিতে না এটি যা বলে, এবং কি, ডকুমেন্টেশন এই দুই বিভাগগুলির মধ্যে এই দ্বন্দ্বের রেজল্যুশন হিসাবে ভাল হিসাবে বর্ণনা মধ্যে এবং প্রকৃত আচরণ?


আরও দেখুন: ডকস.প্যাথন.আর.
২.৫

উত্তর:


104

চেঞ্জলগটি opালু শব্দযুক্ত। from __future__ import absolute_importকিছু স্ট্যান্ডার্ড লাইব্রেরির অংশ কিনা তা নিয়ে চিন্তা করে না এবং import stringসর্বদা আপনাকে নিখুঁত আমদানি সহ স্ট্যান্ডার্ড-লাইব্রেরি মডিউল দেয় না।

from __future__ import absolute_importএর অর্থ হ'ল আপনি যদি import stringপাইথন সর্বদা একটি শীর্ষ স্তরের stringমডিউলের চেয়ে সন্ধান করেন current_package.string। যাইহোক, পাইথনটি কোন ফাইলটি stringমডিউল তা নির্ধারণ করার জন্য যে যুক্তি ব্যবহার করে তা এটি প্রভাবিত করে না । যখন তুমি কর

python pkg/script.py

pkg/script.pyপাইথনের প্যাকেজের অংশের মতো দেখাচ্ছে না। সাধারণ পদ্ধতি অনুসরণ করে pkgডিরেক্টরিটি पथটিতে যুক্ত .pyকরা হয় এবং pkgডিরেক্টরিতে সমস্ত ফাইল শীর্ষ স্তরের মডিউলগুলির মতো দেখায়। এটি কোনও আপেক্ষিক আমদানি করছে বলে import stringখুঁজে পাওয়া যায় pkg/string.pyনা, তবে pkg/string.pyএটি শীর্ষ স্তরের মডিউল হিসাবে উপস্থিত বলে মনে হয় string। এটি স্ট্যান্ডার্ড-লাইব্রেরি stringমডিউল নয় তা সত্য নয়।

pkgপ্যাকেজের অংশ হিসাবে ফাইলটি চালানোর জন্য , আপনি এটি করতে পারেন

python -m pkg.script

এই ক্ষেত্রে pkgডিরেক্টরিটি ডিরেক্টরিটিতে যুক্ত করা হবে না। যাইহোক, বর্তমান ডিরেক্টরিটি পথে যুক্ত করা হবে।

আপনি pkg/script.pyপাইথনকে pkgফাইল হিসাবে চালিত করার পরেও প্যাকেজের অংশ হিসাবে এটি করতে কিছু বয়লারপ্লেট যুক্ত করতে পারেন :

if __name__ == '__main__' and __package__ is None:
    __package__ = 'pkg'

তবে, এটি প্রভাবিত করবে না sys.pathpkgডিরেক্টরিটি ডিরেক্টরি থেকে সরানোর জন্য আপনাকে কিছু অতিরিক্ত হ্যান্ডলিংয়ের প্রয়োজন হবে এবং যদি pkgপিতামাতার ডিরেক্টরিটি পথে না থাকে তবে আপনাকেও সেই পথে চলতে হবে।


2
ঠিক আছে, মানে আমি তা পেয়েছি get আমার পোস্টটি ডকুমেন্ট করছে ঠিক এটাই আচরণ। যদিও এর মুখে দুটি প্রশ্ন: (১.) যদি "এটি ঠিক সত্য না" হয়, তবে ডকসগুলি কেন স্পষ্টতই এটি বলে? এবং, (২) তাহলে, আপনি import stringযদি দুর্ঘটনাক্রমে এটিকে ছায়া দিয়ে থাকেন তবে অন্তত রাইফেল না করে sys.modules। এটি কি from __future__ import absolute_importপ্রতিরোধের উদ্দেশ্যে এটি নয় ? এটার কাজ কি? (পিএস, আমি নিম্নগামী নয়))
টু-বিট অ্যালকেমিস্ট

14
হ্যাঁ, আমি ছিলাম ('দরকারী নয়' এর জন্য ডাউনভোট, 'ভুল' এর জন্য নয়)। এটি নীচের অংশটি থেকে স্পষ্ট হয়েছে ওপি বুঝতে পারে কীভাবে sys.pathকাজ করে এবং আসল প্রশ্নটি মোটেই সমাধান করা হয়নি। অর্থাৎ কি না from __future__ import absolute_importআসলে কি?
wim

5
@ টু-বিটএলচেমিস্ট: ১) চেঞ্জলগটি আলগাভাবে শব্দযুক্ত এবং অ-আদর্শিক। 2) আপনি এটি ছায়া গো বন্ধ করুন। এমনকি যদি আপনি নিজের শীর্ষ-স্তরের মডিউলটির সাথে ছায়া তৈরি করেন তবে রাইফেলিং sys.modulesস্ট্যান্ডার্ড-লাইব্রেরি stringমডিউলটি পাবেন না । from __future__ import absolute_importশীর্ষ-স্তরের মডিউলগুলি ছড়িয়ে দেওয়া শীর্ষ-স্তরের মডিউলগুলি থামানোর উদ্দেশ্যে নয়; এটি শীর্ষ-স্তরের মডিউলগুলি ছায়া থেকে প্যাকেজ-অভ্যন্তরীণ মডিউলগুলি বন্ধ করার কথা। আপনি যদি pkgপ্যাকেজের অংশ হিসাবে ফাইলটি চালনা করেন তবে প্যাকেজের অভ্যন্তরীণ ফাইলগুলি শীর্ষ স্তরের হিসাবে দেখা বন্ধ করবে।
ব্যবহারকারী 2357112 21

@ টু-বিটএলচেমিস্ট: উত্তর সংশোধিত হয়েছে। এই সংস্করণটি কি আরও সহায়ক?
ব্যবহারকারী 2357112

1
@ স্টোরেন: ধরে pkgনেওয়া আমদানি অনুসন্ধানের পথে একটি প্যাকেজ, এটি হওয়া উচিত python -m pkg.main-mএকটি ফাইল পাথ নয়, একটি মডিউল নাম প্রয়োজন।
ব্যবহারকারী 2357112

44

পরম এবং আপেক্ষিক আমদানির মধ্যে পার্থক্য কেবল তখনই কার্যকর হয় যখন আপনি কোনও প্যাকেজ থেকে কোনও মডিউল আমদানি করেন এবং সেই মডিউলটি সেই প্যাকেজ থেকে অন্য উপ-মডেল আমদানি করে। পার্থক্যটা দেখ:

$ mkdir pkg
$ touch pkg/__init__.py
$ touch pkg/string.py
$ echo 'import string;print(string.ascii_uppercase)' > pkg/main1.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "pkg/main1.py", line 1, in <module>
    import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
>>> 
$ echo 'from __future__ import absolute_import;import string;print(string.ascii_uppercase)' > pkg/main2.py
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> 

নির্দিষ্টভাবে:

$ python2 pkg/main2.py
Traceback (most recent call last):
  File "pkg/main2.py", line 1, in <module>
    from __future__ import absolute_import;import string;print(string.ascii_uppercase)
AttributeError: 'module' object has no attribute 'ascii_uppercase'
$ python2
Python 2.7.9 (default, Dec 13 2014, 18:02:08) [GCC] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ
>>> 
$ python2 -m pkg.main2
ABCDEFGHIJKLMNOPQRSTUVWXYZ

নোট করুন যে python2 pkg/main2.pyতারপরে আরম্ভ python2এবং তারপরে আমদানি করা pkg.main2(যা -mস্যুইচ ব্যবহারের সমতুল্য ) এর একটি আলাদা আচরণ রয়েছে ।

আপনি যদি কখনও কোনও প্যাকেজের সাবমডিউল চালাতে চান তবে সর্বদা -mস্যুইচটি ব্যবহার করুন যা sys.pathতালিকায় শৃঙ্খলার জন্য দোভাষীকে বাধা দেয় এবং সাবমোডলের শব্দার্থকে সঠিকভাবে পরিচালনা করে।

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


সুতরাং মূলত এটি কেবল একটি সংকীর্ণ ক্ষেত্রে কাজ করে যেখানে আপনি "বর্তমান ডিরেক্টরি" সমস্যাটি এড়িয়ে গেছেন? এটি পিইপি 328 এবং 2.5 এর পরিবর্তনের দ্বারা বর্ণিত তুলনায় অনেক দুর্বল বাস্তবায়ন বলে মনে হচ্ছে। আপনি কি ডকুমেন্টেশনটি ভুল বলে বিশ্বাস করেন?
টু-বিট অ্যালকেমিস্ট

@ টু-বিটএলচেমিস্ট আসলে আপনি যা করছেন তা হ'ল "সরু কেস"। মৃত্যুদন্ড কার্যকর করার জন্য আপনি কেবলমাত্র একটি অজগর ফাইল চালু করেন, তবে এটি কয়েকশো আমদানিকে ট্রিগার করতে পারে। কোনও প্যাকেজের সাবমডিউলগুলি কেবল কার্যকর করা উচিত নয়, এগুলিই।
বাকুরিউ

python2 pkg/main2.pyপাইথন 2 আরম্ভ করে এবং তারপরে pkg.main2 আমদানি করার কেন আলাদা আচরণ রয়েছে?
storen

1
@ স্টোরেন কারণ এটি আপেক্ষিক আমদানির সাথে আচরণ পরিবর্তন হয়। আপনি pkg/main2.pyঅজগর চালু করার সময় (সংস্করণ 2) প্যাকেজ হিসাবে বিবেচনা করবেন নাpkg । ব্যবহার করার সময় python2 -m pkg.main2বা আমদানি এটা কি যে অ্যাকাউন্টটি নিতে pkgএকটি প্যাকেজ।
বাকুরিউ
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.