แม้จะมีคำถามนี้ได้รับการถามและตอบหลายครั้ง (เช่นที่นี่ , ที่นี่ , ที่นี่และที่นี่ ) ในความคิดของฉันไม่มีคำตอบที่มีอยู่อย่างเต็มที่หรือรัดกุมจับความหมายทั้งหมดของ-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:
เพื่อดำเนินการโมดูลจากบรรทัดคำสั่งที่หนึ่งอาจไม่รู้จักชื่อไฟล์ของพวกเขา กรณีการใช้งานนี้ใช้ประโยชน์จากข้อเท็จจริงที่ว่า Python interpreter รู้วิธีแปลง modulenames เป็นชื่อไฟล์ สิ่งนี้มีประโยชน์เป็นพิเศษเมื่อต้องการเรียกใช้โมดูล stdlib หรือโมดูลบุคคลที่สามจากบรรทัดคำสั่ง ตัวอย่างเช่นคนน้อยมากที่รู้ว่าชื่อไฟล์สำหรับhttp.server
โมดูล แต่คนส่วนใหญ่จะรู้ modulename python -m http.server
ของตนเพื่อให้เราสามารถดำเนินการได้จากบรรทัดคำสั่งโดยใช้
เพื่อรันแพ็คเกจโลคัลที่มีการอิมพอร์ตสัมบูรณ์โดยไม่จำเป็นต้องติดตั้ง กรณีการใช้งานนี้มีรายละเอียดใน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__
การประเมินแพคเกจอัตโนมัติ) ด้วยความสะดวกสบายของบรรทัดคำสั่งหลาม
-m
ดูเหมือนว่าจะค้นหาmymod1
ในเส้นทางห้องสมุดเริ่มต้น ตัวอย่าง:python -m SimpleHTTPServer
การทำงานในขณะที่ล้มเหลวด้วยpython SimpleHTTPServer
can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory