Python范围规则到底是什么?
如果我有一些代码:
code1
class Foo:
code2
def spam.....
code3
for code4..:
code5
x()
在哪里x找到?一些可能的选择包括以下列表:
- 在随附的源文件中
- 在类命名空间中
- 在函数定义中
- 在for循环中索引变量
- 在for循环内
当函数spam传递到其他地方时,执行期间还会有上下文。也许lambda函数传递的方式有所不同?
某个地方必须有一个简单的参考或算法。对于中级Python程序员而言,这是一个令人困惑的世界。
在Python的名称解析只知道以下几种范围:
print,int,或zip,def块,lambda表达式或理解。def块,lambda表达式或理解内的函数局部作用域,class块内。值得注意的是,其他的结构,例如
if,for或with语句不会有自己的范围。TLDR范围界定:名称的查找始于使用该名称的范围,然后是所有封闭范围(不包括类范围),直至模块全局变量,最后是内置函数–使用此搜索顺序中的第一个匹配项。默认情况下,对作用域的分配是当前作用域-特殊形式
nonlocal,global必须用于从外部作用域分配名称。最后,综合起来时,理解和生成器表达式以及
:=赋值表达式具有一个特殊的规则。嵌套范围和名称解析
这些不同的作用域构建了一个层次结构,其中内置的变量然后全局变量始终构成基础,而闭包,局部变量和类作用域则按照词汇定义进行嵌套。也就是说,仅源代码中的嵌套很重要,例如调用堆栈不重要。
即使
class创建了作用域并且可能具有嵌套的类,函数和理解,class作用域的名称对于封闭的作用域也不可见。这将创建以下层次结构:Name resolution always starts at the current scope in which a name is accessed, then goes up the hierarchy until a match is found. For example, looking up
some_localinsideouter_functionandinner_functionstarts at the respective function - and immediately finds thesome_localdefined inouter_functionandinner_function, respectively. When a name is not local, it is fetched from the nearest enclosing scope that defines it – looking upsome_closureandprintinsideinner_functionsearches untilouter_functionand builtins, respectively.Scope Declarations and Name Binding
By default, a name belongs to any scope in which it is bound to a value. Binding the same name again in an inner scope creates a new variable with the same name - for example,
some_localexists separately in bothouter_functionandinner_function. As far as scoping is concerned, binding includes any statement that sets the value of a name – assignment statements, but also the iteration variable of aforloop, or the name of awithcontext manager. Notably,delalso counts as name binding.When a name must refer to an outer variable and be bound in an inner scope, the name must be declared as not local. Separate declarations exists for the different kinds of enclosing scopes:
nonlocalalways refers to the nearest closure, andglobalalways refers to a global name. Notably,nonlocalnever refers to a global name andglobalignores all closures of the same name. There is no declaration to refer to the builtin scope.Of note is that function local and
nonlocalare resolved at compile time. Anonlocalname must exist in some outer scope. In contrast, aglobalname can be defined dynamically and may be added or removed from the global scope at any time.Comprehensions and Assignment Expressions
The scoping rules of list, set and dict comprehensions and generator expressions are almost the same as for functions. Likewise, the scoping rules for assignment expressions are almost the same as for regular name binding.
The scope of comprehensions and generator expressions is of the same kind as function scope. All names bound in the scope, namely the iteration variables, are locals or closures to the comprehensions/generator and nested scopes. All names, including iterables, are resolved using name resolution as applicable inside functions.
An
:=assignment expression works on the nearest function, class or global scope. Notably, if the target of an assignment expression has been declarednonlocalorglobalin the nearest scope, the assignment expression honors this like a regular assignment.However, an assignment expression inside a comprehension/generator works on the nearest enclosing scope of the comprehension/generator, not the scope of the comprehension/generator itself. When several comprehensions/generators are nested, the nearest function or global scope is used. Since the comprehension/generator scope can read closures and global variables, the assignment variable is readable in the comprehension as well. Assigning from a comprehension to a class scope is not valid.
虽然迭代变量对于绑定它的理解是局部的,但是赋值表达式的目标不会创建局部变量,而是从外部范围读取: