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

时间:2013-03-13 21:47:25

标签: python python-2.7 global-variables

我正在尝试将我的代码分散到不同的文件中以提高可读性,而且我遇到了在导入文件中引用未定义的全局名称的问题。有没有比在调用时故意将所有必要值传递给函数更好的解决方案?

我的代码目前是这样的:

#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

-

#bar.py

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

#END bar.py

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

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

并像这样重写incr():

def incr(self,a):
            c += a

或者有更好的方法吗?

为了记录,上面的代码被大量抽象。实际的代码涉及很多类和函数,它们传递了许多类型的变量,包括一些大的字典。

提前致谢!

2 个答案:

答案 0 :(得分:4)

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

首先,main未设置全局a,而是设置本地def main(): global a a = 1 # ... 。如果你想让它全球化,你必须明确:

foo.a

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

如果您愿意,可以foo.a然后访问if __name__ == '__main__'。 (在这种情况下,循环依赖不应该是一个问题,并且foo将不会执行两次。)或者您可以假设已导入sys.modules['foo'].a,并使用a }。或者您可以将bar注入foo的{​​{1}}字典中。或许多其他技巧。但这些都是可怕的事情。

如果你不能做全球工作,那么正确的答案几乎总是不使用全球性的。 (事实上​​,即使你可以进行全球工作,这通常也是正确答案。)

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


在评论中,您建议您拥有一堆这些配置变量。如果你将它们全部包装在dict中并将dict传递给每个对象的构造函数,那将使事情变得更简单。

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

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()

rps.py:

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

当你运行它时,它会打印出如下内容:

Falling with gravity 1.0.
Falling with gravity 2.1.

你没有修改值configs['gravity'](这是一个不可变的浮点数;你不能修改它),但你用不同的值替换它(因为{{1是一个可变的configs;你可以修改它就好了)。如果身份不明确,您可以尝试在各个地方打印dictid(self.configs)等内容。

答案 1 :(得分:2)

如果aBar的特征或配置,则它应该是其实例或类属性。

class Bar(object):
    class_step = 1
    def __init__(self, inst_step):
        self.inst_step = inst_step
        self.c = 0
        self.step_mode = 'class'
    def inc(self):
        self.c += Bar.class_step if self.step_mode == 'class' else self.inst_step