使用 -m 选项执行 Python 代码或不执行
使用 -m
标志。
如果你要将包中的子包或模块作为程序的主入口点运行,那么使用脚本时结果几乎相同,但是在开发包时,如果没有 -m
标志,则无法使导入工作正确(相信我,我已经尝试过很多次)。
文档
像-m 标志文档中所说:
在 sys.path 中搜索指定的模块并执行其内容作为 __main__
模块。
以及
与 -c 选项一样,当前目录将添加到 sys.path 的开头。
因此,
python -m pdb
大致相当于
python /usr/lib/python3.5/pdb.py
(假设您当前目录中没有名为pdb.py的包或脚本)
解释:
行为意图 "有意与" 脚本相似。
许多标准库模块包含在其执行时作为脚本调用的代码。例如timeit 模块:
一些 Python 代码旨在作为模块运行: (我认为这个例子比命令行选项文档的例子更好)
$ 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
从Python 2.4版本的发布说明中可以看到:
命令行选项"-m",即python -m modulename将在标准库中查找模块并调用它。例如,python -m pdb
等价于 python /usr/lib/python2.4/pdb.py
后续问题
此外,David Beazley的《Python Essential Reference》解释道:" -m选项运行库模块作为脚本,在主脚本执行前在__main__
模块内部执行".
这意味着您可以使用import语句查找任何模块,并以程序入口的形式运行它——如果它有一段代码块,通常位于结尾处,其中带有if __name__ == '__main__':
.
-m
在不将当前目录添加到路径的情况下:
这里的其他评论说:
-m选项还会将当前目录添加到sys.path中,这显然是一种安全问题(参见:preload攻击)。 这个行为类似于Windows中的库搜索顺序(在最近已经被加固之前)。 遗憾的是,Python没有跟随这个趋势,并没有提供一种简单的方法来禁用在sys.path中添加“。”
好吧,这证明了可能存在的问题 - (在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)]
在生产环境中使用 -I
标志来锁定此功能(自 3.4 版本起新增):
python -Im pdb
usage: pdb.py [-c command] ... pyfile [arg] ...
etc...
来自文档:
-I
以隔离模式运行Python。这也意味着使用了-E和-s选项。在隔离模式下,sys.path既不包含脚本目录,也不包含用户的site-packages目录。所有PYTHON*环境变量也会被忽略。还可能实施其他限制以防止用户注入恶意代码。
__package__
是什么作用?
它启用显式相对导入,与此问题无关 - 参见这里的答案:Python中“__package__”属性的目的是什么?
PYTHONPATH=test python -m foo.bar
的实际含义是什么?您能详细解释一下吗? - AndriyPYTHONPATH
设置一个环境变量,扩展了Python导入模块时查找的一系列目录;这里添加了test
目录到该系列中。将其放在同一命令行上,它仅适用于该单个python
命令。-m
告诉Python要导入特定的模块,就像运行import foo.bar
一样。但是,在使用该开关时,当你使用了一个包内的__main__
模块作为脚本时,Python会自动运行它。 - Martijn Pieters-m
仅适用于当前目录或已注册到搜索路径的目录。那就是我的观点。-m
不是您要为最终用户提供的东西,因为存在这个可用性问题。 - Martijn Pietersfrom Photos import ...
会报错。import Photos.<something>
也一样。只有import Photos
能够正常工作,因为 Python 支持命名空间包(即两个独立的分发提供了Photos.foo
和Photos.bar
分别管理)。 - Martijn Pieters