是否使用 -m 选项执行 Python 代码
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/22241420/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Execution of Python code with -m option or not
提问by prosseek
The python interpreter has -mmoduleoption that "Runs library module moduleas a script".
python 解释器具有“将库模块模块作为脚本运行”的-m模块选项。
With this python code a.py:
使用这个python代码a.py:
if __name__ == "__main__":
print __package__
print __name__
I tested python -m ato get
我测试python -m a得到
"" <-- Empty String
__main__
whereas python a.pyreturns
而python a.py返回
None <-- None
__main__
To me, those two invocation seems to be the same except __package__ is not None when invoked with -m option.
对我来说,这两个调用似乎是相同的,除了使用 -m 选项调用时 __package__ 不是 None 。
Interestingly, with python -m runpy a, I get the same as python -m awith python module compiled to get a.pyc.
有趣的是,使用python -m runpy a,我得到的结果与python -m a编译得到 a.pyc 的 python 模块相同。
What's the (practical) difference between these invocations? Any pros and cons between them?
这些调用之间的(实际)区别是什么?他们之间有什么优缺点吗?
Also, David Beazley's Python Essential Reference explains it as "The -m option runs a library module as a script which executes inside the __main__ module prior to the execution of the main script". What does it mean?
此外,David Beazley 的 Python Essential Reference 将其解释为“ -m 选项将库模块作为脚本运行,该脚本在执行主脚本之前在 __main__ 模块内执行”。这是什么意思?
采纳答案by Martijn Pieters
When you use the -mcommand-line flag, Python will import a module or packagefor you, then run it as a script. When you don't use the -mflag, the file you named is run as just a script.
当您使用-m命令行标志时,Python 会为您导入一个模块或包,然后将其作为脚本运行。当您不使用该-m标志时,您命名的文件将作为脚本运行。
The distinction is important when you try to run a package. There is a big difference between:
当您尝试运行包时,这种区别很重要。之间有很大的区别:
python foo/bar/baz.py
and
和
python -m foo.bar.baz
as in the latter case, foo.baris imported and relative imports will work correctly with foo.baras the starting point.
与后一种情况一样,foo.bar导入和相对导入将foo.bar作为起点正常工作。
Demo:
演示:
$ mkdir -p test/foo/bar
$ touch test/foo/__init__.py
$ touch test/foo/bar/__init__.py
$ cat << EOF > test/foo/bar/baz.py
> if __name__ == "__main__":
> print __package__
> print __name__
>
> EOF
$ PYTHONPATH=test python test/foo/bar/baz.py
None
__main__
$ PYTHONPATH=test python -m foo.bar.baz
foo.bar
__main__
As a result, Python has to actually care about packages when using the -mswitch. A normal script can never bea package, so __package__is set to None.
因此,Python 在使用-mswitch时必须真正关心包。普通脚本永远不能是包,因此__package__设置为None.
But run a package or module insidea package with -mand now there is at least the possibilityof a package, so the __package__variable is set to a string value; in the above demonstration it is set to foo.bar, for plain modules not inside a package, it is set to an empty string.
但运行一个封装或模块内与包裹-m和现在至少存在可能性的封装的,所以__package__变量设置为一个字符串值; 在上面的演示中,它被设置为foo.bar,对于不在包内的普通模块,它被设置为空字符串。
As for the __main__module; Python imports scripts being run as it would a regular module. A new module object is created to hold the global namespace, stored in sys.modules['__main__']. This is what the __name__variable refers to, it is a key in that structure.
至于__main__模块;Python 导入正在运行的脚本,就像普通模块一样。创建一个新的模块对象来保存全局命名空间,存储在sys.modules['__main__']. 这就是__name__变量所指的内容,它是该结构中的一个键。
For packages, you can create a __main__.pymodule and have that run when running python -m package_name; in fact that's the only way you canrun a package as a script:
对于包,您可以创建一个__main__.py模块并在运行时运行它python -m package_name;其实这是你的唯一途径可以运行包的脚本:
$ PYTHONPATH=test python -m foo.bar
python: No module named foo.bar.__main__; 'foo.bar' is a package and cannot be directly executed
$ cp test/foo/bar/baz.py test/foo/bar/__main__.py
$ PYTHONPATH=test python -m foo.bar
foo.bar
__main__
So, when naming a package for running with -m, Python looks for a __main__module contained in that package and executes that as a script. It's name is then still set to __main__, and the module object is still stored in sys.modules['__main__'].
因此,当命名一个包以运行 with 时-m,Python 会查找__main__该包中包含的模块并将其作为脚本执行。然后它的名称仍然设置为__main__,并且模块对象仍然存储在sys.modules['__main__'].
回答by Aaron Hall
Execution of Python code with -m option or not
是否使用 -m 选项执行 Python 代码
Use the -mflag.
使用-m旗帜。
The results are pretty much the same when you have a script, but when you develop a package, without the -mflag, there's no way to get the imports to work correctly if you want to run a subpackage or module in the package as the main entry point to your program (and believe me, I've tried.)
当您有脚本时,结果几乎相同,但是当您开发包时,如果没有-m标志,如果您想将包中的子包或模块作为主条目运行,则无法使导入正常工作指向你的程序(相信我,我已经试过了。)
The docs
文档
Like the docs on the -m flagsay:
Search sys.path for the named module and execute its contents as the
__main__module.
在 sys.path 中搜索命名模块并将其内容作为
__main__模块执行。
and
和
As with the -c option, the current directory will be added to the start of sys.path.
与 -c 选项一样,当前目录将被添加到 sys.path 的开头。
so
所以
python -m pdb
is roughly equivalent to
大致相当于
python /usr/lib/python3.5/pdb.py
(assuming you don't have a package or script in your current directory called pdb.py)
(假设您的当前目录中没有名为 pdb.py 的包或脚本)
Explanation:
解释:
Behavior is made "deliberately similar to" scripts.
行为是“故意类似于”脚本的。
Many standard library modules contain code that is invoked on their execution as a script. An example is the timeit module:
许多标准库模块包含在作为脚本执行时调用的代码。一个例子是timeit 模块:
Some python code is intended to be run as a module:(I think this example is better than the commandline option doc example)
一些python代码打算作为一个模块运行:(我认为这个例子比命令行选项doc示例更好)
$ python -m timeit '"-".join(str(n) for n in range(100))'
10000 loops, best of 3: 40.3 usec per loop
$ python -m timeit '"-".join([str(n) for n in range(100)])'
10000 loops, best of 3: 33.4 usec per loop
$ python -m timeit '"-".join(map(str, range(100)))'
10000 loops, best of 3: 25.2 usec per loop
And from the release note highlights for Python 2.4:
The -m command line option - python -m modulename will find a module in the standard library, and invoke it. For example,
python -m pdbis equivalent topython /usr/lib/python2.4/pdb.py
-m 命令行选项 - python -m modulename 将在标准库中找到一个模块,并调用它。例如,
python -m pdb相当于python /usr/lib/python2.4/pdb.py
Follow-up Question
后续问题
Also, David Beazley's Python Essential Reference explains it as "The -m option runs a library module as a script which executes inside the
__main__module prior to the execution of the main script".
此外,David Beazley 的 Python Essential Reference 将其解释为“-m 选项将库模块作为脚本运行,该脚本
__main__在执行主脚本之前在模块内执行”。
It means any module you can lookup with an import statement can be run as the entry point of the program - if it has a code block, usually near the end, with if __name__ == '__main__':.
这意味着您可以使用 import 语句查找的任何模块都可以作为程序的入口点运行 - 如果它有一个代码块,通常在末尾,带有if __name__ == '__main__':.
-mwithout adding the current directory to the path:
-m不将当前目录添加到路径中:
A comment here elsewhere says:
其他地方的评论说:
That the -m option also adds the current directory to sys.path, is obviously a security issue (see: preload attack). This behavior is similar to library search order in Windows (before it had been hardened recently). It's a pity that Python does not follow the trend and does not offer a simple way to disable adding . to sys.path
-m 选项还将当前目录添加到 sys.path,这显然是一个安全问题(请参阅:预加载攻击)。此行为类似于 Windows 中的库搜索顺序(在最近强化之前)。遗憾的是,Python 没有跟上潮流,也没有提供一种简单的方法来禁用添加 . 到 sys.path
Well, this demonstrates the possible issue - (in windows remove the quotes):
好吧,这说明了可能的问题 - (在 Windows 中删除引号):
echo "import sys; print(sys.version)" > pdb.py
python -m pdb
3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul 5 2016, 11:41:13) [MSC v.1900 64 bit (AMD64)]
Use the -Iflag to lock this down for production environments (new in version 3.4):
使用该-I标志来锁定生产环境(3.4 版中的新功能):
python -Im pdb
usage: pdb.py [-c command] ... pyfile [arg] ...
etc...
from the docs:
从文档:
-IRun Python in isolated mode. This also implies -E and -s. In isolated mode sys.path contains neither the script's directory nor the user's site-packages directory. All PYTHON* environment variables are ignored, too. Further restrictions may be imposed to prevent the user from injecting malicious code.
-I在隔离模式下运行 Python。这也意味着 -E 和 -s。在隔离模式下 sys.path 既不包含脚本的目录也不包含用户的站点包目录。所有 PYTHON* 环境变量也被忽略。可能会施加进一步的限制以防止用户注入恶意代码。
What does __package__do?
有什么作用__package__?
It enables explicit relative imports, not particularly germane to this question, though - see this answer here: What's the purpose of the "__package__" attribute in Python?
它启用了显式相对导入,但与这个问题并不是特别密切相关 - 请在此处查看此答案:Python 中“__package__”属性的目的是什么?
回答by ddbug
The main reason to run a module (or package) as a script with -m is to simplify deployment, especially on Windows. You can install scripts in the same place in the Python library where modules normally go - instead of polluting PATH or global executable directories such as ~/.local (the per-user scripts directory is ridiculously hard to find in Windows).
使用 -m 将模块(或包)作为脚本运行的主要原因是为了简化部署,尤其是在 Windows 上。您可以在 Python 库中模块通常所在的同一位置安装脚本 - 而不是污染 PATH 或全局可执行目录,例如 ~/.local (在 Windows 中很难找到每个用户的脚本目录)。
Then you just type -m and Python finds the script automagically. For example, python -m pipwill find the correct pip for the same instance of Python interpreter which executes it. Without -m, if user has several Python versions installed, which one would be the "global" pip?
然后你只需输入 -m ,Python 就会自动找到脚本。例如,python -m pip将为执行它的 Python 解释器的同一个实例找到正确的 pip。如果没有 -m,如果用户安装了多个 Python 版本,哪一个是“全局”pip?
If user prefers "classic" entry points for command-line scripts, these can be easily added as small scripts somewhere in PATH, or pip can create these at install time with entry_points parameter in setup.py.
如果用户更喜欢命令行脚本的“经典”入口点,可以将它们作为小脚本轻松添加到 PATH 中的某处,或者 pip 可以在安装时使用 setup.py 中的 entry_points 参数创建这些。
So just check for __name__ == '__main__'and ignore other non-reliable implementation details.
所以只需检查__name__ == '__main__'并忽略其他不可靠的实现细节。

