是否使用-m选项执行Python代码

发布于 2021-01-29 17:37:52

python解释器具有-m 模块 选项“将库模块 模块 作为脚本运行”。

使用此python代码a.py:

if __name__ == "__main__":
    print __package__
    print __name__

我测试python -m a

"" <-- Empty String
__main__

python a.py回报

None <-- None
__main__

对我来说,这两个调用似乎是相同的,只是当用-m选项调用__package__时不为None。

有趣的是,有了python -m runpy a,我得到了与python -m a编译成a.pyc的python模块相同的东西。

这些调用之间的(实际)区别是什么?它们之间有什么利弊?

同样,David Beazley的Python Essential Reference将其解释为“
-m选项将库模块作为脚本运行,并在执行主脚本之前在__main__模块内部执行 ”。这是什么意思?

关注者
0
被浏览
50
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    当您使用-m命令行标志时,Python将为您导入模块
    或包 ,然后将其作为脚本运行。当您不使用该-m标志时,您命名的文件 仅作为脚本 运行。

    当您尝试运行软件包时,区别很重要。之间有很大的区别:

    python foo/bar/baz.py
    

    python -m foo.bar.baz
    

    与后一种情况一样,foo.bar将导入,并且相对导入将foo.bar作为起点正确运行。

    演示:

    $ 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__
    

    结果,在使用-m开关时,Python实际上必须关心软件包。普通脚本永远 不能 是软件包,因此__package__将其设置为None

    但运行一个封装或模块 与包裹-m和现在至少存在 可能性 的封装的,所以__package__变量设置为一个字符串值;
    在上面的演示中,将其设置为'foo.bar',对于不在包内的普通模块,将其设置为空字符串。

    至于__main__ 模块
    ,Python会导入正在运行的脚本,就像导入常规模块一样。创建一个新的模块对象来保存全局名称空间,并将其存储在中sys.modules['__main__']。这就是__name__变量所指的,它是该结构中的关键。

    对于包,您可以在其中创建一个__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__
    

    因此,在命名要与一起运行的包时-m,Python会查找__main__该包中包含的模块并将其作为脚本执行。然后,其名称仍设置为'__main__',并且模块对象仍存储在中sys.modules['__main__']



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看