Python的作用域规则是什么
如果我有一些代码:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
在哪里可以找到x
?一些可能的选择包括以下列表:
- 在封闭的源文件中
- 在类命名空间中
- 在函数定义中
- for循环中的索引变量
- 在for循环内部
在执行过程中,当函数spam
被传递到其他地方时,还有上下文。也许lambda functions的传递方式有点不同
一定有一个简单的参考或算法。对于中级Python程序员来说,这是一个令人困惑的世界
Tags:
实际上,Python范围解析的简明规则来自Learning Python, 3rd. Ed.。(这些规则特定于变量名,而不是属性。如果引用时没有句点,则适用这些规则。)
立法局规则
Local-在函数(
def
或lambda
)中以任何方式分配的名称,并且在该函数中未声明为全局的Enclosing function-在任何和所有静态封闭函数(
def
或lambda
)的局部范围内指定的名称,从内部到外部Global(模块)-在模块文件的顶层分配的名称,或通过在文件内的
def
中执行global
语句分配的名称B内置(Python)-在内置名称模块中预先分配的名称:
open
、range
、SyntaxError
等那么,在
for
循环没有自己的命名空间。按照立法顺序,范围将是def spam
(incode3
、code4
和code5
)def
)x
(在code1
)李>x
将永远不会在code2
中找到(即使在您可能期望的情况下,请参见Antti's answer或here)关于Python3号的时间还没有完全的答案,所以我在这里做了一个回答。这里描述的大部分内容在Python3文档的4.2.2 Resolution of names中有详细说明
如其他答案所述,有4个基本范围,即LEGB,用于本地、封闭、全局和内置。除此之外,还有一个特殊的作用域,类主体,它不包括类内定义的方法的封闭作用域;类主体中的任何赋值都会使从此处开始的变量绑定到类主体中
特别是,noblock语句,除了
def
和class
之外,还创建了一个变量作用域。在Python2中,列表理解不创建变量作用域,但是在Python3中,列表理解中的循环变量是在新的作用域中创建的展示班级成员的特点
因此,与函数体不同,您可以在类体中将变量重新分配到相同的名称,以获得具有相同名称的类变量;对此名称的进一步查找将解决此问题 改为使用类变量
对于许多Python新手来说,更令人惊讶的是
for
循环并没有创建变量作用域。在Python 2中,列表理解也不创建作用域(而生成器和dict理解创建作用域!),而是在函数或全局作用域中泄漏值:这些理解可以作为一种巧妙的(或者糟糕的)方法,在Python 2中的lambda表达式中生成可修改的变量-lambda表达式确实会创建变量范围,就像
def
语句一样,但在lambda中不允许任何语句。赋值是Python中的语句,这意味着lambda中不允许变量赋值,但列表理解是一个表达式这种行为在Python3中已得到修复-没有理解表达式或生成器泄漏变量
全局实际上是指模块范围;python的主要模块是
__main__
;所有导入的模块都可以通过sys.modules
变量访问;要访问__main__
,可以使用sys.modules['__main__']
或import __main__
;在那里访问和分配属性是完全可以接受的;它们将在主模块的全局范围内显示为变量如果在当前作用域(类作用域除外)中分配了名称,则该名称将被视为属于该作用域,否则将被视为属于分配给变量的任何封闭作用域(可能尚未分配,或根本未分配),或最终属于全局作用域。如果变量被视为局部变量,但尚未设置或已删除,则读取变量值将导致
UnboundLocalError
,这是NameError
的子类作用域可以声明它显式地想要修改全局(模块作用域)变量,并使用global关键字:
即使它被隐藏在封闭范围内,这也是可能的:
在Python2中,没有简单的方法修改封闭范围中的值;通常,这是通过具有可变值来模拟的,例如长度为1的列表:
然而,在python 3中,
nonlocal
起到了拯救作用:报告说,
即
nonlocal
始终指名称已绑定到的最内层外部非全局作用域(即分配给,包括用作for
目标变量、在with
子句中或用作函数参数)任何不被认为是当前作用域或任何封闭作用域的局部变量都是全局变量。在模块全局字典中查找全局名称;如果未找到,则从内置模块中查找全局;模块名称从python 2更改为python 3;在Python2中它是
__builtin__
,在Python3中它现在被称为builtins
。如果指定给buil的属性tins模块之后,它将作为可读的全局变量对任何模块可见,除非该模块使用其自己的同名全局变量对其进行阴影处理阅读内置模块也很有用;假设您希望在文件的某些部分使用python 3样式的打印函数,但文件的其他部分仍然使用
print
语句。在Python 2.6-2.7中,您可以通过以下方法获得Python 3print
函数:实际上
from __future__ import print_function
并没有在Python 2中的任何地方导入print
函数,而是在当前模块中禁用print
语句的解析规则,像处理任何其他变量标识符一样处理print
,从而允许在内置函数中查找print
函数从本质上讲,Python中唯一引入新作用域的是函数定义。类是一种特殊情况,因为直接在主体中定义的任何内容都放在类的命名空间中,但它们不能从它们包含的方法(或嵌套类)中直接访问
在您的示例中,只有3个作用域将在其中搜索x:
垃圾邮件的范围-包含code3和code5中定义的所有内容(以及code4,循环变量)
全局范围-包含code1中定义的所有内容,以及Foo(以及此后的任何更改)
内置名称空间。有一点特殊——它包含各种Python内置函数和类型,如len()和str()。一般来说,这不应该被任何用户代码修改,所以希望它包含标准函数而不包含其他内容
只有在图片中引入嵌套函数(或lambda)时,才会出现更多作用域。 然而,它们的行为将与您预期的非常相似。嵌套函数可以访问本地范围内的所有内容,以及封闭函数范围内的任何内容。例如
限制:
可以访问除局部函数变量以外的作用域中的变量,但如果没有进一步的语法,则无法恢复到新参数。相反,赋值将创建一个新的局部变量,而不会影响父范围中的变量。例如:
为了从函数范围内实际修改全局变量的绑定,需要使用global关键字指定该变量为全局变量。例如:
目前没有办法对封闭函数作用域的变量执行相同的操作,但是Python 3引入了一个新的关键字“
nonlocal
”,它将以类似于全局的方式运行,但用于嵌套函数作用域相关问题 更多 >
编程相关推荐