-m 开关的用途是什么?

发布于 2024-12-07 06:40:46 字数 318 浏览 1 评论 0原文

之间的区别吗?

python -m mymod1 mymod2.py args

你能向我解释一下调用和

python mymod1.py mymod2.py args

似乎在这两种情况下都调用了 mymod1.pysys.argv

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

那么 -m 是什么? 切换为?

Could you explain to me what the difference is between calling

python -m mymod1 mymod2.py args

and

python mymod1.py mymod2.py args

It seems in both cases mymod1.py is called and sys.argv is

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

So what is the -m switch for?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

盗心人 2024-12-14 06:40:46

尽管这个问题已被多次提出和回答(例如,此处这里此处此处 ),在我看来,没有现有的答案能够完全或简洁地捕获 -m 标志的所有含义。因此,下文将尝试在之前的基础上进行改进。

简介 (TLDR)

-m 标志可以做很多事情,但并不是所有的事情都一直需要。简而言之,它可用于:(1) 通过模块名而不是文件名从命令行执行 python 代码 (2) 将目录添加到 sys.path 以便在 import 中使用code> 解析并 (3) 执行包含来自命令行的相对导入的 python 代码。

预备知识

为了解释 -m 标志,我们首先需要解释一些术语。

Python 的主要组织单元称为模块。模块有两种类型之一:代码模块和包模块。代码模块是包含 python 可执行代码的任何文件。包模块是包含其他模块(代码模块或包模块)的任何目录。最常见的代码模块类型是 *.py 文件,而最常见的包模块类型是包含 __init__.py 文件的目录。

Python 允许通过两种方式唯一标识模块:模块名和文件名。一般来说,模块由 Python 代码中的模块名(例如,import)和命令行上的文件名(例如,python)来标识。 。所有 Python 解释器都能够通过遵循相同的几个明确定义的规则将模块名转换为文件名。这些规则取决于 sys.path 变量。通过更改此变量,可以更改 Python 将模块名解析为文件名的方式(有关如何完成此操作的更多信息,请参阅 PEP 302)。

所有模块(代码和包)都可以执行(即与模块关联的代码将由Python解释器评估)。根据执行方法(和模块类型),评估哪些代码以及何时评估,可能会发生很大的变化。例如,如果通过 python 执行包模块,则 /__main__.py 将被执行。另一方面,如果通过 import执行相同的包模块,则只会执行包的 __init__.py

-m 的历史发展

-m 标志首次在 Python 2.4.1。最初它的唯一目的是提供一种识别要从命令行执行的 python 模块的替代方法。也就是说,如果我们知道模块的 ,那么以下两个命令是等效的:python;python -m。根据 PEP 338,此迭代的一个约束是-m 仅适用于顶级模块名称(即可以直接在 sys.path 上找到的模块,无需任何中间包模块)。

随着 PEP 338 的完成,-m功能已扩展为支持超出顶层的 表示。这意味着诸如 http.server 之类的名称现在已得到完全支持。此扩展还意味着除了 modulename 本身引用的模块之外,现在还会评估 modulename 中的每个父包(即,评估所有父包 __init__.py 文件)。

-m 的最终主要功能增强来自 PEP 366< /a>.通过此升级,-m 不仅能够支持绝对导入,还能够在执行模块时支持显式相对导入。这是通过更改 -m 来实现的,以便将 __package__ 变量设置为给定模块名的父模块(除了它已经完成的其他所有操作之外)。

用例

-m 标志有两个值得注意的用例:

  1. 从命令行执行模块,而人们可能不知道其文件名。该用例利用了 Python 解释器知道如何将模块名转换为文件名的事实。当想要从命令行运行 stdlib 模块或第 3 方模块时,这是特别有利的。例如,很少有人知道 http.server 模块的文件名,但大多数人都知道它的模块名称,因此我们可以使用 python -m http.server 从命令行执行它代码>.

  2. 执行包含绝对或相对导入的本地包,而无需安装它。 PEP 338 中详细介绍了此用例 并利用当前工作目录被添加到 sys.path 而不是模块目录的事实。此用例与使用 pip install -e . 在开发/编辑模式下安装软件包非常相似。

缺点

尽管多年来对 -m 进行了所有增强,但它仍然有一个主要缺点 - 它只能执行用 Python 编写的模块(即 *.py)。例如,如果使用 -m 执行 C 编译代码模块,则会产生以下错误:No code object available for(请参阅此处了解更多详细信息)。

详细比较

通过导入语句执行模块(即import):

  • sys.path不是以任何方式修改
  • __name__ 设置为 的绝对形式
  • __package__ 设置为 < 中的直接父包;模块名称>
  • __init__.py 针对所有包(包括它自己的包模块)进行评估;
  • __main__.py 不针对包模块进行评估;针对代码模块评估代码

通过带有文件名的命令行执行模块(即python):

  • sys.path 已修改将最终目录包含在
  • __name__ 设置为 '__main__'
  • __package__ 设置为 <代码>无
  • __init__.py 不会针对任何包(包括它自己的包模块)进行评估;
  • __main__.py 会针对包模块进行评估;代码针对代码模块进行评估。

通过带有模块名称的命令行执行模块(即python -m):

  • sys.path 被修改为包含当前目录
  • __name__ 设置为 '__main__'
  • __package__ 设置为 中的直接父包
  • __init__.py 针对所有包(包括它自己的包模块)进行评估;
  • __main__.py 针对包模块进行评估; 最简单的是,-m标志

结论

是一种使用模块名而不是文件名从命令行执行 python 脚本的方法。然而,-m 的真正威力在于它能够结合 import 语句的威力(例如,支持显式相对导入和自动包 __init__< /code> 评估)与命令行的便利。

Despite this question having been asked and answered several times (e.g., here, here, here, and here), in my opinion no existing answer fully or concisely captures all the implications of the -m flag. Therefore, the following will attempt to improve on what has come before.

Introduction (TLDR)

The -m flag does a lot of things, not all of which will be needed all the time. In short, it can be used to: (1) execute python code from the command line via modulename rather than filename (2) add a directory to sys.path for use in import resolution and (3) execute python code that contains relative imports from the command line.

Preliminaries

To explain the -m flag we first need to explain a little terminology.

Python's primary organizational unit is known as a module. Modules come in one of two flavors: code modules and package modules. A code module is any file that contains python executable code. A package module is any directory that contains other modules (either code modules or package modules). The most common type of code module is a *.py file while the most common type of package module is a directory containing an __init__.py file.

Python allows modules to be uniquely identified in two ways: modulename and filename. In general, modules are identified by modulename in Python code (e.g., import <modulename>) and by filename on the command line (e.g., python <filename>). All Python interpreters are able to convert modulenames to filenames by following the same few, well-defined rules. These rules hinge on the sys.path variable. By altering this variable one can change how Python resolves modulenames into filenames (for more on how this is done see PEP 302).

All modules (both code and package) can be executed (i.e., code associated with the module will be evaluated by the Python interpreter). Depending on the execution method (and module type) what code gets evaluated, and when, can change quite a bit. For example, if one executes a package module via python <filename> then <filename>/__main__.py will be executed. On the other hand, if one executes that same package module via import <modulename> then only the package's __init__.py will be executed.

Historical Development of -m

The -m flag was first introduced in Python 2.4.1. Initially its only purpose was to provide an alternative means of identifying the python module to execute from the command line. That is, if we knew both the <filename> and <modulename> for a module then the following two commands were equivalent: python <filename> <args> and python -m <modulename> <args>. One constraint with this iteration, according to PEP 338, was that -m only worked with top level modulenames (i.e., modules that could be found directly on sys.path without any intervening package modules).

With the completion of PEP 338 the -m feature was extended to support <modulename> representations beyond the top level. This meant names such as http.server were now fully supported. This extension also meant that each parent package in modulename was now evaluated (i.e., all parent package __init__.py files were evaluated) in addition to the module referenced by the modulename itself.

The final major feature enhancement for -m came with PEP 366. With this upgrade -m gained the ability to support not only absolute imports but also explicit relative imports when executing modules. This was achieved by changing -m so that it set the __package__ variable to the parent module of the given modulename (in addition to everything else it already did).

Use Cases

There are two notable use cases for the -m flag:

  1. To execute modules from the command line for which one may not know their filename. This use case takes advantage of the fact that the Python interpreter knows how to convert modulenames to filenames. This is particularly advantageous when one wants to run stdlib modules or 3rd-party module from the command line. For example, very few people know the filename for the http.server module but most people do know its modulename so we can execute it from the command line using python -m http.server.

  2. To execute a local package containing absolute or relative imports without needing to install it. This use case is detailed in PEP 338 and leverages the fact that the current working directory is added to sys.path rather than the module's directory. This use case is very similar to using pip install -e . to install a package in develop/edit mode.

Shortcomings

With all the enhancements made to -m over the years it still has one major shortcoming -- it can only execute modules written in Python (i.e., *.py). For example, if -m is used to execute a C compiled code module the following error will be produced, No code object available for <modulename> (see here for more details).

Detailed Comparisons

Module execution via import statement (i.e., import <modulename>):

  • sys.path is not modified in any way
  • __name__ is set to the absolute form of <modulename>
  • __package__ is set to the immediate parent package in <modulename>
  • __init__.py is evaluated for all packages (including its own for package modules)
  • __main__.py is not evaluated for package modules; the code is evaluated for code modules

Module execution via command line with filename (i.e., python <filename>):

  • sys.path is modified to include the final directory in <filename>
  • __name__ is set to '__main__'
  • __package__ is set to None
  • __init__.py is not evaluated for any package (including its own for package modules)
  • __main__.py is evaluated for package modules; the code is evaluated for code modules.

Module execution via command line with modulename (i.e., python -m <modulename>):

  • sys.path is modified to include the current directory
  • __name__ is set to '__main__'
  • __package__ is set to the immediate parent package in <modulename>
  • __init__.py is evaluated for all packages (including its own for package modules)
  • __main__.py is evaluated for package modules; the code is evaluated for code modules

Conclusion

The -m flag is, at its simplest, a means to execute python scripts from the command line by using modulenames rather than filenames. The real power of -m, however, is in its ability to combine the power of import statements (e.g., support for explicit relative imports and automatic package __init__ evaluation) with the convenience of the command line.

你怎么这么可爱啊 2024-12-14 06:40:46

PEP 338基本原理部分的第一行> 说:

Python 2.4 添加了命令行开关 -m,以允许使用 Python 模块命名空间来定位模块,以便作为脚本执行。激励示例是标准库模块,例如 pdb 和 profile,Python 2.4 实现非常适合这个有限的目的。

所以你可以通过这种方式指定Python搜索路径中的任何模块,而不仅仅是当前目录中的文件。您是对的,python mymod1.py mymod2.py args具有完全相同的效果。 此提案的范围部分的第一行指出:

在 Python 2.4 中,使用 -m 定位的模块的执行就像在命令行上提供了其文件名一样。

使用 -m 可以实现更多功能,例如使用属于包一部分的模块等。这就是 PEP 338 其余部分的内容。阅读它以获取更多信息。

The first line of the Rationale section of PEP 338 says:

Python 2.4 adds the command line switch -m to allow modules to be located using the Python module namespace for execution as scripts. The motivating examples were standard library modules such as pdb and profile, and the Python 2.4 implementation is fine for this limited purpose.

So you can specify any module in Python's search path this way, not just files in the current directory. You're correct that python mymod1.py mymod2.py args has exactly the same effect. The first line of the Scope of this proposal section states:

In Python 2.4, a module located using -m is executed just as if its filename had been provided on the command line.

With -m more is possible, like working with modules which are part of a package, etc. That's what the rest of PEP 338 is about. Read it for more info.

银河中√捞星星 2024-12-14 06:40:46

值得一提的是只有当包中有文件__main__.py时才有效,否则该包无法直接执行。

python -m some_package some_arguments

python解释器将在包路径中寻找__main__.py文件来执行。相当于:

python path_to_package/__main__.py somearguments

它将执行之后的内容:

if __name__ == "__main__":

It's worth mentioning this only works if the package has a file __main__.py Otherwise, this package can not be executed directly.

python -m some_package some_arguments

The python interpreter will looking for a __main__.py file in the package path to execute. It's equivalent to:

python path_to_package/__main__.py somearguments

It will execute the content after:

if __name__ == "__main__":
极度宠爱 2024-12-14 06:40:46

我只想提一个可能令人困惑的案例。

假设您使用 pip3 安装包 foo,其中包含 bar 模块。所以这意味着您可以从任何目录执行python3 -m foo.bar。另一方面,您的目录结构如下:

src
|
+-- foo
    |
    +-- __init__.py
    |
    +-- bar.py

您位于 src/。当您运行python -m foo.bar时,您正在运行bar.py,而不是已安装的模块。但是,如果您从任何其他目录调用 python -m foo.bar ,则您正在使用已安装的模块。

如果您使用 python 而不是 python -m,这种行为肯定不会发生,并且可能会让初学者感到困惑。原因是 Python 搜索模块的顺序。

I just want to mention one potentially confusing case.

Suppose you use pip3 to install a package foo, which contains a bar module. So this means you can execute python3 -m foo.bar from any directory. On the other hand, you have a directory structure like this:

src
|
+-- foo
    |
    +-- __init__.py
    |
    +-- bar.py

You are at src/. When you run python -m foo.bar, you are running the bar.py, instead of the installed module. However, if you are calling python -m foo.bar from any other directory, you are using the installed module.

This behavior certainly doesn't happen if you are using python instead of python -m, and can be confusing for beginners. The reason is the order how Python searches for modules.

梦里泪两行 2024-12-14 06:40:46

简而言之,“python -m”开关的最佳用例之一是当您想要告诉 Python 您想要运行模块而不是执行 .py 文件时。

考虑以下示例:名为“venv”的文件(不带“.py”文件扩展名)中有一个 Python 脚本。如果您发出此命令:

python venv

那么,Python 将执行当前目录中的“venv”文件。但是,如果您想使用“python venv”模块创建新的虚拟环境,则可以运行:

python -m venv

在这种情况下,Python 将运行“venv”模块,而不是“venv”文件。

另一个例子,如果你想运行 Pyhton 的内置本地 http 服务器并发出命令:

python http.server

你会得到一个类似这样的错误:

python: can't open file '/home/user/http.server': [Errno 2] No such file or directory

那是因为 Python 试图执行一个名为“http.server”的文件,但没有找到它。
因此,您希望发出相同的命令,但使用“-m”开关:

python -m http.server

以便 Python 知道您需要模块“http.server”而不是文件。

In short, one of the best use case for 'python -m' switch is when you want to tell Python that you want to run a module instead of executing a .py file.

Consider this example: you have a Python script in a file named 'venv' (without '.py' file extension). If you issue this command:

python venv

then, Python will excute the 'venv' file in the current directory. However, if instead you want to create a new virtual environment using the 'python venv' module, you would run:

python -m venv

in which case, Python will run the 'venv' module, not the file 'venv'.

Another example, if you want to run Pyhton's built-in local http server and issue the command:

python http.server

you would get an error like:

python: can't open file '/home/user/http.server': [Errno 2] No such file or directory

That's because Python tried to execute a file called 'http.server' and didn't find it.
So instead, you want to issue the same command but with '-m' switch:

python -m http.server

so that Python knows you want the module 'http.server' not the file.

水水月牙 2024-12-14 06:40:46

由于当您搜索 Use of "python -m" 时会出现这个问题,我只是想为那些喜欢模块化代码而不创建完整的 Python 包每次修改 PYTHONPATHsys.path

设置

让我们设置以下文件结构,

.
├── f1
│   ├── f2
│   │   ├── __init__.py
│   │   └── test2.py
│   ├── __init__.py
│   └── test1.py
└── test.py

让当前路径为m1

使用 python -m 而不是 python ./*

  1. 使用 . 限定的模块文件名称(因为它们现在被视为模块)。例如,要运行 ./f1/test1.py 中的内容,我们这样做

    python -m f1.test1
    

    而不是

    python ./f1/test1.py
    
  2. 当使用 module 方法时,sys.path test1.py(运行时)中的m1。使用./(相对文件)方法时,路径为m1/f1

    因此我们可以使用 -m 访问 m1 中的所有文件(并假设它是一个完整的 python 包)。这是因为 m1 的路径已存储(作为 PYTHONPATH)。


  3. 如果我们想运行深层嵌套的“模块”,我们仍然可以使用(就像我们在import语句中所做的那样)。

    # 这可以完成
    python -m f1.f2.test2
    

    test2.py 中,我们可以执行 from f1.test1 import do_something 而无需使用任何 其中的路径噱头

  4. 每次我们以这种方式导入模块时,都会自动调用__init__.py。即使我们筑巢时也是如此。

    python -m f1.f2.test2
    

    当我们这样做时,会调用./f1/__init__.py,然后调用./f1/f2/__init__.py

Since this question comes up when you google Use of "python -m", I just wanted to add a quick reference for those who like to modularize code without creating full python packages or modifying PYTHONPATH or sys.path every time.

Setup

Let's setup the following file structure

.
├── f1
│   ├── f2
│   │   ├── __init__.py
│   │   └── test2.py
│   ├── __init__.py
│   └── test1.py
└── test.py

Let the present path be m1.

Using python -m instead of python ./*

  1. Use . qualified module names for the files (because they're being treated as modules now). For example, to run the contents in ./f1/test1.py, we do

    python -m f1.test1
    

    and not

    python ./f1/test1.py
    
  2. When using the module method, the sys.path in test1.py (when that is run) is m1. When using the ./ (relative file) method, the path is m1/f1.

    So we can access all files in m1 (and assume that it is a full python package) using -m. This is because the path to m1 is stored (as PYTHONPATH).

  3. If we want to run deeply nested "modules", we can still use . (just as we do in import statements).

    # This can be done
    python -m f1.f2.test2
    

    And in test2.py, we can do from f1.test1 import do_something without using any path gimmicks in it.

  4. Every time we do module imports this way, the __init__.py is automatically called. This is true even when we're nesting.

    python -m f1.f2.test2
    

    When we do that, the ./f1/__init__.py is called, followed by ./f1/f2/__init__.py.

千里故人稀 2024-12-14 06:40:46

TLDR:

-m 标志允许您从任何地方运行脚本(模块),只要 Python 可以找到它。

更长的版本:

假设我们有一个脚本my_script.py

您必须从文件所在的目录运行python my_script.py

或者 - python path/to/my_script.py

但是,您可以运行 python -m my_script (即通过省略 .py 按模块名称引用脚本)从任何地方,只要Python能找到它!

Python 搜索如下(不能 100% 确定顺序):

  • 当前目录
  • PYTHONPATH 环境变量中列出的目录,如果设置了
  • PythonXX\Lib (标准库所在的位置,如 os 或 random
  • PythonXX\Lib\site-packages (全局安装的包所在的位置)

要对其进行测试,请继续将“Hello World”脚本放置在 <代码>站点包或者在 PYTHONPATH 环境变量中设置其目录,您会发现可以从命令行的任何位置运行它

有关更多低级但重要的差异,请参阅其他答案。

TLDR:

The -m flag lets you run a script (module) from anywhere, as long as Python can find it.

Longer version:

Assume we have a script my_script.py.

You must run python my_script.py from the directory where the file is located.

Alternatively - python path/to/my_script.py

However, you can run python -m my_script (ie refer to the script by module name by omitting the .py) from anywhere, as long as Python can find it!

Python searches as follows (not 100% sure about the order):

  • Current directory
  • Directories listed in the PYTHONPATH environment variable, if set
  • PythonXX\Lib (where the standard libraries live, like os or random
  • PythonXX\Lib\site-packages (where globally installed packages live)

To test it out, go ahead and place a "Hello World" script in either site-packages or set its directory in the PYTHONPATH env variable, and you will find that you can run it from anywhere on the command line.

For more low-level but important differences, see other answers.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文