Python sys.argv作用域规则

时间:2014-04-02 11:36:40

标签: python

我刚注意到sys.argv在导入的脚本中可见。

A.py

import sys
print("A")
print(sys.argv)
import B

B.py

import sys
print("B")
print(sys.argv)

产量

>> python A.py --foo bar
>> A
>> ['path/to/A.py', '--foo', 'bar']
>> B
>> ['path/to/A.py', '--foo', 'bar']

这很好,因为现在我不必在主脚本(aka.manage.py)中进行参数解析。

问题是:我能依靠这种行为吗?是否存在不起作用的情况?

4 个答案:

答案 0 :(得分:5)

模块属性,如sys.argv是对象。无论您访问哪个模块,它们都是同一个对象。

这也意味着如果一个模块修改sys.argv,那么该更改也会影响访问sys.argv的任何其他模块。


关于编码风格的提示:

虽然可能从两个不同的模块访问sys.argv,但我不推荐它,这就是原因。

我喜欢可以兼作模块的脚本。这为您重用代码提供了最大的灵活性。 sys.argv仅在代码作为脚本调用时才有意义。为了使代码可用作模块,代码不应依赖于在sys.argv中查找值。

因此,我建议在主调用脚本中解析sys.argv 一次

if __name__ == '__main__':
    import argparse
    def parse_args():
        ... # argparse uses  sys.argv

    args = parse_args()

然后根据需要将args中的值传递给函数。

因此,if __name__ == 'main__'语句之外的所有内容都不需要依赖sys.argv,因此可以通过简单的函数调用或模块导入来使用。

答案 1 :(得分:3)

这与sys.argv的范围无关,特别是所有模块都在一个全局实例中加载。

因此,如果A.py导入模块然后对其进行修改,如果B.py导入同一模块,则只能访问导入的模块A.py

例如:

A.py

import sys
sys.foo = "foo!"
import B

B.py

import sys
print sys.foo

在此处运行A.py将导入B.py,这将有权访问修改后的sys模块及其中的foo变量。但是,如果您直接运行B.py,则此代码会引发sys.foo不存在的错误。

这是一种非常糟糕的行为依赖,因为它对哪个模块导入了非常强大的假设,并且导致极其脆弱的代码。

答案 2 :(得分:1)

在启动期间(使用sys.argv)功能在Modules/main.c中设置了{p> PySys_SetArgv

现在, 可能另一个模块也调用PySys_SetArgvPySys_SetArgvEx,但是没有一个标准模块似乎这样做(Python 2.7),并且这样做要么1)成为非常特定的东西的一部分,或2)白痴

所谓的" argv clobbering"有时用于设置流程标题,虽然现代系统提供了更好的方法来执行此操作,但由于C argv的值在启动时被复制,这不应该是一个问题,即使它会使用。

所以,是的。你可以合理地依赖所有模块中的sys.argv,尽管有很多方法可以打破它,如果你真的想要的话。

答案 3 :(得分:0)

父脚本启动时设置sys.argv。无论你导入什么,它都不会在任何地方改变。