Mục đích của công tắc -m là gì?


174

Bạn có thể giải thích cho tôi sự khác biệt giữa các cuộc gọi

python -m mymod1 mymod2.py args

python mymod1.py mymod2.py args

Dường như trong cả hai trường hợp mymod1.pyđược gọi và sys.argv

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

Vậy công -mtắc để làm gì?


Vui lòng sửa cho tôi nếu tôi sai, nhưng -mdường như tìm kiếm mymod1trong đường dẫn thư viện mặc định. Ví dụ: python -m SimpleHTTPServerhoạt động, trong khi python SimpleHTTPServerthất bại với can't open file 'SimpleHTTPServer': [Errno 2] No such file or directory.
Basj

7
Tôi thực sự đã tìm thấy câu trả lời ở đây rõ ràng hơn: stackoverflow.com/questions/46319694/
Kẻ

Câu trả lời:


137

Dòng đầu tiên của Rationalephần PEP 338 nói:

Python 2.4 thêm khóa chuyển đổi dòng lệnh -m để cho phép các mô-đun được định vị bằng cách sử dụng không gian tên mô-đun Python để thực thi dưới dạng tập lệnh. Các ví dụ tạo động lực là các mô-đun thư viện tiêu chuẩn như pdb và hồ sơ và việc triển khai Python 2.4 phù hợp với mục đích giới hạn này.

Vì vậy, bạn có thể chỉ định bất kỳ mô-đun nào trong đường dẫn tìm kiếm của Python theo cách này, không chỉ các tệp trong thư mục hiện tại. Bạn đúng mà python mymod1.py mymod2.py argscó tác dụng chính xác như nhau. Dòng đầu tiên của Scope of this proposalphần nêu:

Trong Python 2.4, một mô-đun nằm bằng -m được thực thi giống như tên tệp của nó đã được cung cấp trên dòng lệnh.

Với -mnhiều hơn là có thể, như làm việc với các mô-đun là một phần của gói, v.v. Đó là những gì còn lại của PEP 338. Đọc nó để biết thêm.


47
Cách sử dụng yêu thích của tôi -mpython -m SimpleHTTPServer. Thực sự tiện dụng khi tôi cần chia sẻ một số tập tin mà không cần sử dụng ổ flash USB.
arifwn

21
@arifwn Chạy Python3 yêu cầu cập nhật nhẹ python -m http.servervà điều này vẫn tuyệt vời!
Kit Roed

12
TL; DR: 1) Bạn có thể chạy python -m package.subpackage.modulevà máy móc phân giải bình thường sẽ được sử dụng, bạn không phải chỉ ra .pytệp chính xác . 2) Có thể thực hiện nhập tương đối từ mô-đun đang chạy mà không cần bất kỳ cách giải quyết nào, vì gói của nó sẽ được tải dọc đường. 3) Nhập tuyệt đối sẽ dựa trên thư mục hiện tại của bạn, không phải thư mục chứa .pytệp ( ''nằm ở đầu sys.path, thay vì /path/to/my, nếu tập lệnh đang ở /path/to/my/script.py).
clacke

Điều mà câu trả lời này không làm rõ là nó chỉ hoạt động trên tập hợp con của các mô-đun có thể thực thi tức là có một __main__.pytệp. Hầu hết không và sẽ phá vỡ, ví dụ như python -m sys 'print(sys.version)'thất bại với python: No code object available for sys. Đề nghị bạn làm rõ điều đó trong câu trả lời.
smci

19

Điều đáng nói là nó chỉ hoạt động nếu gói có tệp__main__.py Nếu không, gói này không thể được thực thi trực tiếp.

python -m some_package some_arguments

Trình thông dịch python sẽ tìm kiếm một __main__.pytệp trong đường dẫn gói để thực thi. Nó tương đương với:

python path_to_package/__main__.py somearguments

Nó sẽ thực thi nội dung sau:

if __name__ == "__main__":

2
Còn tập tin init gói thì sao? Trong sự hiện diện của tập tin chính, init cũng sẽ được gọi?
biến

@variable Có init .py sẽ được gọi trước khi main .py được gọi
Mark Rucker

1

Mặc dù câu hỏi này đã được hỏi và trả lời nhiều lần (ví dụ, ở đây , ở đây , ở đâyở đây ) theo ý kiến của tôi câu trả lời không hiện đầy đủ hoặc chính xác chụp tất cả những tác động của -mcờ. Do đó, những điều sau đây sẽ cố gắng cải thiện những gì đã đến trước đó.

TLD

Các -mlệnh thực hiện rất nhiều thứ không phải tất cả trong số họ hẳn sẽ cần tất cả các thời gian. Nói tóm lại: (1) cho phép các tập lệnh python được thực thi thông qua tên modul thay vì tên tệp (2) cho phép một người chọn một thư mục để thêm vào sys.pathđể importgiải quyết và (3) cho phép các tập lệnh python có nhập tương đối hoạt động giống như khi chúng gọi qua import.

Sơ bộ

Để hiểu tầm quan trọng của -mcờ, cần phải làm rõ một thuật ngữ nhỏ.

Đầu tiên, các tệp mà Python có thể thực thi được gọi là các mô-đun. Thông thường các mô-đun chúng tôi quan tâm là *.pycác tệp, nhưng không phải luôn luôn. Ví dụ, có thể viết các mô-đun Python bằng C để thực hiện mã quan trọng. Sự phân biệt này sẽ trở nên quan trọng sau này. Cho đến nay, đủ để biết rằng các mô-đun không phải là gói là các tệp.

Thứ hai, Python xác định các mô-đun thông qua một <modulename>định danh duy nhất (ví dụ import <modulename>:). Đối với mỗi duy nhất <modulename>cũng có một tệp duy nhất ở đâu đó trên máy với sự độc đáo của riêng nó <filename>. Các trình thông dịch Python tuân theo một số quy tắc được xác định rõ ràng được xây dựng xung quanh sys.pathđể ánh xạ <modulename>tới a <filename>(để biết thêm về cách thực hiện điều này, xem PEP 302 ).

Lịch sử phát triển của -m

Với ý nghĩa sơ bộ -mcó thể được giải thích theo nghĩa đơn giản nhất là bảo python tìm một mô-đun để thực hiện thông qua <modulename>chứ không phải <filename>. Nghĩa là, được đưa ra một <filename>hoặc <modulename>cho cùng một mô-đun, hai lệnh sau là tương đương python <filename>hoặc python -m <modulename>.

Trong bản phát hành 2.4.1 ban đầu , nơi -mđã được thêm vào, tất cả những gì nó đã làm là tìm và thực thi các mô-đun bằng cách <modulename>(cùng với việc thêm thư mục hiện tại vào sys.pathđể có thể tìm thấy các mô đun cục bộ). Theo PEP 338, việc triển khai ban đầu cũng bị hạn chế do đó -mkhông thể tham chiếu tên mô-đun trong các gói (nghĩa là phiên bản 2.4.1 sẽ không hỗ trợ tên mô-đun http.servernhưng sẽ hỗ trợ timeit).

Với việc bổ sung PEP 338 , -mchức năng đã được mở rộng để hỗ trợ các <modulename>đại diện trong các gói. Điều này có nghĩa là những cái tên như http.serverbây giờ đã được hỗ trợ đầy đủ -m. Tăng cường này cũng có nghĩa là tất cả các gói trong một tên mô-đun đã được nạp (ví dụ, gói __init__.pyfile đã được thực hiện), cùng với các mô-đun riêng của mình, trong trường hợp các gói sửa đổi của họ __path__trong __init__.py.

Một trường hợp sử dụng đáng chú ý được hỗ trợ -msau PEP 338 là các câu lệnh nhập tuyệt đối trong các gói tùy chỉnh mà không cần phải cài đặt gói sys.path. Điều này có thể đạt được bằng cách sử dụng đơn giản -mđể tải các tệp script từ thư mục gốc của dự án tùy chỉnh (vì thư mục gốc sau đó sẽ được thêm vào sys.path).

Cải tiến tính năng chính cuối cùng -mđã đi kèm với PEP 366 . Với bản cập nhật này -mđã đạt được khả năng hỗ trợ không chỉ nhập tuyệt đối mà cả nhập khẩu tương đối rõ ràng. Điều này đã đạt được bằng cách sửa đổi __package__biến cho mô-đun được đặt tên trong -mlệnh.

Với tất cả các cải tiến trên được thực hiện cho -mnó vẫn còn một thiếu sót lớn. Nó chỉ có thể thực thi các mô-đun được viết bằng python (tức là *.py). Nếu một tên mô-đun đề cập đến một mô-đun biên dịch C được chuyển đến -mlỗi sau đây được tạo ra No code object available for <modulename>.

So sánh -mvới các phương pháp thực hiện khác

Trái tim, -mcờ là một phương tiện để thực thi các tập lệnh python thông qua tên modul chứ không phải tên tệp. Vì lý do này, chúng tôi so sánh nó với hai phương thức nổi tiếng khác để thực hiện các mô-đun: (1) tên tệp với pythonlệnh và (2) tên mô-đun với importcâu lệnh.

Tác dụng của việc thực thi tên tệp bằng pythonlệnh (tức là python <filename>):

  1. Python's sys.pathđược sửa đổi để bao gồm vị trí của mô-đun trong độ phân giải nhập
  2. Biến của mô-đun __name__được đặt thành'__main__'
  3. Biến của mô-đun __package__được đặt thànhNone
  4. Không có __init__.pytệp nào sẽ được thực thi cho các gói cha trong<filename>

Hiệu ứng của việc thực thi modulename với importcâu lệnh (tức là import <modulename>):

  1. Python sys.pathkhông sửa đổi trong bất kỳ cách nào để giải quyết nhập khẩu
  2. Biến của mô-đun __name__được đặt thành tên mô-đun tuyệt đối của nó
  3. Biến của mô-đun __package__được đặt thành gói chứa trong<modulename>
  4. Tất cả __init__.pycác tệp sẽ được thực thi cho các gói cha mẹ trong<modulename>

Hiệu ứng của việc thực thi modulename với -mcờ (tức là python -m <modulename>):

  1. Python's sys.pathđược sửa đổi để bao gồm thư mục hiện tại trong độ phân giải nhập
  2. Biến của mô-đun __name__được đặt thành'__main__'
  3. Biến của mô-đun __package__được đặt thành gói chứa trong<modulename>
  4. Tất cả __init__.pycác tệp sẽ được thực thi cho các gói cha mẹ trong<modulename>

Tóm lược

Các -mlá cờ chỉ đơn giản là một cách khác để thực hiện một kịch bản python qua môđun chứ không phải là tên tập tin. Vì lý do này, người ta cần có ít nhất một sự hiểu biết nhỏ về cách Python ánh xạ các modulename thành tên tệp để tận dụng tối đa lợi thế của nó. Với cách hiểu này mặc dù người ta có được một công cụ mới mạnh mẽ kết hợp các tính năng của importcâu lệnh (ví dụ: hỗ trợ cho câu lệnh nhập tương đối rõ ràng) với sự tiện lợi của câu lệnh dòng pythonlệnh.


Bạn cũng có thể thêm việc sử dụng gói gọi bằng cách sử dụng python -m packagenamenhư đã đề cập ở đây: stackoverflow.com/a/53772635/1779091
biến
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.