Python自学成才之路 彻底搞懂python变量作用域
python 作用域分成四种 L(Local):最内层,包含局部变量,比如一个方法内部。 E(Enclosing):包含了非局部(non-local)也非全局(non-global)的变量。比如两个嵌套函数,一个函数(或类) A 里面又包含了一个函数 B ,那么对于 B 中的名称来说 A 中的作用域就为 nonlocal。 G(Global):当前脚本的最外层,比如当前模块的全局变量。 B(Built-in):包含了内建的变量/关键字等。,最后被搜索
看个案例:
# 全局变量
num = 30
def outer():
# 嵌套变量
num = 20
def inner():
# 局部变量
num = 10
print(num)
inner()
outer()
这个案例里面,第一个num是全局变量,第二个是局部变量,第三个是嵌套变量。内建变量这里没有,内建变量都是python系统内部定义好的变量。
变量的访问顺序遵循LEGB原则 L(局部)> E(内嵌)> G(全局)> B(内建)。这里的变量类型是一个相对的概念,第三个num相对于inner这个函数是局部变量,第二个num相对于inner是局部变量。所以是否是局部变量是相对于当前的作用域而言的。而能创建作用域的只有模块,类和函数。其它的代码块(如 if/elif/else/、try/except、for/while等)是不会引入新的作用域的,也就是说这些语句内定义的变量,外部也可以访问,比如下面的例子:
if True:
num = 10
num+=1
print(num)
虽然变量有四种类型,但是访问一个变量可以简单的分为两种类型,局部变量和非局部变量。如果是局部变量,则在当前作用域访问的就是该局部变量,如果是非局部变量访问的就是离改作用域最近的局部变量,这个最近遵循LEGB原则。
看下面这个案例:
arg1 = 100
arg2 = 15
def funtion1():
arg1 = 90
arg2 = 10
def inner_function1():
print(arg1)
arg2 = 99
print(arg2)
arg3 = arg1 + arg2
print(arg3)
inner_function1()
funtion1()
输出:
90
99
189
这个案例里面输出的arg1是非局部变量,根据LEGB原则arg1应该是90。arg2是局部变量,输出99。
再看下面这个案例:
# 全局变量
num = 30
def outer():
# 局部变量
num = 20
def inner():
# 嵌套变量
num = num + 1
print(num)
inner()
outer()
这个案例会输出什么?什么都不会输出,直接报错,语法都过不了。如果改成下面这个样子就不会报错。
# 全局变量
num = 30
def outer():
# 局部变量
num = 20
def inner():
# 嵌套变量
num = 1
print(num)
inner()
outer()
原因就在num = num + 1这里,如果是num = 1 ,那num是局部变量。同样num = num + 1这里num也是局部变量,但是局部变量还没任何值,然后又做加1操作,语法上就是错误的。那如何让num = num + 1有效呢?可以使用nonlocal。nonlocal的使用后面会介绍。
上面介绍的都是脚本里面的局部变量,类里面的变量和脚本不一样。看下面这个案例:
# 全局变量
num = 10
class GlobalDemo(object):
num = 15
def __init__(self, num):
self.num = num
def add(self):
global num
num += 1
def getTotal(self):
return num
globalDemo = GlobalDemo(1)
globalDemo.add()
print(globalDemo.getTotal())
输出:
11
上面这个案例最后输出结果是11,因为返回的num是全局变量。如果getTotal方法改成下面这种形式:
def getTotal(self):
return self.num
输出结果是1,这个时候访问的是示例属性,再改成下面这种形式:
def getTotal(self):
return GlobalDemo.num
输出结果是15,这个时候访问的是类属性。
类里面访问的变量判断方法其实和脚本是一样的,但是首先要把实例属性和类属性区分出来,有self的是实例属性,带‘类名.’的是类属性(可以看我前面的文章),如果既不是实例属性也不是类属性,那访问判断方式和脚本是一样的。
global和nonlocal关键字 如果想要指定访问的变量是全局变量可以使用global关键字
num = 10
def myFunction():
global num
num = num + 1
myFunction()
print(num)
输出:
11
如果是在函数嵌套里面想要使用外层函数的变量,则要用nonlocal关键字。
# 全局变量
num = 30
def outer():
# 局部变量
num = 20
def inner():
# 嵌套变量
nonlocal num
num = num + 1
print(num)
inner()
outer()
输出:
21
这里如果把nonlocal改为global输出的结果就是31。所以global和nonlocal的区别就是,global是争对全局变量,nonlocal是争对嵌套函数里面的上级变量。
总结一下:访问一个变量前需要先知道这个变量是什么变了,局部还是非局部,如果是非局部,则根据LEGB原则访问的就是最近的非局部变量。如果想指定访问的是哪个变量,全局可以使用global关键字,嵌套函数上级变量可以使用nonlocal关键字。
- Windows下Thumbnail的开发总结
- 剑指OFFER之调整数组顺序使奇数位于偶数前面找(九度OJ1516)
- Linux架构
- 绘图: Python matplotlib简介
- 绘图: matplotlib Basemap简介
- GridView实战二:使用ObjectDataSource数据源控件(自定义缓存机制实现Sort)
- 把孩子打造成为码农
- 分享基于Qt5开发的一款故障波形模拟软件
- 剑指OFFER之打印1到最大的N位数(九度OJ1515)
- GridView实战二:使用ObjectDataSource数据源控件
- javascript实例:逐条记录停顿的走马灯
- Python标准库05 存储对象 (pickle包,cPickle包)
- macOS平台下虚拟摄像头的研发总结
- 网页优化系列三:使用压缩后置viewstate
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- 如何编写不存在即插入的 SQL
- SQL 打印一个月的日历
- Kubernetes节点的驱逐与预留
- 使用reveal.js制作精美的网页版PPT
- Ceph快照爱你不容易系列 03:快照数据一致性浅析
- 没想到竟是因为它!让我的服务器变成了别人的挖矿工具
- 从零到一,Serverless 平台在滴滴内部落地
- React 使用 Proxy 代理(create-react-app)
- .Net Core + EF + mysql 从数据库生成实体
- Git 常用命令
- Nodejs 一些细节 (持续更新)
- Jenkins 凭据使用
- React源码解读【一】API复习与基础
- choco 安装 和 mkcert 本地https
- js 函数柯里化(Currying)