Apa tujuan dari saklar -m?

174

Bisakah Anda menjelaskan kepada saya apa perbedaan antara menelepon

python -m mymod1 mymod2.py args

dan

python mymod1.py mymod2.py args

Tampaknya dalam kedua kasus mymod1.pydisebut dan sys.argvmerupakan

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

Jadi untuk apa -msaklar itu?

Charles Brunet
sumber
Harap perbaiki saya jika saya salah, tetapi -mtampaknya mencari mymod1di jalur pustaka default. Contoh: python -m SimpleHTTPServerberfungsi, sedangkan python SimpleHTTPServergagal dengan can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory.
Basj
7
Saya benar-benar menemukan jawabannya di sini lebih jelas: stackoverflow.com/questions/46319694/…
Casebash

Jawaban:

137

Baris pertama dari Rationalebagian PEP 338 mengatakan:

Python 2.4 menambahkan saklar baris perintah -m untuk memungkinkan modul ditempatkan menggunakan namespace modul Python untuk dieksekusi sebagai skrip. Contoh yang memotivasi adalah modul perpustakaan standar seperti pdb dan profil, dan implementasi Python 2.4 baik untuk tujuan terbatas ini.

Jadi Anda dapat menentukan modul apa pun di jalur pencarian Python dengan cara ini, bukan hanya file di direktori saat ini. Anda benar yang python mymod1.py mymod2.py argsmemiliki efek yang persis sama. Baris pertama Scope of this proposalmenyatakan bagian:

Dalam Python 2.4, modul yang terletak menggunakan -m dijalankan seolah-olah nama filenya telah disediakan pada baris perintah.

Dengan -mlebih banyak dimungkinkan, seperti bekerja dengan modul yang merupakan bagian dari paket, dll. Itulah inti dari PEP 338. Baca untuk info lebih lanjut.

agf
sumber
47
Penggunaan favorit saya -madalah python -m SimpleHTTPServer. Sangat praktis ketika saya perlu berbagi beberapa file tanpa menggunakan usb flash drive.
arifwn
21
@arifwn Menjalankan Python3 memerlukan sedikit pembaruan karena python -m http.serverdan ini masih mengagumkan!
Kit Roed
12
TL; DR: 1) Anda dapat menjalankan python -m package.subpackage.moduledan mesin penyelesaian normal akan digunakan, Anda tidak perlu menunjukkan .pyfile yang tepat . 2) Dimungkinkan untuk melakukan impor relatif dari modul yang dijalankan, tanpa penyelesaian, karena paketnya akan dimuat di sepanjang jalan. 3) Impor absolut akan didasarkan pada direktori Anda saat ini, bukan direktori tempat .pyfile berada ( ''berada di kepala sys.path, bukan /path/to/my, jika skrip berada di /path/to/my/script.py).
clacke
Apa jawaban ini tidak membuatnya jelas adalah ini hanya bekerja pada subset dari modul yang dapat dieksekusi yaitu memiliki __main__.pyfile. Sebagian besar tidak dan akan rusak misalnya python -m sys 'print(sys.version)'gagal python: No code object available for sys. Sarankan Anda menjelaskannya dalam jawaban.
smci
19

Layak disebutkan ini hanya berfungsi jika paket memiliki file.__main__.py Jika tidak, paket ini tidak dapat dieksekusi secara langsung.

python -m some_package some_arguments

Penerjemah python akan mencari __main__.pyfile di jalur paket untuk dieksekusi. Ini setara dengan:

python path_to_package/__main__.py somearguments

Ini akan mengeksekusi konten setelah:

if __name__ == "__main__":
Marquez.Z
sumber
2
Bagaimana dengan file init paket? Di hadapan file utama, apakah init juga akan dipanggil?
variabel
@variable Ya init .py akan dipanggil sebelum .py utama dipanggil
Mark Rucker
1

Meskipun pertanyaan ini telah ditanyakan dan dijawab beberapa kali (misalnya, di sini , di sini , di sini , dan di sini ) menurut pendapat saya tidak ada jawaban yang ada sepenuhnya atau secara ringkas menangkap semua implikasi dari -mbendera. Oleh karena itu, berikut ini akan berusaha untuk memperbaiki apa yang telah terjadi sebelumnya.

Pengantar (TLDR)

The -mperintah melakukan banyak hal tidak semua dari mereka akan selalu dibutuhkan setiap saat. Singkatnya: (1) memungkinkan skrip python dieksekusi melalui modulename daripada filename (2) memungkinkan seseorang untuk memilih direktori untuk ditambahkan ke sys.pathuntukimport resolusi dan (3) memungkinkan script python dengan impor relatif akan dieksekusi dari baris perintah .

Persiapan

Untuk menjelaskan -mbendera, pertama-tama kita harus memperjelas terminologi kecil.

Pertama, unit organisasi utama Python dikenal sebagai modul . Modul datang dalam salah satu dari dua rasa: modul kode dan modul paket. Modul kode adalah file apa pun yang berisi kode yang dapat dieksekusi python. Modul paket adalah direktori yang berisi modul lain (baik modul kode atau modul paket). Jenis modul kode yang *.pypaling umum adalah file sedangkan jenis modul paket yang paling umum adalah direktori yang berisi__init__.py file.

Kedua, semua modul dapat diidentifikasi secara unik dalam dua cara berbeda: <modulename>dan <filename>. Modul paling sering diidentifikasi oleh modulename dalam kode Python (misalnya, import <modulename>) dan dengan nama file pada baris perintah (misalnya, python <filename>). Semua juru bahasa Python dapat mengubah modulenames menjadi nama file melalui seperangkat aturan yang didefinisikan dengan baik. Aturan-aturan ini bergantung pada sys.pathvariabel dan karenanya pemetaan dapat diubah dengan mengubah nilai ini (untuk lebih lanjut tentang bagaimana hal ini dilakukan lihat PEP 302 ).

Ketiga, semua modul (baik kode dan paket) dapat dieksekusi (maksud kami kode yang terkait dengan modul akan dievaluasi oleh juru bahasa Python). Bergantung pada metode eksekusi, dan jenis modul, kode apa yang dievaluasi, dan kapan, dapat berubah sedikit. Sebagai contoh, jika seseorang mengeksekusi modul paket melalui python <filename>maka <filename>/__init__.pyakan dievaluasi diikuti oleh <filename>/__main__.py. Di sisi lain, jika seseorang mengeksekusi modul paket yang sama via import <modulename>maka hanya paket yang __init__.pyakan dieksekusi.

Perkembangan Sejarah -m

Bendera -m pertama kali diperkenalkan dalam Python 2.4.1 . Awalnya satu-satunya tujuan adalah untuk menyediakan cara alternatif untuk mengidentifikasi modul python untuk dieksekusi. Yaitu, jika kita tahu modul <filename>dan <modulename>untuk modul maka dua perintah berikut ini setara: python <filename> <args>dan python -m <modulename> <args>. Selain itu, menurut PEP 338 iterasi ini -mhanya bekerja dengan modulenames tingkat atas (yaitu, modul yang dapat ditemukan langsung di sys.path tanpa paket intervensi).

Dengan selesainya PEP 338 yang -mfungsi diperpanjang dukungan <modulename>representasi luar modulenames tingkat atas. Ini berarti nama-nama seperti http.serversekarang sepenuhnya didukung. Peningkatan ini juga berarti bahwa semua paket dalam sebuah modul sekarang dimuat (yaitu, semua __init__.pyfile paket dievaluasi), bersama dengan modul itu sendiri.

Peningkatan fitur utama akhir untuk -mdatang dengan PEP 366 . Dengan pembaruan ini -mdiperoleh kemampuan untuk mendukung tidak hanya impor absolut tetapi juga impor relatif eksplisit. Ini dicapai dengan memodifikasi __package__variabel untuk modul bernama dalam -mperintah.

Gunakan Kasing

Ada dua kasus penggunaan penting untuk flag -m:

  1. Untuk menjalankan modul dari baris perintah yang orang mungkin tidak tahu nama file mereka. Use case ini mengambil keuntungan dari fakta bahwa interpreter Python tahu cara mengubah modulenames menjadi nama file. Ini sangat menguntungkan ketika seseorang ingin menjalankan modul stdlib atau modul pihak ke-3 dari baris perintah. Sebagai contoh, sangat sedikit orang yang tahu nama file untuk http.servermodul tetapi kebanyakan orang tahu modulename-nya sehingga kita dapat mengeksekusinya dari baris perintah dengan menggunakan python -m http.server.

  2. Untuk menjalankan paket lokal yang mengandung impor absolut tanpa perlu menginstalnya. Kasus penggunaan ini dirinci dalam PEP 338 dan memanfaatkan fakta bahwa direktori kerja saat ini ditambahkan ke sys.pathdirektori modul. Kasus penggunaan ini sangat mirip dengan menggunakan pip install -e .untuk menginstal paket dalam mode mengembangkan / mengedit.

Kekurangan

Dengan semua perangkat tambahan yang dibuat -mselama bertahun-tahun masih memiliki satu kekurangan utama - itu hanya dapat menjalankan modul kode yang ditulis dengan python (yaitu, * .py). Misalnya, jika -mdigunakan untuk menjalankan modul kode yang dikompilasi C kesalahan berikut akan dihasilkan, No code object available for <modulename>(lihat di sini untuk detail lebih lanjut).

Perbandingan terperinci

Efek dari eksekusi modul melalui perintah python (yaitu, python <filename>):

  • sys.path dimodifikasi untuk memasukkan direktori final di <filename>
  • __name__ diatur ke '__main__'
  • __package__ diatur ke None
  • __init__.py tidak dievaluasi untuk paket apa pun (termasuk paket modulnya sendiri)
  • __main__.pydievaluasi untuk modul paket; kode dievaluasi untuk modul kode.

Efek dari eksekusi modul melalui pernyataan impor (yaitu, import <modulename>):

  • sys.pathadalah tidak diubah dengan cara apapun
  • __name__ diatur ke bentuk absolut dari <modulename>
  • __package__ diatur ke paket induk langsung di <modulename>
  • __init__.py dievaluasi untuk semua paket (termasuk sendiri untuk modul paket)
  • __main__.pyadalah tidak dievaluasi untuk modul paket; kode dievaluasi untuk modul kode

Efek dari eksekusi modul melalui flag -m (yaitu, python -m <modulename>):

  • sys.path dimodifikasi untuk memasukkan direktori saat ini
  • __name__ diatur ke '__main__'
  • __package__ diatur ke paket induk langsung di <modulename>
  • __init__.py dievaluasi untuk semua paket (termasuk sendiri untuk modul paket)
  • __main__.pydievaluasi untuk modul paket; kode dievaluasi untuk modul kode

Kesimpulan

The -mbendera, pada yang paling sederhana, alat untuk mengeksekusi script python dari baris perintah dengan menggunakan modulenames bukan nama file. Selain itu, -mmemberikan fungsionalitas tambahan yang menggabungkan kekuatan importpernyataan (misalnya, dukungan untuk impor relatif eksplisit dan __init__evaluasi paket otomatis ) dengan kenyamanan baris perintah python.

Mark Rucker
sumber
Bisakah Anda juga menambahkan penggunaan menggunakan paket menggunakan python -m packagenameseperti yang disebutkan di sini: stackoverflow.com/a/53772635/1779091
variabel
@variable good idea, saya menambahkan bagian "Use Case" yang mencakup itu.
Mark Rucker