-M विकल्प या नहीं के साथ पायथन कोड का निष्पादन


111

अजगर दुभाषिया में -m मॉड्यूल विकल्प होता है कि "लाइब्रेरी मॉड्यूल को स्क्रिप्ट के रूप में चलाता है "।

इस अजगर कोड के साथ:

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 aa.pyc प्राप्त करने के लिए संकलित अजगर मॉड्यूल के साथ ही मिलता हूं।

इन मंगलाचरणों में क्या (व्यावहारिक) अंतर है? उनके बीच कोई पेशेवरों और विपक्ष?

इसके अलावा, डेविड बेज़ले के पाइथन आवश्यक संदर्भ के रूप में बताते हैं कि " -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मतलब है? क्या आप इसे विस्तार से बता सकते हैं, कृपया
एंड्री

3
@ भारत: PYTHONPATHएक पर्यावरण चर सेट करता है; यह उन निर्देशिकाओं की श्रृंखला का विस्तार करता है जहां पायथन आयात करते समय मॉड्यूल की तलाश करेगा; यहाँ यह जोड़ता हैtest उस श्रृंखला निर्देशिका को । इसे एक ही कमांड लाइन पर रखकर, यह केवल उस सिंगल pythonकमांड पर लागू होता है । -mपायथन को एक विशिष्ट मॉड्यूल आयात करने के लिए कहता है, जैसे कि आप भाग गए import foo.bar। हालाँकि, पायथन स्वचालित __main__रूप से एक पैकेज के अंदर एक मॉड्यूल को स्क्रिप्ट के रूप में चलाएगा जब आप उस स्विच का उपयोग करेंगे।
मार्टिन पीटर्स

1
having to use -m always is not that user-.friendly.मुझे लगता है कि मिश्रण का उपयोग करना और उपयोग नहीं करना -mकम उपयोगकर्ता के अनुकूल है।
सिमिन जी

1
@SiminJie: स्क्रिप्ट किसी भी मनमाने तरीके से खोली जा सकती हैं और फिर उनकी मूल निर्देशिका को मॉड्यूल खोज पथ में जोड़ा जाता है। -mकेवल वर्तमान निर्देशिका या निर्देशिका के लिए काम करता है जो पहले से ही खोज पथ पर पंजीकृत है। वह मेरी बात थी। -mकुछ ऐसा नहीं है जिसे आप एंड-यूजर्स को देते हैं जो कि बहुत ही प्रयोज्य समस्या है।
मार्टिन पीटर्स

1
@ flow2k: मेरा मतलब है कि from Photos import ...शिकायत करेंगे। तो होगा import Photos.<something>import Photosकेवल इसलिए काम करता है क्योंकि पायथन नामांकित पैकेजों का समर्थन करता है (जहां दो अलग-अलग वितरण प्रदान करते हैं Photos.fooऔर Photos.barअलग-अलग होते हैं और उन्हें स्वतंत्र रूप से प्रबंधित किया जा सकता है)।
मार्टिन पीटर्स

25

-M विकल्प या नहीं के साथ पायथन कोड का निष्पादन

-mझंडे का इस्तेमाल करें ।

जब आपके पास स्क्रिप्ट होती है, तो परिणाम बहुत अधिक होते हैं, लेकिन जब आप -mझंडे के बिना एक पैकेज विकसित करते हैं , तो आयात करने के लिए सही तरीके से काम करने का कोई तरीका नहीं है यदि आप मुख्य प्रविष्टि के रूप में पैकेज में एक सबपैकेज या मॉड्यूल चलाना चाहते हैं अपने कार्यक्रम को इंगित करें (और मुझ पर विश्वास करें, मैंने कोशिश की है।)

डॉक्स

जैसे डॉल्स-एम ध्वज पर कहते हैं:

नामित मॉड्यूल के लिए sys.path खोजें और मॉड्यूल के रूप में इसकी सामग्री को निष्पादित करें __main__

तथा

-C विकल्प के रूप में, वर्तमान निर्देशिका को sys.path की शुरुआत में जोड़ा जाएगा।

इसलिए

python -m pdb

के बराबर है

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

(मान लें कि आपके पास अपनी वर्तमान निर्देशिका में कोई पैकेज या स्क्रिप्ट नहीं है जिसे pdb.py कहा जाता है)

स्पष्टीकरण:

व्यवहार "लिपियों के समान" जानबूझकर किया जाता है।

कई मानक लाइब्रेरी मॉड्यूल में कोड होते हैं जो स्क्रिप्ट के रूप में उनके निष्पादन पर लगाए जाते हैं। एक उदाहरण टाइमिट मॉड्यूल है:

कुछ अजगर कोड को एक मॉड्यूल के रूप में चलाने का इरादा है : (मुझे लगता है कि यह उदाहरण कमांडलाइन विकल्प doc उदाहरण से बेहतर है)

$ 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

और पायथन 2.4 के रिलीज़ नोट पर प्रकाश डाला गया :

एम-कमांड लाइन विकल्प - पायथन-एम मोडुलनेम मानक पुस्तकालय में एक मॉड्यूल मिलेगा, और इसे लागू करेगा। उदाहरण के लिए, python -m pdb के बराबर हैpython /usr/lib/python2.4/pdb.py

अनुवर्ती सवाल

इसके अलावा, डेविड बेज़ले के पाइथन आवश्यक संदर्भ इसे "एम-विकल्प एक स्क्रिप्ट के रूप में एक लाइब्रेरी मॉड्यूल चलाता है जो __main__मुख्य स्क्रिप्ट के निष्पादन से पहले मॉड्यूल के अंदर निष्पादित करता है" के रूप में बताता है ।

इसका मतलब है कि कोई भी मॉड्यूल जिसे आप आयात विवरण के साथ देख सकते हैं, उसे कार्यक्रम के प्रवेश बिंदु के रूप में चलाया जा सकता है - यदि इसमें एक कोड ब्लॉक है, आमतौर पर अंत के पास, साथ if __name__ == '__main__':

-m वर्तमान निर्देशिका को पथ में जोड़े बिना:

अन्यत्र यहाँ एक टिप्पणी कहती है:

वह -m विकल्प वर्तमान निर्देशिका को sys.path में भी जोड़ता है, स्पष्ट रूप से एक सुरक्षा समस्या है (देखें: प्रीलोड हमला)। यह व्यवहार विंडोज में लाइब्रेरी सर्च ऑर्डर के समान है (इससे पहले हाल ही में इसे सख्त किया गया था)। यह अफ़सोस की बात है कि पायथन प्रवृत्ति का पालन नहीं करता है और जोड़ने को अक्षम करने का एक सरल तरीका प्रदान नहीं करता है। 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

पायथन को पृथक मोड में चलाएं। इसका तात्पर्य -E और -s भी है। पृथक मोड में sys.path में न तो स्क्रिप्ट की निर्देशिका होती है और न ही उपयोगकर्ता की साइट-संकुल निर्देशिका होती है। सभी PYTHON * पर्यावरण चर को भी नजरअंदाज कर दिया जाता है। उपयोगकर्ता को दुर्भावनापूर्ण कोड इंजेक्ट करने से रोकने के लिए आगे प्रतिबंध लगाए जा सकते हैं।

क्या करता __package__है?

यह स्पष्ट रूप से सापेक्ष आयात को सक्षम करता है, विशेष रूप से इस सवाल को नहीं, हालांकि - इस उत्तर को यहां देखें: पायथन में "__package__" विशेषता का उद्देश्य क्या है?


-M स्विच का उपयोग करने पर किस पथ को sys.path में जोड़ा जाता है?
चर

मैंने पहले ही उद्धृत किया है, "जैसा कि -c विकल्प के साथ, वर्तमान निर्देशिका को sys.path की शुरुआत में जोड़ा जाएगा।" लेकिन मैंने स्पष्ट किया है कि बोली का क्या मतलब है।
हारून हॉल

मेरा मतलब है कि - D: \ test निर्देशिका में मान लीजिए, मैं कमांड चलाता हूं - python -m foo.bar.boo तो क्या यह python अधिष्ठापन फ़ोल्डर या D: \ test निर्देशिका को sys.path में जोड़ देगा? मेरी समझ यह है कि यह d: \ test को sys.path, आयात foo.bar में जोड़ेगा और बू स्क्रिप्ट चलाएगा
चर

@ मूल्य - हाँ, यह कोशिश करो।
हारून हॉल

1

-म के साथ स्क्रिप्ट के रूप में मॉड्यूल (या पैकेज) को चलाने का मुख्य कारण तैनाती को आसान बनाना है, खासकर विंडोज पर। आप पायथन लाइब्रेरी में उसी स्थान पर स्क्रिप्ट स्थापित कर सकते हैं जहां मॉड्यूल आमतौर पर जाते हैं - PATH या वैश्विक निष्पादन योग्य निर्देशिकाओं जैसे कि ~ / .local (प्रति-उपयोगकर्ता स्क्रिप्ट निर्देशिका को विंडोज में खोजना हास्यास्पद है)।

तब आप बस टाइप करते हैं -m और Python स्क्रिप्ट को ऑटोमैटिकली ढूंढ लेते हैं। उदाहरण के लिए,python -m pip पायथन इंटरप्रेटर के उसी उदाहरण के लिए सही पाइप मिलेगा जो इसे निष्पादित करता है। बिना -m, यदि उपयोगकर्ता के कई पायथन संस्करण स्थापित हैं, तो कौन सा "ग्लोबल" पाइप होगा?

यदि उपयोगकर्ता कमांड-लाइन स्क्रिप्ट के लिए "क्लासिक" प्रवेश बिंदु पसंद करते हैं, तो उन्हें आसानी से PATH में कहीं भी छोटी स्क्रिप्ट के रूप में जोड़ा जा सकता है, या इनको सेटअप करने के लिए इनस्टॉल_टाइम पैरामीटर के साथ setup.py में स्थापित किया जा सकता है।

इसलिए __name__ == '__main__'अन्य गैर-विश्वसनीय कार्यान्वयन विवरणों को देखें और अनदेखा करें।


वह -m विकल्प वर्तमान निर्देशिका को sys.path में भी जोड़ता है, स्पष्ट रूप से एक सुरक्षा समस्या है (देखें: प्रीलोड हमला )। यह व्यवहार विंडोज में लाइब्रेरी सर्च ऑर्डर के समान है (इससे पहले हाल ही में इसे सख्त किया गया था)। यह अफ़सोस की बात है कि पायथन प्रवृत्ति का पालन नहीं करता है और जोड़ने को अक्षम करने का एक सरल तरीका प्रदान नहीं करता है। to sys.path
ddbug
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.