为什么全球'关键字需要访问全局变量?

根据我的理解,Python对函数有单独的命名空间,所以如果我想在函数中使用全局变量,我可能应该使用global

然而,即使没有global,我也能够访问全局变量:

>>> sub = ['0', '0', '0', '0']
>>> def getJoin():
...     return '.'.join(sub)
...
>>> getJoin()
'0.0.0.0'

为什么会这样?


另见在第一次使用后重新分配局部变量时发生的UnboundLocalError,当试图分配给全局变量而没有global时发生错误。参见在函数中使用全局变量了解如何使用全局变量的一般问题。

436653 次浏览

访问名称和分配名称是不同的。在本例中,您只是访问一个名称。

如果在函数中赋值给某个变量,则假定该变量为局部变量,除非将其声明为全局变量。如果没有,就假定它是全局的。

>>> x = 1         # global
>>> def foo():
print x       # accessing it, it is global


>>> foo()
1
>>> def foo():
x = 2        # local x
print x


>>> x            # global x
1
>>> foo()        # prints local x
2

虽然你可以在没有global关键字的情况下访问全局变量,但如果你想修改它们,你必须使用global关键字。例如:

foo = 1
def test():
foo = 2 # new local foo


def blub():
global foo
foo = 3 # changes the value of the global foo

在你的例子中,你只是访问列表sub

在函数外部声明的任何变量都被假定为全局变量,只有在函数内部声明它们时(构造函数除外),你必须指定变量为全局变量。

这意味着你不应该做以下事情:

x = 1


def myfunc():
global x


# formal parameter
def localfunction(x):
return x+1


# import statement
import os.path as x


# for loop control target
for x in range(10):
print x


# class definition
class x(object):
def __init__(self):
pass


#function definition
def x():
print "I'm bad"

关键字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

而如果使用global语句,则该变量将在函数作用域“外部”可用,有效地成为全局变量。

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在局部上下文中声明函数、类或其他对象。尽管我建议不要这样做,因为如果出现错误或需要调试,这会导致噩梦。

这是在作用域中访问名称和绑定 it之间的区别。

如果你只是查找一个变量来读取它的值,你可以访问全局作用域和局部作用域。

然而,如果你赋值给一个变量,它的名字不在局部作用域,你将绑定这个名字到这个作用域(如果这个名字也作为一个全局变量存在,你将隐藏它)。

如果您希望能够分配全局名称,则需要告诉解析器使用全局名称,而不是绑定新的本地名称——这就是'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
>>>

其他答案回答了你的问题。关于Python中的名称,要知道的另一件重要的事情是,它们在每个作用域上要么是本地的,要么是全局的。

举个例子:

value = 42


def doit():
print value
value = 0


doit()
print value

你可能会猜测value = 0语句将赋值给一个局部变量,而不会影响在doit()函数外部声明的同一个变量的值。你可能会更惊讶地发现上面的代码将无法运行。函数内的语句print value产生了UnboundLocalError.

原因是Python已经注意到,在函数的其他地方,你分配了value的名称,而且value也没有声明为global。这使它成为一个局部变量。但是当你试图打印它时,本地名称还没有定义。Python在这种情况下不会退缩来查找作为全局变量的名称,就像其他一些语言那样。本质上,如果在函数中定义了同名的局部变量在任何地方,则无法访问全局变量。

  • 你可以不使用global关键字来访问全局关键字
  • 为了能够修改它们,您需要显式地声明关键字是全局的。否则,关键字将在局部范围内声明。

例子:

words = [...]


def contains (word):
global words             # <- not really needed
return (word in words)


def add (word):
global words             # must specify that we're working with a global keyword
if word not in words:
words += [word]

Global使变量为Global

def out():
global x
x = 1
print(x)
return




out()


print (x)

这使得'x'就像函数外的普通变量一样。如果你把全局变量拿出来,它就会报错,因为它不能在函数中打印变量。

def out():
# Taking out the global will give you an error since the variable x is no longer 'global' or in other words: accessible for other commands
x = 1
print(x)
return




out()


print (x)

这在Python常见问题解答中有很好的解释

Python中局部变量和全局变量的规则是什么?

在Python中,只在函数中引用的变量是隐式全局变量。如果一个变量在函数体的任何位置被赋值,除非显式声明为全局变量,否则它将被假定为局部变量。

虽然一开始有点令人惊讶,但仔细考虑一下就能解释这一点。一方面,为赋值的变量要求global可以防止意外的副作用。另一方面,如果所有全局引用都需要global,那么你将一直使用global。你必须将每个对内置函数或导入模块的组件的引用声明为global。这种混乱将破坏global声明识别副作用的有用性。

https://docs.python.org/3/faq/programming.html#what-are-the-rules-for-local-and-global-variables-in-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是一种代码气味,但有时你需要的正是像global这样的肮脏黑客。不管怎样,“global"这是一个不好的名字,因为在python中没有全局作用域这样的东西,它的模块一直向下。