Python作用域基础
当在程序中使用变量名时,Python创建、改变或查找变量名都是在所谓的命名空间中进行的。作用域这个术语指的就是命名空间。在代码中变量名被赋值的位置决定了变量名能被访问到的范围
- 所有的变量名,包括作用域的定义在内,都是Python赋值的时候生成的。Python中的变量名在第一次赋值时已经创建,并且必须经过赋值后才能使用。
- 在代码中给一个变量赋值的地方决定了这个变量将存在哪个命名空间,也就是可见范围
函数的作用域
-
在默认情况下,一个函数的所有变量名都是与函数的命名空间相关联的
* 一个在def内定义的变量名能够被def内的代码使用,不能再函数的外部引用这样的变量名
* def之中的变量名与def之外的变量名并不冲突,即使变量名相同也不会冲突。一个在def之外被赋值的变量x与在这个def之中的赋值的变量x时完全不同的变量 -
如果一个变量在def内赋值,则它被定位在这个函数之内
-
如果一个变量在一个嵌套def中赋值,则对于嵌套函数来说,它是非本地的
-
如果在def之外赋值,它就是整个文件全局的
作用域法则
- 函数定义了本地作用域,模块定义了全局作用域
* 内嵌的模块是全局作用域,每个模块都是一个全局作用域。
* 全局作用域的作用范围仅限于单个文件,是指在一个文件的顶层的变量名仅对于这个文件内部的代码而言是全局的。必须精确的导入一个模块文件才能够使用这个文件中定义的变量名
* 每次对函数的调用都创建了一个新的本地作用域,函数只要被调用,就会重新创建函数内的本地作用域
* 赋值的变量名除非声明为全局变量或非本地变量否则均为本地变量。默认情况下,所有函数定义内部的变量都是本地作用域。
* 如果需要给一个在函数内部却位于模块文件顶层的变量名赋值,需要在函数内部通过global语句声明
* 如果需要给位于一个嵌套的def中的名称赋值,在Python3.0开始可以通过在一条nonlocal语句中声明
作用域的产生
在Python中,只有函数(def) 类(class) 模块(module)才会引入新的作用域,其他的代码块不会产生新的作用域
变量名解析:LEGB原则
- L local 函数中定义的变量
- E enclosing 嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部作用域,但不是全局的;
- G global 全局变量 模块级别定义的变量
- B built-in 系统固定模块里面的变量,比如int, bytearray等
**Python搜索变量的作用域的优先级是:局部作用域>嵌套作用域>全局变量作用域>内置作用域
对于一个def语句 - 变量名引用分为四个作用域进行查找:首先是本地作用域(L),之后是上一层结构中的def或lambda的本地作用域(E),然后是全局作用域(G),最后是Python内置作用域(B),在找到这个变量名后会停止搜索,如果没有找到会报错
- 在默认情况下,变量名赋值会创建或者改变本地变量
- 全局声明和非本地声明将赋值的变量名映射到模块文件内部的作用域
>>> # Global scope
>>> X = 99
>>> def func(Y):
... Z=X+Y
... return Z
>>> fun(1)
>>> func(1)
100
内置作用域
- 内置作用域仅仅是一个名为builtin的内置模块,但是必须要导入后才能使用内置作用域
- 内置作用域是通过一个名为builtin的标准库模块来实现的,没有放置在作用域内,必须导入这个文件才能使用
LEGB 存在的问题
由于LEGB查找的流程,会使它在找到第一处变量名的地方生效,在本地作用域的变量名可能会覆盖在全局作用域和内置作用域的有着相同变量名的变量。全局变量名可能副高内置的变量名
- 如果在def内不增加global(nonlocal)声明的话,是没有办法在函数内改变函数外部的变量
locals() globals()
- locals() 返回一个局部命名空间内容的字典
- globals() 返回一个全局命名空间内容的字典
>>> animal = 'fruitbat'
>>> def change_local():
... animal = 'wombat'
... print('locals',locals())
...
>>> animal
'fruitbat'
>>> change_local()
locals {'animal': 'wombat'}
>>> print('globals',globals())
globals {'__name__': '__main__', '__doc__': None, '__package__': None, '__loader__':
>>> animal
'fruitbat'
名称中 和_用法
Python中以两个下划线__开头和结束的名称都是Python的保留用法。因此在自定义的变量中不能使用它们
网友评论