4

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

我的代码目前是这样的:

#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: global name 'a' is not defined。我是否需要像这样重写 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

或者,还有更好的方法?

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

提前致谢!

4

2 回答 2

5

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

首先,main不是设置全局a,而是设置本地。如果你想让它成为全球性的,你必须明确:

def main():
    global a
    a = 1
    # ...

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

如果你愿意,你可以import foo然后访问foo.a。(在这种情况下,循环依赖应该没有问题,并且if __name__ == '__main__'不会执行两次。)或者你可以假设它foo已经被导入,并使用sys.modules['foo'].a. 或者您可以a从. 或者很多其他的技巧。但这些都是可怕的事情。barfoo

如果您无法制作全局作品,那么正确的答案几乎总是不使用全局作品。(事实上​​,即使你可以制作出全球性的作品,这通常也是正确的答案。)

那么,你是怎么做到的呢?在不了解更多细节的情况下,很难猜测是否a属于显式模块全局、类属性、实例属性、参数incr等。但是根据所代表的内容找出哪个最有意义a,然后去做。


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

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

主要.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'](这是一个不可变的浮点数;您无法修改它),但是您已将其替换为不同的值(因为configs它是一个可变的dict;您可以修改它就好了)。如果身份不清楚,您可以尝试在各个地方打印出id(self.configs),等内容。id(self.configs['gravity'])

于 2013-03-13T21:57:15.723 回答
2

如果a是 的一个特征或配置Bar,则应该是其实例或类属性。

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
于 2013-03-13T21:53:28.337 回答