Python中导入的类函数中的全局变量

yoe*_*oel 4 python global-variables python-2.7

我试图将代码分散到单独的文件中以提高可读性,并且遇到了在导入的文件中引用未定义的全局名称的麻烦。是否有比调用时将所有必要的值有意传递给函数更好的解决方案?

我的代码当前是这样的:

#foo.py

import bar

def main():
    a = 1
    b = bar.Bar()
    while True:
        a += 1
        b.incr()
        print a
        print b.c

if __name__ == '__main__':
    main()

#END foo.py
Run Code Online (Sandbox Code Playgroud)

--

#bar.py

class Bar:
    def __init__(self):
        self.c = 0
    def incr(self):
        self.c += a

#END bar.py
Run Code Online (Sandbox Code Playgroud)

它给我NameError:全局名称'a'未定义。我需要像这样重写main():

def main():
        b = new bar.Bar()
        while True:
            a += 1
            b.incr(a)
            print a
            print b.c
Run Code Online (Sandbox Code Playgroud)

然后像这样重写incr():

def incr(self,a):
            c += a
Run Code Online (Sandbox Code Playgroud)

或者,还有更好的方法?

作为记录,上面的代码被大量抽象。实际的代码包含大量的类和函数,这些类和函数传递许多类型的变量,包括一些大型词典。

提前致谢!

aba*_*ert 5

如果您只想知道为什么它不起作用:

首先,main不是设置global a,而是设置local。如果要使其全局,则必须明确:

def main():
    global a
    a = 1
    # ...
Run Code Online (Sandbox Code Playgroud)

但这不能解决问题,因为Python中的“全局”是按模块的。换句话说,这只会创建一个foo.a,但是您的代码bar.Bar将在寻找中bar.a,而该将不存在。

如果需要import foo,您可以然后访问foo.a。(在这种情况下,循环依赖关系不应该成为问题,并且if __name__ == '__main__'不会被执行两次。)或者您可以假定foo已将其导入并使用sys.modules['foo'].a。或者你也可以注入abar从的字典foo。或许多其他技巧。但是这些都是可怕的事情。

如果您无法进行全局工作,那么正确的答案几乎总是避免使用全局工作。(实际上,即使您可以进行全球工作,通常也是正确的答案。)

那么,你该怎么做呢?在不了解更多细节的情况下,很难猜测是否a属于全局的显式模块,类属性,实例属性,的参数incr,等等。但是要弄清楚哪个a代表最有意义,并做到这一点。


在注释中,您建议您有很多这样的配置变量。如果将它们全部包装在a中,dict并将其传递dict给每个对象的构造函数,那将使事情变得更简单。

更重要的dict是,a 是对可变对象的引用。复制它只是对该对象的另一个引用。

main.py:

def main():
    configs = {}
    configs['gravity'] = 1.0
    rock = rps.Rock(configs)
    rock.do_stuff()
    configs['gravity'] = 2.1
    rock.do_stuff()
if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

rps.py:

class Rock(object):
    def __init__(self, configs):
        self.configs = configs
    def do_stuff(self):
        print('Falling with gravity {}.'.format(self.configs['gravity']))
Run Code Online (Sandbox Code Playgroud)

运行此命令时,它将打印如下内容:

Falling with gravity 1.0.
Falling with gravity 2.1.
Run Code Online (Sandbox Code Playgroud)

您尚未修改该值configs['gravity'](这是一个不可变的float;您无法修改它),但是您已将其替换为其他值(因为configs它是可变的dict;您可以修改它就好了)。如果身份不清楚id(self.configs),您可以尝试id(self.configs['gravity'])在各个地方打印,等内容。