পাইথন কোডটি এম-এর বিকল্পের সাথে কার্যকর করা যায় না


111

পাইথন ইন্টারপ্রেটার হয়েছে -m মডিউল বিকল্প যে "গ্রন্থাগার মডিউল চালায় মডিউল একটি স্ক্রিপ্ট হিসাবে"।

এই পাইথন কোডটি দিয়ে a.py:

if __name__ == "__main__":
    print __package__
    print __name__

আমি python -m aপেতে পরীক্ষা

"" <-- Empty String
__main__

যেখানে python a.pyরিটার্ন

None <-- None
__main__

আমার কাছে, এই দুটি অনুরোধটি __package__ ব্যতীত একই বলে মনে হচ্ছে যখন -m বিকল্পের সাথে আহ্বান করা হয়।

মজার বিষয় হল, এর সাথে python -m runpy aআমি পাই python -m aপাইথন পাওয়ার জন্য পাইথন মডিউলের সাথে একইভাবে পেলাম

এই আমন্ত্রণগুলির মধ্যে (ব্যবহারিক) পার্থক্য কী? তাদের মধ্যে কোন মতামত আছে?

এছাড়াও, ডেভিড বেজলির পাইথন এসেনসিয়াল রেফারেন্সটি এটিকে ব্যাখ্যা করেছে "" -m বিকল্পটি একটি স্ক্রিপ্ট হিসাবে একটি লাইব্রেরি মডিউল চালায় যা মূল স্ক্রিপ্টটি কার্যকর করার আগে __main__ মডিউলের অভ্যন্তরে সঞ্চালিত হয় "। এর মানে কী?

উত্তর:


169

আপনি যখন -mকমান্ড-লাইন পতাকা ব্যবহার করবেন , পাইথন আপনার জন্য একটি মডিউল বা প্যাকেজ আমদানি করবে, তারপরে এটিকে স্ক্রিপ্ট হিসাবে চালাবে। আপনি যখন -mপতাকা ব্যবহার করবেন না , আপনার নাম করা ফাইলটি কেবল একটি স্ক্রিপ্ট হিসাবে চালিত হবে ।

আপনি যখন প্যাকেজ চালানোর চেষ্টা করবেন তখন পার্থক্যটি গুরুত্বপূর্ণ। এর মধ্যে একটি বড় পার্থক্য রয়েছে:

python foo/bar/baz.py

এবং

python -m foo.bar.baz

পরবর্তী ক্ষেত্রে যেমনটি foo.barআমদানি করা হয় এবং আপেক্ষিক আমদানিগুলি foo.barসূচনা পয়েন্ট হিসাবে সঠিকভাবে কাজ করবে ।

ডেমো:

$ mkdir -p test/foo/bar
$ touch test/foo/__init__.py
$ touch test/foo/bar/__init__.py
$ cat << EOF > test/foo/bar/baz.py 
> if __name__ == "__main__":
>     print __package__
>     print __name__
> 
> EOF
$ PYTHONPATH=test python test/foo/bar/baz.py 
None
__main__
$ PYTHONPATH=test python -m foo.bar.baz 
foo.bar
__main__

ফলস্বরূপ, পাইথনকে -mস্যুইচটি ব্যবহার করার সময় প্যাকেজগুলির বিষয়ে আসলে যত্ন নেওয়া উচিত । একটি সাধারণ স্ক্রিপ্ট কখনও প্যাকেজ হতে পারে না , তাই __package__সেট করা আছে None

কিন্তু একটি প্যাকেজ বা মডিউল চালানোর ভিতরে সঙ্গে একটি প্যাকেজ -mএবং এখন সেখানে অন্তত হয় সম্ভাবনা , একটি প্যাকেজের তাই __package__পরিবর্তনশীল স্ট্রিং মান সেট করা হয়; উপরের প্রদর্শনীতে এটি সেট করা হয়েছে foo.bar, প্যাকেজের অভ্যন্তরে নয় এমন সরল মডিউলগুলির জন্য, এটি একটি খালি স্ট্রিংয়ে সেট করা আছে।

__main__ মডিউল হিসাবে ; পাইথন স্ক্রিপ্টগুলি নিয়মিত মডিউল হিসাবে চালিত হয় তা আমদানি করে। একটি নতুন মডিউল বস্তু বিশ্বব্যাপী নামস্থান, সঞ্চিত রাখা তৈরি করা হয় sys.modules['__main__']। এটি __name__ভেরিয়েবলকে বোঝায় এটি সে কাঠামোর মূল কী।

প্যাকেজগুলির জন্য, আপনি একটি __main__.pyমডিউল তৈরি করতে পারেন এবং চলমান অবস্থায় চালিত করতে পারেন python -m package_name; আসলে একমাত্র উপায় আপনি যে পারেন একটি স্ক্রিপ্ট হিসাবে একটি প্যাকেজ সঞ্চালন করুন:

$ PYTHONPATH=test python -m foo.bar
python: No module named foo.bar.__main__; 'foo.bar' is a package and cannot be directly executed
$ cp test/foo/bar/baz.py test/foo/bar/__main__.py
$ PYTHONPATH=test python -m foo.bar
foo.bar
__main__

সুতরাং, যখন প্যাকেজটির সাথে চলার জন্য নামকরণ করা -mহচ্ছে, পাইথন __main__সেই প্যাকেজে থাকা মডিউলটি সন্ধান করে এবং এটি স্ক্রিপ্ট হিসাবে কার্যকর করে। এটির নামটি এখনও সেট করা আছে __main__এবং মডিউল অবজেক্টটি এখনও এতে সঞ্চিত আছে sys.modules['__main__']


1
কমান্ড PYTHONPATH=test python -m foo.barবলতে আসলে কী বোঝায়? দয়া করে আপনি এটি বিশদভাবে ব্যাখ্যা করতে পারেন?
Andriy

3
@ অ্যান্ড্রি: PYTHONPATHএকটি পরিবেশের পরিবর্তনশীল সেট করে; এটি ডিরেক্টরিগুলির সিরিজটি প্রসারিত করে যেখানে পাইথন আমদানি করার সময় মডিউলগুলির সন্ধান করবে; এখানে এটি testসেই সিরিজে ডিরেক্টরি যুক্ত করে । এটি একই কমান্ড লাইনে রেখে, এটি কেবলমাত্র একক pythonকমান্ডের জন্য প্রযোজ্য । -mপাইথনকে একটি নির্দিষ্ট মডিউল আমদানি করতে বলে, যেন আপনি দৌড়ে এসেছেন import foo.bar। তবে, __main__আপনি যখন এই স্যুইচটি ব্যবহার করবেন তখন পাইথন স্বয়ংক্রিয়ভাবে স্ক্রিপ্ট হিসাবে প্যাকেজের ভিতরে একটি মডিউল চালাবে ।
মার্টিজন পিটারস

1
having to use -m always is not that user-.friendly.আমি মনে করি মিক্স ব্যবহার করা এবং ব্যবহার না -mকরা কম ব্যবহারকারী বান্ধব।
সিমিন জি

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

1
@ ফ্লো টু: আমি বলতে চাইছি from Photos import ...অভিযোগ করবে। তাই হবে import Photos.<something>import Photosপাইথন কেবলমাত্র স্পেস প্যাকেজগুলিকে সমর্থন করে কারণ (যেখানে দুটি পৃথক বিতরণ সরবরাহ করা হয় Photos.fooএবং Photos.barপৃথকভাবে পৃথকভাবে পরিচালিত হয়) only
মার্টিজন পিটারস

25

পাইথন কোডটি এম-এর বিকল্পের সাথে কার্যকর করা যায় না

-mপতাকা ব্যবহার করুন ।

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

ডকস

-ম পতাকাটিতে থাকা দস্তাবেজের মতো বলুন:

নামযুক্ত মডিউলটির জন্য sys.path অনুসন্ধান করুন এবং মডিউল হিসাবে এর বিষয়বস্তুগুলি কার্যকর করুন __main__

এবং

-C বিকল্পের মতো, বর্তমান ডিরেক্টরিটি sys.path শুরুতে যুক্ত করা হবে।

সুতরাং

python -m pdb

মোটামুটি সমান

python /usr/lib/python3.5/pdb.py

(ধরে নিলাম আপনার বর্তমান ডিরেক্টরিতে পিডিবি.পি নামে একটি প্যাকেজ বা স্ক্রিপ্ট নেই)

ব্যাখ্যা:

আচরণটি "ইচ্ছাকৃতভাবে" স্ক্রিপ্টগুলির অনুরূপ করা হয়।

অনেক স্ট্যান্ডার্ড লাইব্রেরি মডিউলগুলিতে কোড থাকে যা তাদের স্ক্রিপ্ট হিসাবে কার্যকর করার জন্য অনুরোধ করা হয়। একটি উদাহরণ হ'ল সময়কালীন মডিউল:

কিছু অজগর কোড মডিউল হিসাবে চালানোর উদ্দেশ্যে করা হয়েছে : (আমি মনে করি এই উদাহরণটি কমান্ডলাইন বিকল্প ডক উদাহরণের চেয়ে ভাল)

$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 33.4 usec per loop
$ python -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 25.2 usec per loop

পাইথন ২.৪-এর জন্য প্রকাশিত নোটের হাইলাইটগুলি থেকে :

-M কমান্ড লাইন বিকল্পটি - পাইথন-এম মডিউল নাম স্ট্যান্ডার্ড লাইব্রেরিতে একটি মডিউল খুঁজে পেতে পারে এবং এটিতে অনুরোধ জানায়। উদাহরণস্বরূপ, python -m pdb সমানpython /usr/lib/python2.4/pdb.py

ফলো-আপ প্রশ্ন

এছাড়াও, ডেভিড বেজলির পাইথন এসেনশিয়াল রেফারেন্সটি এটিকে ব্যাখ্যা করেছে কারণ "The -m অপশনটি একটি স্ক্রিপ্ট হিসাবে একটি লাইব্রেরি মডিউল চালায় যা __main__মূল স্ক্রিপ্টটি কার্যকর করার আগে মডিউলের ভিতরে সঞ্চালিত হয় "।

এর মানে কোন মডিউল আপনাকে একটি আমদানি বক্তব্যের সঙ্গে অনুসন্ধান করতে পারেন প্রোগ্রামের এন্ট্রি পয়েন্ট হিসাবে চালানো যাবে - যদি এটা একটি কোড ব্লক হয়েছে সাধারণত শেষ কাছাকাছি, সঙ্গে if __name__ == '__main__':

-m পথে বর্তমান ডিরেক্টরিটি যুক্ত না করে:

এখানে অন্যত্র একটি মন্তব্য বলেছেন:

যে -m বিকল্পটি বর্তমান ডিরেক্টরিটিকে sys.path এ যুক্ত করে, এটি অবশ্যই একটি সুরক্ষা সমস্যা (দেখুন: প্রিলোড আক্রমণ) attack এই আচরণটি উইন্ডোজে লাইব্রেরি অনুসন্ধানের ক্রমের অনুরূপ (এটি সম্প্রতি কঠোর করার আগে)। এটি অত্যন্ত দুঃখের বিষয় যে পাইথন ট্রেন্ডটি অনুসরণ করে না এবং যোগ করা অক্ষম করার সহজ উপায় সরবরাহ করে না। to sys.path

ঠিক আছে, এটি সম্ভাব্য সমস্যাটি দেখায় - (উইন্ডোতে উদ্ধৃতিগুলি সরান):

echo "import sys; print(sys.version)" > pdb.py

python -m pdb
3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul  5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)]

-Iউত্পাদন পরিবেশের জন্য এটি লক করতে পতাকাটি ব্যবহার করুন (সংস্করণ 3.4 এ নতুন):

python -Im pdb
usage: pdb.py [-c command] ... pyfile [arg] ...
etc...

ডক্স থেকে :

-I

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

কি করে __package__?

এটি এই প্রশ্নের বিশেষত জার্মানি নয়, সুস্পষ্ট আপেক্ষিক আমদানি সক্ষম করে - যদিও এই উত্তরটি এখানে দেখুন: পাইথনের "__package__" বৈশিষ্ট্যের উদ্দেশ্য কী?


-M সুইচ ব্যবহৃত হয় যখন sys.path এ কোন পাথ যুক্ত হয়?
ভেরিয়েবল

আমি ইতিমধ্যে উদ্ধৃত করেছি, "-c বিকল্প হিসাবে, বর্তমান ডিরেক্টরিটি sys.path শুরুতে যুক্ত করা হবে।" তবে আমি স্পষ্ট করে দিয়েছি যে উদ্ধৃতিটি কী বোঝায়।
অ্যারন হল

আমি এর অর্থ - ধরুন ডি: \ পরীক্ষা ডিরেক্টরিতে, আমি কমান্ডটি চালাচ্ছি - পাইথন-এম foo.bar.boo তাহলে এটি কি পাইথন ইনস্টলেশন ফোল্ডারটি বা সি: সিটিপথের সাথে ডি: \ পরীক্ষার ডিরেক্টরি যুক্ত করবে? আমার বোধগম্যতা হ'ল এটি d: ys sys.path এ পরীক্ষা করবে, foo.bar আমদানি করবে এবং বু স্ক্রিপ্টটি চালাবে
চলক

@ পরিবর্তনশীল - হ্যাঁ, চেষ্টা করুন
হারুন হলের

1

-M সহ একটি স্ক্রিপ্ট হিসাবে মডিউল (বা প্যাকেজ) চালানোর মূল কারণ হ'ল বিশেষত উইন্ডোজে স্থাপনাকে সহজ করা। আপনি পাইথন লাইব্রেরিতে একই জায়গায় স্ক্রিপ্টগুলি ইনস্টল করতে পারেন যেখানে মডিউলগুলি সাধারণত যায় - PATH বা ~ / .local এর মতো গ্লোবাল এক্সিকিউটেবল ডিরেক্টরিগুলিকে দূষিত না করে (প্রতি ব্যবহারকারী স্ক্রিপ্ট ডিরেক্টরিটি উইন্ডোতে সন্ধান করা হাস্যকরভাবে শক্ত)।

তারপরে আপনি কেবল -m টাইপ করেন এবং পাইথন স্ক্রিপ্টটি স্বয়ংক্রিয়ভাবে আবিষ্কার করেন। উদাহরণস্বরূপ, python -m pipযার ফলে এটি executes পাইথন ইন্টারপ্রেটার একই উদাহরণস্বরূপ সঠিক পিপ পাবেন। -এম ব্যতীত যদি ব্যবহারকারীর বেশ কয়েকটি পাইথন সংস্করণ ইনস্টল থাকে তবে কোনটি "গ্লোবাল" পিপ হবে?

ব্যবহারকারী যদি কমান্ড-লাইন স্ক্রিপ্টগুলির জন্য "ক্লাসিক" এন্ট্রি পয়েন্টগুলি পছন্দ করেন তবে এগুলি সহজেই PATH এর কোথাও ছোট স্ক্রিপ্ট হিসাবে যুক্ত করা যেতে পারে, বা পাইপ সেটআপ.পিতে এন্ট্রি_পয়েন্টগুলির সাথে ইনস্টল করার সময় এগুলি তৈরি করতে পারে।

সুতরাং কেবল __name__ == '__main__'অন্যান্য অবিশ্বাস্য প্রয়োগের বিশদটি যাচাই করুন এবং উপেক্ষা করুন।


যে -m বিকল্পটি বর্তমান ডিরেক্টরিটিকে sys.path এ যুক্ত করে, এটি অবশ্যই একটি সুরক্ষা সমস্যা (দেখুন: প্রিলোড আক্রমণ ) attack এই আচরণটি উইন্ডোজে লাইব্রেরি অনুসন্ধানের ক্রমের অনুরূপ (এটি সম্প্রতি কঠোর করার আগে)। এটি অত্যন্ত দুঃখের বিষয় যে পাইথন ট্রেন্ডটি অনুসরণ করে না এবং যোগ করা অক্ষম করার সহজ উপায় সরবরাহ করে না। to sys.path।
ddbug
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.