关于Python3时间没有彻底的答案,所以我在这里做了一个回答。这里描述的大部分内容在Python 3文档的4.2.2名称解析中详细描述。
正如在其他回答中提供的,有4个基本范围,即LEGB,分别表示本地、封闭、全局和内置。除此之外,还有一个特殊的作用域,即类体,它不包含类内定义的方法的封闭作用域;类体中的任何赋值都将使该变量从此被绑定到类体中。
特别是,除了def和class,没有块语句创建变量作用域。在Python 2中,列表推导式不创建变量作用域,但在Python 3中,列表推导式中的循环变量是在新的作用域中创建的。
为了证明阶级主体的特殊性
x = 0
class X(object):
y = x
x = x + 1 # x is now a variable
z = x
def method(self):
print(self.x) # -> 1
print(x) # -> 0, the global x
print(y) # -> NameError: global name 'y' is not defined
inst = X()
print(inst.x, inst.y, inst.z, x) # -> (1, 0, 1, 0)
因此,与在函数体中不同的是,你可以将变量重新赋值给类体中的相同名称,以获得具有相同名称的类变量;进一步查找此名称将解析
改为类变量。
对于许多Python新手来说,一个更大的惊喜是for循环不创建变量作用域。在Python 2中,列表推导式也不创建作用域(而生成器和字典推导式可以!)相反,它们会泄漏函数或全局作用域中的值:
>>> [ i for i in range(5) ]
>>> i
4
在Python 2中,推导式可以用作在lambda表达式中创建可修改变量的狡猾(如果你愿意,也可以是可怕的)方法——lambda表达式确实创建了一个变量作用域,就像def语句一样,但在lambda中不允许任何语句。赋值在Python中是一个语句,这意味着lambda中不允许变量赋值,但列表理解式是一个表达式…
这种行为在Python 3中已经修复——没有理解表达式或生成器泄漏变量。
全局指的是模块作用域;python的主要模块是__main__;所有导入的模块都可以通过sys. sys访问。模块变量;要访问__main__,可以使用sys. js。模块['__main__'],或导入__main__;在那里访问和赋值属性是完全可以接受的;它们将作为变量显示在主模块的全局作用域中。
如果一个名称在当前作用域中被赋值(类作用域除外),它将被认为属于该作用域,否则它将被认为属于赋值给该变量的任何封闭作用域(它可能还没有被赋值,或者根本没有赋值),或者最终属于全局作用域。如果变量被认为是本地的,但尚未设置或已删除,读取变量值将导致UnboundLocalError,它是NameError的子类。
x = 5
def foobar():
print(x) # causes UnboundLocalError!
x += 1 # because assignment here makes x a local variable within the function
# call the function
foobar()
作用域可以声明它显式地想要修改全局(模块作用域)变量,使用global关键字:
x = 5
def foobar():
global x
print(x)
x += 1
foobar() # -> 5
print(x) # -> 6
这也是可能的,即使它是封闭范围的阴影:
x = 5
y = 13
def make_closure():
x = 42
y = 911
def func():
global x # sees the global value
print(x, y)
x += 1
return func
func = make_closure()
func() # -> 5 911
print(x, y) # -> 6 13
在python 2中,没有简单的方法来修改封闭范围内的值;通常这是通过一个可变值来模拟的,比如一个长度为1的列表:
def make_closure():
value = [0]
def get_next_value():
value[0] += 1
return value[0]
return get_next_value
get_next = make_closure()
print(get_next()) # -> 1
print(get_next()) # -> 2
然而在python3中,nonlocal来拯救:
def make_closure():
value = 0
def get_next_value():
nonlocal value
value += 1
return value
return get_next_value
get_next = make_closure() # identical behavior to the previous example.
非本地文档是这么说的
与全局语句中列出的名称不同,非局部语句中列出的名称必须引用封闭作用域中的预先存在的绑定(不能明确确定应该在其中创建新绑定的作用域)。
即nonlocal总是指名称被绑定的最内外部的非全局作用域(即赋值给,包括用作for目标变量,在with子句中,或作为函数参数)。
Any variable that is not deemed to be local to the current scope, or any enclosing scope, is a global variable. A global name is looked up in the module global dictionary; if not found, the global is then looked up from the builtins module; the name of the module was changed from python 2 to python 3; in python 2 it was __builtin__ and in python 3 it is now called builtins. If you assign to an attribute of builtins module, it will be visible thereafter to any module as a readable global variable, unless that module shadows them with its own global variable with the same name.
读取内置模块也很有用;假设您希望在文件的某些部分使用python 3样式的print函数,但文件的其他部分仍然使用print语句。在Python 2.6-2.7中,你可以通过以下方法获得Python 3 print函数:
import __builtin__
print3 = __builtin__.__dict__['print']
from __future__ import print_function实际上不会在Python 2中的任何地方导入print函数——相反,它只是禁用当前模块中print语句的解析规则,像处理任何其他变量标识符一样处理print,从而允许在内置中查找print函数。