แม้จะมีคำถามนี้ได้รับการถามและตอบหลายครั้ง (เช่นที่นี่ , ที่นี่ , ที่นี่และที่นี่ ) ในความคิดของฉันไม่มีคำตอบที่มีอยู่อย่างเต็มที่หรือรัดกุมจับความหมายทั้งหมดของ-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 SimpleHTTPServercan't open file 'SimpleHTTPServer': [Errno 2] No such file or directory