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)
或者,还有更好的方法?
作为记录,上面的代码被大量抽象。实际的代码包含大量的类和函数,这些类和函数传递许多类型的变量,包括一些大型词典。
提前致谢!
如果您只想知道为什么它不起作用:
首先,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。或者你也可以注入a到bar从的字典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'])在各个地方打印,等内容。