在Java中,如果我想要“一个可用于类中所有方法的不变的变量而不作为参数传递”,我会这样做:
public class MyClass {
private static final OtherClass OTHER_CLASS = buildOtherClass()
...
private static OtherClass buildOtherClass() {
//<creation logic>
}
}
但是,如果我尝试在Python脚本中做类似的事情,我会收到错误:
$ cat python_test.py
#!/usr/bin/env python3
DICTIONARY = buildDictionary()
def methodThatUsesDictionary()
...
def buildDictionary():
d = {}
for i in range(5):
d[str(i)] = i
return d
if __name__ == '__main__':
methodThatUsesDictionary()
$ ./python_test.py
Traceback (most recent call last):
File "./python_test.py", line 3, in <module>
DICTIONARY = buildDictionary()
NameError: name 'buildDictionary' is not defined
如果我在方法声明下面移动变量声明,代码将按预期运行。但是,对我而言,感觉真的不合理,因为依赖于元素排序的代码合法性, - 文件中的方法存在,我不明白为什么它不能仅仅因为它“没有”而被找到已被宣布尚未“。 Moverover,将一般(非特定于方法的)变量放在文件的顶部是一个代码约定,我发现它非常明智和有用 - “这里是我们将要处理的事情的概述”(虽然我猜测在Python中不那么真实,你没有类型声明来提供额外的上下文。)
我可以看到几种可以解决这个问题的方法,其中没有一种方法在美学方面令人愉悦:
__init__
方法中初始化该变量。再次,这似乎是不必要的开销。__main__
方法调用的方法的全局变量,如下面的代码所示。我看到很多指导意见表明全局变量是危险信号,所以我怀疑我也应该避免这种情况。(我需要在这里放置文字,否则下面的片段是未格式化的,大概是因为紧接在上面的子弹)
$ cat python_test_2.py
#!/usr/bin/env python3
def initializeGlobalVariables():
global DICTIONARY
DICTIONARY = {}
for i in range(5):
DICTIONARY[str(i)] = i
def doOtherLogic():
for key in DICTIONARY:
print('DICTIONARY[' + str(key) + '] is ' + str(DICTIONARY[key]))
def main():
initializeGlobalVariables()
doOtherLogic()
if __name__ == '__main__':
main()
$ ./python_test_2.py
DICTIONARY[0] is 0
DICTIONARY[1] is 1
DICTIONARY[2] is 2
DICTIONARY[3] is 3
DICTIONARY[4] is 4
可能我正在尝试做的事情完全是单声道的,因此缺乏支持是“按设计”。我希望从更有经验的Python用户那里得到一些关于风格和结构的反馈。
答案 0 :(得分:1)
Python和Java基本上是非常不同的语言,Python更像是脚本语言而不是编译(尽管它可以即时编译)。此外,Python并没有真正具有&#34;一个不变的变量......&#34;的概念,至少不是变量名。变量名实际上是指向任何类型数据的指针(请参阅:动态类型),如果没有一些特殊的python装饰器,您可以随时更改变量的值,有时甚至会对您造成损害。
更重要的是,由于其脚本性质(并且可以交互式执行),事情的顺序很重要:
>>> def test():
... print x
...
>>> test()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in test
NameError: global name 'x' is not defined
>>> x = 1
>>> test()
1
>>>
在这种情况下,函数x
中的全局test
只是一个指针,x
尚不存在并不重要因为你没有& #39; t试图运行test
。当来自强类型和编译语言时,这似乎是违反直觉的,但是它允许很多很好的东西,比如动态导入只会在使用函数时加载模块:
>>> def dyn_import():
... import random
... for i in xrange(5):
... print random.random()
...
>>> random.random()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'random' is not defined
>>> dyn_import()
0.246957404578
0.302236192705
0.614960539467
0.0928052533036
0.389804554563
>>> random.random()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'random' is not defined
如果在函数内部使用之前需要完全定义每个变量,那么定义dyn_import
将失败,除非加载random
并且了解random.random()
的含义。在这种情况下,在实际执行该功能之前不会加载它。此外,由于该函数不会将模块放入脚本的全局命名空间,因此只要函数完成就会丢弃该模块。
这只是一个非常有益的例子,虽然这是一个非常重要的例子。