Python作用域总结
来源:互联网 发布:自动对比度算法 编辑:程序博客网 时间:2024/06/04 19:56
Python特有的语法规则和诸如Java等其他静态类型语言有很大不同,而作用域规则则是其一,初识Python会遇到一些问题,现在对Python作用域相关的知识做个总结。
Python作用域规则一句话概括就是 LEGB 规则; L 代表 Local、E 代表 enclosing、G 代表 Global、B 代表 Builtin
作用域由 Python 的代码文本决定,一个模块定义了一个 Global 作用域、一个函数定义一个 Local 作用域; 作用域与一个名字空间一一对应,名字空间是一个mapping对象,它存储了当前作用域中的变量名字以及名字所绑定的对象。不同作用域中的变量名是不相关的。大概关系如下图:
假设一个模块中定义一个函数,在函数外面定义了变量a,b; 在函数中定义变量a,c, 模块本身也有Local命名空间,只是和 Global 是同一个命名空间。
除了 Global 和 Local 作用域,还有一个最顶层的作用域 – Builtin 作用域。 Builtin 作用域对应于 Builtin 命名空间,里面包含了内置函数和其他一些内置的东西。既然是系统内置的模块,地位自然非同一般,可以认为在任何模块作用域外面都有一层 Builtin 作用域。
当引用一个变量时,会首先在当前 Local 作用域的命名空间中查找,没找到就去 Global 命名空间查找,再没找到就会去 Builtin 命名空间查找,再没找到就会抛出异常。
a = 1b = 2def func(): a = 3 c = 4 print(a) #打印3 Local 中找到,直接打印 print(b) #打印2 Local 中不存在,去 Global 找 print(abs(-5)) #打印5 abs先去 Local 再去 Global找,都没找到,去 Builtin 中找 #print(haha) #报错,name 'haha' is not definedprint(a) #打印 1 直接在 Global 中找
在 func 中通过 b = 10 这样的语句是不会修改 Global 中的 b 的,而是会在 Local 命名空间中添加一个名字 ‘b’ 并绑定值为 10
要想修改 Global 中的 b, 需要这样
前面介绍了 L G B 所代表的作用域以及它们之间的关系,还有查找一个变量的顺序 L -> G -> B,下面介绍比较特殊的 E。
当在函数内部再定义一个函数时,就形成了函数嵌套,形成了闭包,而内层函数的直接外部作用域是外层函数,这块作用域就是 enclosing, 例:
a = 1def wrapper(): a = 2 def inner(): print(a) inner()wrapper() #执行这句后,会打印2
这里内层函数会先找最内层作用域,即 inner 的 Local 命名空间,没有找到则会到 wapper 的 Local 命名空间找,找到后打印,找不到时才会再往 Global 中去找。 这里在 inner 中直接去修改 wrapper 中的变量还是不起作用的,只会在inner 的 Local 命名空间中添加名字和值,要想修改 enclosing 作用域中的值,
需要这样:
在 Python2 中:
def wrapper(): a = 1 count = [a] def inner(): count[0] += 1 print 'a:', a return count[0] return innerinner = wrapper()print inner()print inner()#打印# a: 1# 2# a: 1# 3
这里是借用一个列表间接修改,实际 a 的值并没有变。
Python3中,提供了一个 nonlocal 关键字,用于直接修改闭包变量
def wrapper(): a = 1 def inner(): nonlocal a a += 1 return a return innerinner = wrapper()print(inner())print(inner())
至此所有的作用域介绍完毕,总的来说当寻找某个变量时从最内层开始找,按照
L -> E -> G -> B 的顺序逐层查找。
其他问题:
a = 1def func(): print(a) a = 1 print(a)func()
执行上面的代码会报错 UnboundLocalError: local variable ‘a’ referenced before assignment,这是因为在执行第一句 print 时直接就去 Local 中去找了,并且还找到了,但是不幸的是,当前 Local 中的 a 虽然找到了,但是还不可用,赋值语句在下面,Python 是在编译完成后,未执行程序时,就已经知道了 Local 作用域中藏着一个 a,这体现了 Python 作用域的静态性。
在作用域的问题上,只要记住以文本定义为准,而不看在哪里调用的,可以理解为在 python 解释器执行代码时,定义一个函数时,就已经将 Global 和 Local 命名空间绑定到函数对象上了,这个 Global 和 Local 就是函数执行时的环境。
另外内置函数 globals() 和 locals() 分别返回了当前 Global 命名空间和 Local 命名空间的内容。
- Python作用域总结
- python 变量作用域
- python 变量作用域
- python变量作用域
- python作用域
- python 变量作用域
- python 变量作用域
- python变量作用域
- python 变量作用域
- python变量作用域
- python的作用域
- python作用域概述
- 【Python】变量作用域
- python 变量作用域
- Python作用域陷阱
- python学习:作用域
- python 变量作用域
- Python的作用域
- Angular4
- for循环的执行顺序(案例+详解)
- C++协程库coroutine使用指南
- 机器学习笔记之(三)常用的求导公式
- hdu 1233 还是畅通工程 最小生成树
- Python作用域总结
- tcp 服务端如何判断客户端断开连接
- python tkinter grid 拉伸
- redis源码分析(2)——SDS API详解
- redis Lua脚本(二)
- 一口气搞懂《虚函数和纯虚函数》
- Python基础 itertools
- Rxjava+Retrofit+Okhttp(原理)
- 低价购买