根据我的理解,Python有一个单独的函数名称空间,所以如果我想在函数中使用全局变量,我可能应该使用global。
然而,我能够访问一个全局变量,即使没有全局:
>>> sub = ['0', '0', '0', '0']
>>> def getJoin():
... return '.'.join(sub)
...
>>> getJoin()
'0.0.0.0'
为什么会这样?
另请参阅第一次使用后重新分配局部变量时发生的UnboundLocalError,以了解试图分配给全局变量而不使用全局变量时发生的错误。有关如何使用全局变量的一般问题,请参阅在函数中使用全局变量。
其他答案回答了你的问题。关于Python中的名称,要知道的另一件重要的事情是,它们在每个作用域上要么是本地的,要么是全局的。
举个例子:
value = 42
def doit():
print value
value = 0
doit()
print value
您可能会猜测,value = 0语句将赋值给一个局部变量,而不会影响在doit()函数外部声明的同一个变量的值。您可能会更惊讶地发现上面的代码无法运行。函数内部的语句打印值产生一个UnboundLocalError。
原因是Python已经注意到,在函数的其他地方,你分配了name value,而且value也没有声明为全局的。这使它成为一个局部变量。但是当你试图打印它时,本地名称还没有定义。在这种情况下,Python不会像其他一些语言那样返回到将名称作为全局变量来查找。从本质上讲,如果在函数中任何地方定义了同名的局部变量,则无法访问全局变量。
这就是访问名称和在作用域中绑定名称之间的区别。
如果你只是查找一个变量来读取它的值,你可以访问全局作用域和局部作用域。
但是,如果赋值给的变量的名称不在局部作用域中,则将该名称绑定到此作用域中(如果该名称也作为全局变量存在,则将隐藏它)。
如果您希望能够分配全局名称,则需要告诉解析器使用全局名称,而不是绑定新的本地名称——这就是'global'关键字所做的。
绑定块中的任何位置都会导致该块中的任何位置的名称都被绑定,这可能会导致一些看起来相当奇怪的结果(例如,UnboundLocalError突然出现在之前的工作代码中)。
>>> a = 1
>>> def p():
print(a) # accessing global scope, no binding going on
>>> def q():
a = 3 # binding a name in local scope - hiding global
print(a)
>>> def r():
print(a) # fail - a is bound to local scope, but not assigned yet
a = 4
>>> p()
1
>>> q()
3
>>> r()
Traceback (most recent call last):
File "<pyshell#35>", line 1, in <module>
r()
File "<pyshell#32>", line 2, in r
print(a) # fail - a is bound to local scope, but not assigned yet
UnboundLocalError: local variable 'a' referenced before assignment
>>>
关键字global仅用于在局部上下文中更改或创建全局变量,尽管创建全局变量很少被认为是一个好的解决方案。
def bob():
me = "locally defined" # Defined only in local context
print(me)
bob()
print(me) # Asking for a global variable
以上会给你:
locally defined
Traceback (most recent call last):
File "file.py", line 9, in <module>
print(me)
NameError: name 'me' is not defined
而如果使用全局语句,则变量将在函数作用域之外可用,有效地成为全局变量。
def bob():
global me
me = "locally defined" # Defined locally but declared as global
print(me)
bob()
print(me) # Asking for a global variable
所以上面的代码会给你:
locally defined
locally defined
此外,由于python的特性,您还可以使用global在局部上下文中声明函数、类或其他对象。尽管我建议不要这样做,因为如果出现错误或需要调试,这会导致噩梦。
Global使变量对模块(模块作用域)中的所有内容可见,就像您在模块本身的顶层定义了它一样。它在模块外部是不可见的,在它被设置之前,它不能从模块中导入,所以不用麻烦,这不是它的用途。
全球何时能解决实际问题?(注意:仅在Python 3上检查。)
# Attempt #1, will fail
# We cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to
# do it automatically when importing this module
top_level_something_or_other = None
def foo1():
import catbus
# Now ``catbus`` is visible for anything else defined inside ``foo()``
# at *compile time*
bar() # But ``bar()`` is a call, not a definition. ``catbus``
# is invisible to it.
def bar():
# `bar()` sees what is defined in the module
# This works:
print(top_level_something_or_other)
# This doesn't work, we get an exception: NameError: name 'catbus' is not defined
catbus.run()
这可以用global来修复:
# Attempt #2, will work
# We still cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to
# do it automatically when importing this module
top_level_something_or_other = None
def foo2():
import catbus
global catbus # Now catbus is also visible to anything defined
# in the top-level module *at runtime*
bar()
def bar():
# `bar` sees what is defined in the module and when run what is available at run time
# This still works:
print(top_level_something_or_other)
# This also works now:
catbus.run()
如果bar()在foo中定义,这就不需要了:
# Attempt 3, will work
# We cannot import ``catbus`` here
# as that would lead to an import loop somewhere else,
# or importing ``catbus`` is so expensive that you don't want to
# do it automatically when importing this module
top_level_something_or_other = None
def foo3():
def bar():
# ``bar()`` sees what is defined in the module *and* what is defined in ``foo()``
print(top_level_something_or_other)
catbus.run()
import catbus
# Now catbus is visible for anything else defined inside foo() at *compile time*
bar() # Which now includes bar(), so this works
通过在foo()之外定义bar(), bar()可以被导入到可以直接导入catbus的东西中,或者在单元测试中模拟它。
全局是一种代码气味,但有时你需要的正是像全局这样的肮脏黑客。不管怎样,“global”对它来说是个坏名字,因为在python中没有全局作用域这样的东西,它一直是模块。