จุดประสงค์ของสวิตช์ -m คืออะไร?


174

คุณช่วยอธิบายให้ฉันฟังได้ไหมว่าความแตกต่างระหว่างการโทรเป็นอย่างไร

python -m mymod1 mymod2.py args

และ

python mymod1.py mymod2.py args

ดูเหมือนว่าในทั้งสองกรณีmymod1.pyมีการเรียกและsys.argvเป็น

['mymod1.py', 'mymod2.py', 'args']

ดังนั้นสิ่งที่เป็น-mสวิทช์หรือไม่?


โปรดแก้ไขให้ฉันถ้าฉันผิด แต่-mดูเหมือนว่าจะค้นหาmymod1ในเส้นทางห้องสมุดเริ่มต้น ตัวอย่าง: python -m SimpleHTTPServerการทำงานในขณะที่ล้มเหลวด้วยpython SimpleHTTPServer can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory
Basj

7
ฉันพบคำตอบจริงที่นี่ชัดเจนกว่า: stackoverflow.com/questions/46319694/…
Casebash

คำตอบ:


137

บรรทัดแรกของRationaleส่วนของPEP 338พูดว่า:

Python 2.4 เพิ่มสวิตช์บรรทัดคำสั่ง -m เพื่ออนุญาตให้โมดูลอยู่โดยใช้เนมสเปซโมดูล Python สำหรับการทำงานเป็นสคริปต์ ตัวอย่างที่สร้างแรงจูงใจคือโมดูลไลบรารีมาตรฐานเช่น pdb และโปรไฟล์และการใช้งาน Python 2.4 นั้นใช้ได้ดีสำหรับวัตถุประสงค์ที่ จำกัด นี้

ดังนั้นคุณสามารถระบุโมดูลใด ๆ ในเส้นทางการค้นหาของ Python ด้วยวิธีนี้ไม่ใช่แค่ไฟล์ในไดเรกทอรีปัจจุบัน คุณถูกต้องที่python mymod1.py mymod2.py argsมีผลเหมือนกันทุกประการ บรรทัดแรกของScope of this proposalสถานะส่วน:

ใน Python 2.4 โมดูลที่อยู่โดยใช้ -m จะถูกดำเนินการราวกับว่ามีการระบุชื่อไฟล์ไว้ในบรรทัดคำสั่ง

มี-mความเป็นไปได้มากขึ้นเช่นการทำงานกับโมดูลที่เป็นส่วนหนึ่งของแพ็คเกจ ฯลฯ นั่นคือสิ่งที่เหลือใน PEP 338 อ่านมันสำหรับข้อมูลเพิ่มเติม


47
การใช้งานที่ชื่นชอบของมี-m python -m SimpleHTTPServerมีประโยชน์จริงๆเมื่อฉันต้องการแชร์ไฟล์บางไฟล์โดยไม่ใช้แฟลชไดรฟ์ usb
arifwn

21
@arifwn Running Python3 ต้องการการอัพเดทเล็กน้อยpython -m http.serverและนี่ก็ยังยอดเยี่ยม!
Kit Roed

12
TL; DR: 1) คุณสามารถเรียกใช้python -m package.subpackage.moduleและเครื่องจักรที่ใช้ในการแก้ปัญหาปกติจะใช้คุณไม่ต้องชี้ให้เห็น.pyไฟล์ที่แน่นอน 2) เป็นไปได้ที่จะทำการนำเข้าแบบสัมพัทธ์จากโมดูลที่รันโดยไม่มีการแก้ไขใด ๆ เนื่องจากแพ็คเกจจะถูกโหลดไปพร้อมกัน 3) การนำเข้าแบบสัมบูรณ์จะขึ้นอยู่กับไดเรกทอรีปัจจุบันของคุณไม่ใช่ไดเรกทอรีที่เป็น.pyไฟล์ ( ''อยู่ที่ส่วนหัวsys.pathแทนที่จะเป็น/path/to/myถ้าสคริปต์อยู่ที่/path/to/my/script.py)
clacke

สิ่งที่คำตอบนี้ไม่ทำให้ชัดเจนคือมันใช้ได้เฉพาะในส่วนย่อยของโมดูลที่สามารถเรียกทำงานได้เช่นมี__main__.pyไฟล์ ส่วนใหญ่ไม่ได้และจะทำลายเช่นล้มเหลวด้วยpython -m sys 'print(sys.version)' python: No code object available for sysแนะนำให้คุณทำให้ชัดเจนในคำตอบ
smci

19

เป็นมูลค่าการกล่าวขวัญว่านี้จะทำงานเฉพาะในกรณีที่แพคเกจมีไฟล์__main__.pyมิฉะนั้นแพคเกจนี้ไม่สามารถดำเนินการได้โดยตรง

python -m some_package some_arguments

ไพ ธ อนล่ามจะค้นหา__main__.pyไฟล์ในเส้นทางแพกเกจเพื่อดำเนินการ มันเทียบเท่ากับ:

python path_to_package/__main__.py somearguments

มันจะรันเนื้อหาหลังจาก:

if __name__ == "__main__":

2
ไฟล์ init package เป็นอย่างไร ต่อหน้าไฟล์หลัก init จะถูกเรียกใช้ด้วยหรือไม่
ตัวแปร

@variable ใช่init .py จะถูกเรียกใช้ก่อนที่จะเรียกใช้main .py
Mark Rucker

1

แม้จะมีคำถามนี้ได้รับการถามและตอบหลายครั้ง (เช่นที่นี่ , ที่นี่ , ที่นี่และที่นี่ ) ในความคิดของฉันไม่มีคำตอบที่มีอยู่อย่างเต็มที่หรือรัดกุมจับความหมายทั้งหมดของ-mธง ดังนั้นสิ่งต่อไปนี้จะพยายามปรับปรุงสิ่งที่เกิดขึ้นก่อนหน้านี้

บทนำ (TLDR)

-mคำสั่งไม่มากของสิ่งที่ไม่ทั้งหมดของพวกเขาจะจำเป็นต้องมีความจำเป็นตลอดเวลา ในระยะสั้นก็คือ (1) ช่วยให้สคริปต์หลามที่จะดำเนินการผ่านทาง modulename มากกว่าชื่อไฟล์ (2) ช่วยให้หนึ่งในการเลือกไดเรกทอรีที่จะเพิ่มไปsys.pathสำหรับimportความละเอียดและ (3) ช่วยให้สคริปต์หลามกับการนำเข้าญาติที่จะดำเนินการจากบรรทัดคำสั่ง .

รอบคัดเลือกโซน

เพื่ออธิบายการ-mตั้งค่าสถานะก่อนอื่นเราต้องทำความเข้าใจคำศัพท์เล็กน้อย

ครั้งแรกที่หน่วยองค์กรหลัก Python เป็นที่รู้จักกันเป็นโมดูล โมดูลมาในหนึ่งในสองรสชาติ: โมดูลโค้ดและโมดูลแพ็กเกจ โมดูลรหัสคือไฟล์ใด ๆ ที่มีรหัสที่สามารถใช้งานได้ของไพ ธ อน โมดูลแพ็กเกจคือไดเร็กทอรีที่มีโมดูลอื่น (โมดูลโค้ดหรือโมดูลแพ็กเกจ) โมดูลโค้ดชนิดที่พบบ่อยที่สุดคือ*.pyไฟล์ในขณะที่โมดูลแพ็กเกจชนิดที่พบมากที่สุดคือไดเร็กทอรีที่มี__init__.pyไฟล์

ประการที่สองโมดูลทั้งหมดสามารถระบุได้โดยไม่ซ้ำกันในสองวิธีที่แตกต่างกันและ<modulename> <filename>โมดูลส่วนใหญ่มักถูกระบุโดย modulename ในรหัส Python (เช่น, import <modulename>) และโดยชื่อไฟล์ในบรรทัดคำสั่ง (เช่น, python <filename>) Python interpreters ทั้งหมดสามารถแปลง modulenames เป็นชื่อไฟล์ผ่านชุดของกฎที่กำหนดไว้อย่างดี กฎเหล่านี้ขึ้นกับsys.pathตัวแปรและดังนั้นการแมปสามารถเปลี่ยนแปลงได้โดยการเปลี่ยนค่านี้ (สำหรับข้อมูลเพิ่มเติมเกี่ยวกับวิธีการทำสิ่งนี้ดูPEP 302 )

ประการที่สามโมดูลทั้งหมด (ทั้งรหัสและแพ็คเกจ) สามารถดำเนินการได้ (โดยที่เราหมายถึงโค้ดที่เกี่ยวข้องกับโมดูลจะถูกประเมินโดย Python interpreter) ขึ้นอยู่กับวิธีการดำเนินการและประเภทโมดูลรหัสใดที่ได้รับการประเมินและเมื่อใดสามารถเปลี่ยนแปลงได้บ้าง ตัวอย่างเช่นถ้าหนึ่งรันโมดูลแพคเกจผ่านpython <filename>แล้วจะมีการประเมินตาม<filename>/__init__.py <filename>/__main__.pyในทางกลับกันหากมีใครเรียกใช้งานโมดูลแพ็กเกจimport <modulename>นั้นผ่านทางแพคเกจเท่านั้นที่__init__.pyจะถูกดำเนินการ

พัฒนาการทางประวัติศาสตร์ของ -m

ธง -m เป็นครั้งแรกในPython 2.4.1 เริ่มแรกมีวัตถุประสงค์เพียงอย่างเดียวคือการจัดหาวิธีการทางเลือกในการระบุโมดูลหลามเพื่อดำเนินการ นั่นคือถ้าเรารู้ทั้งใน<filename>และ<modulename>สำหรับโมดูลจากนั้นทั้งสองคำสั่งต่อไปได้เทียบเท่า: และpython <filename> <args> python -m <modulename> <args>นอกจากนี้ตามPEP 338การวนซ้ำของการ-mทำงานร่วมกับ modulenames ระดับบนสุดเท่านั้น (เช่นโมดูลที่สามารถพบได้โดยตรงบน sys.path โดยไม่ต้องมีแพ็คเกจใด ๆ )

ด้วยความสมบูรณ์ของPEP 338-mการทำงานก็ขยายไปถึงการสนับสนุน<modulename>การแสดงเกิน modulenames ระดับบนสุด ชื่อที่มีความหมายเช่นhttp.serverนี้ได้รับการสนับสนุนอย่างสมบูรณ์แล้ว การปรับปรุงนี้ยังหมายถึงตอนนี้แพ็คเกจทั้งหมดในโมดูลได้ถูกโหลดแล้ว (เช่น__init__.pyไฟล์แพคเกจทั้งหมดได้รับการประเมิน) พร้อมกับโมดูลเอง

การเพิ่มประสิทธิภาพของคุณลักษณะสุดท้ายที่สำคัญสำหรับการ-mมาพร้อมกับPEP 366 ด้วยการอัพเดทนี้-mได้รับความสามารถในการสนับสนุนไม่เพียง แต่การนำเข้าที่แน่นอน แต่ยังนำเข้าที่เกี่ยวข้องอย่างชัดเจน สิ่งนี้ทำได้โดยการแก้ไข__package__ตัวแปรสำหรับโมดูลที่ระบุชื่อใน-mคำสั่ง

ใช้เคส

มีสองกรณีการใช้ที่เด่นสำหรับแฟล็ก -m:

  1. เพื่อดำเนินการโมดูลจากบรรทัดคำสั่งที่หนึ่งอาจไม่รู้จักชื่อไฟล์ของพวกเขา กรณีการใช้งานนี้ใช้ประโยชน์จากข้อเท็จจริงที่ว่า Python interpreter รู้วิธีแปลง modulenames เป็นชื่อไฟล์ สิ่งนี้มีประโยชน์เป็นพิเศษเมื่อต้องการเรียกใช้โมดูล stdlib หรือโมดูลบุคคลที่สามจากบรรทัดคำสั่ง ตัวอย่างเช่นคนน้อยมากที่รู้ว่าชื่อไฟล์สำหรับhttp.serverโมดูล แต่คนส่วนใหญ่จะรู้ modulename python -m http.serverของตนเพื่อให้เราสามารถดำเนินการได้จากบรรทัดคำสั่งโดยใช้

  2. เพื่อรันแพ็คเกจโลคัลที่มีการอิมพอร์ตสัมบูรณ์โดยไม่จำเป็นต้องติดตั้ง กรณีการใช้งานนี้มีรายละเอียดในPEP 338และใช้ประโยชน์จากความจริงที่ว่าไดเรกทอรีการทำงานปัจจุบันถูกเพิ่มไปยังsys.pathมากกว่าไดเรกทอรีของโมดูล กรณีการใช้งานนี้คล้ายกับการใช้pip install -e .เพื่อติดตั้งแพคเกจในโหมดพัฒนา / แก้ไข

ข้อบกพร่อง

ด้วยการปรับปรุงทั้งหมดที่ทำใน-mช่วงหลายปีที่ผ่านมามันยังคงมีข้อบกพร่องที่สำคัญเพียงข้อเดียวเท่านั้น - มันสามารถเรียกใช้งานโมดูลโค้ดที่เขียนด้วยไพ ธ อนเท่านั้น ตัวอย่างเช่นหาก-mใช้เพื่อเรียกใช้งานโมดูลโค้ดที่คอมไพล์ด้วย C ข้อผิดพลาดต่อไปนี้จะเกิดขึ้นNo code object available for <modulename>(ดูรายละเอียดเพิ่มเติมที่นี่ )

การเปรียบเทียบรายละเอียด

ผลของการใช้โมดูลผ่านคำสั่ง python (เช่นpython <filename>):

  • sys.path ถูกแก้ไขเพื่อรวมไดเรกทอรีสุดท้ายใน <filename>
  • __name__ ถูกตั้งค่าเป็น '__main__'
  • __package__ ถูกตั้งค่าเป็น None
  • __init__.py ไม่ได้รับการประเมินสำหรับแพ็คเกจใด ๆ (รวมถึงของตัวเองสำหรับโมดูลแพคเกจ)
  • __main__.pyถูกประเมินสำหรับโมดูลแพ็กเกจ โค้ดจะถูกประเมินสำหรับโมดูลโค้ด

ผลของการทำงานของโมดูลผ่านข้อความสั่งการนำเข้า (เช่นimport <modulename>):

  • sys.pathจะไม่ปรับเปลี่ยนในทางใดทางหนึ่ง
  • __name__ ถูกตั้งค่าเป็นรูปแบบสัมบูรณ์ของ <modulename>
  • __package__ ถูกตั้งเป็นแพ็คเกจหลักทันที <modulename>
  • __init__.py ถูกประเมินสำหรับแพ็คเกจทั้งหมด (รวมถึงโมดูลของตัวเองสำหรับโมดูลแพ็คเกจ)
  • __main__.pyจะไม่ได้รับการประเมินสำหรับโมดูลแพคเกจ; โค้ดจะถูกประเมินสำหรับโมดูลโค้ด

ผลของการทำงานของโมดูลผ่านแฟล็ก -m (เช่น, python -m <modulename>):

  • sys.path ถูกแก้ไขเพื่อรวมไดเรกทอรีปัจจุบัน
  • __name__ ถูกตั้งค่าเป็น '__main__'
  • __package__ ถูกตั้งเป็นแพ็คเกจหลักทันที <modulename>
  • __init__.py ถูกประเมินสำหรับแพ็คเกจทั้งหมด (รวมถึงโมดูลของตัวเองสำหรับโมดูลแพ็คเกจ)
  • __main__.pyถูกประเมินสำหรับโมดูลแพ็กเกจ โค้ดจะถูกประเมินสำหรับโมดูลโค้ด

ข้อสรุป

-mธงที่ง่ายที่สุดหมายถึงการรันสคริปต์หลามจากบรรทัดคำสั่งโดยใช้ modulenames มากกว่าชื่อไฟล์ นอกจากนี้-mยังมีฟังก์ชั่นเพิ่มเติมที่รวมพลังของimportคำสั่ง (เช่นการสนับสนุนการนำเข้าที่เกี่ยวข้องอย่างชัดเจนและ__init__การประเมินแพคเกจอัตโนมัติ) ด้วยความสะดวกสบายของบรรทัดคำสั่งหลาม


คุณสามารถเพิ่มการใช้แพคเกจการเรียกใช้python -m packagenameตามที่กล่าวไว้ที่นี่: stackoverflow.com/a/53772635/1779091
ตัวแปร

@ ความคิดที่ดีที่หลากหลายฉันได้เพิ่มส่วน "ใช้กรณี" ซึ่งรวมถึงเรื่องนั้น
Mark Rucker
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.