关于Python3时间,还没有详尽的答案,所以我在这里做了一个答案。4.2.2 Python 3文档名称的解析详细介绍了此处描述的大部分内容。
如其他答案中所提供的,本地,封闭,全局和内置有4个基本范围,即LEGB。除此以外,还有一个特殊的范围,即类主体,它不包含该类中定义的方法的封闭范围;类主体内的任何赋值都会使变量从此绑定到类主体中。
特别是,除了和之外,没有块语句创建变量作用域。在Python 2中,列表推导不会创建变量作用域,但是在Python 3中,列表推导内的循环变量是在新作用域中创建的。def
class
证明班级机构的特殊性
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)
因此,与函数主体不同,您可以在类主体中将变量重新分配给相同的名称,以获得具有相同名称的类变量。对该名称的进一步查找将解析为class变量。
对于Python的许多新手来说,最大的惊喜之一就是for
循环不会创建变量作用域。在Python 2中,列表推导也不创建作用域(而generator和dict则创建!)而是泄漏函数或全局范围中的值:
>>> [ i for i in range(5) ]
>>> i
4
理解可以用作在Python 2中的lambda表达式内创建可修改变量的一种狡猾(或者如果您愿意的话)的方法-lambda表达式确实会创建变量作用域,就像该def
语句那样,但是在lambda中不允许使用任何语句。赋值是Python中的语句,表示不允许在lambda中进行变量赋值,但列表推导是一个表达式...
此行为已在Python 3中修复-没有理解表达式或生成器会泄漏变量。
全局实际上意味着模块范围;主要的python模块是__main__
; 所有导入的模块都可以通过该sys.modules
变量访问;获得__main__
可以使用的权限sys.modules['__main__']
,或import __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
但是,在python 3中,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
文件说
与在全局语句中列出的名称不同,非本地语句中列出的名称必须引用封闭范围内的现有绑定(不能明确确定应在其中创建新绑定的范围)。
即,nonlocal
始终是指已绑定名称的最内层外部非全局范围(即,分配给该全局for
变量,包括在with
子句中或用作函数参数,包括用作目标变量)。
任何不被认为是当前作用域或任何封闭作用域局部变量的变量都是全局变量。在模块全局词典中查找全局名称;如果找不到,则从内建模块中查找全局变量;模块的名称从python 2更改为python 3; 在python 2中曾经是__builtin__
,在python 3中现在被称为builtins
。如果分配给buildins模块的属性,此后它将以可读的全局变量的形式对任何模块可见,除非该模块用自己的同名全局变量来遮盖它们。
读取内置模块也很有用;假设您希望在文件的某些部分使用python 3样式的打印功能,但文件的其他部分仍使用该print
语句。在Python 2.6-2.7中,您可以使用以下命令来掌握Python 3 print
函数:
import __builtin__
print3 = __builtin__.__dict__['print']
该from __future__ import print_function
实际上不会导入print
功能,随时随地在Python 2 -而不是它只是禁止解析规则,print
在当前模块中的语句,处理print
像任何其他变量标识符,从而使print
功能的内建进行查找。