变量作用域规则

1|0全局变量


定义一个函数,它读取两个变量的值:一个是局部变量a,是函数的参数,另一个是变量b,这个函数没有定义它

def f1(a): print(a) print(b) print(f1(3)) # 运行结果 3 Traceback (most recent call last): File "E:/virtual_workshop/everyday/test/f1.py", line 6, in <module> print(f1(3)) File "E:/virtual_workshop/everyday/test/f1.py", line 3, in f1 print(b) NameError: name 'b' is not defined

出现这样的错误并不奇怪,因为全局变量b并没有赋值,使用dis反汇编一下,可以看到是往栈里load了全局变量b

from dis import dis print(dis(f1)) # 运行结果 2 0 LOAD_GLOBAL 0 (print) 2 LOAD_FAST 0 (a) 4 CALL_FUNCTION 1 6 POP_TOP 3 8 LOAD_GLOBAL 0 (print) 10 LOAD_GLOBAL 1 (b) #往栈里load了全局变量b 12 CALL_FUNCTION 1 14 POP_TOP 16 LOAD_CONST 0 (None) 18 RETURN_VALUE None

怎么优化这个程序?只需要先给全局变量b赋值,然后再调用f

def f1(a): print(a) print(b) b = 6 print(f1(3)) # 运行结果 3 6 None

2|0局部变量


下面的f2函数,先给b赋值,然后再打印a和b的值

b = 6 def f2(a): print(a) print(b) b = 9 #局部变量 print(f2(3)) # 运行结果 3 Traceback (most recent call last): File "E:/virtual_workshop/everyday/test/f2.py", line 9, in <module> print(f2(3)) File "E:/virtual_workshop/everyday/test/f2.py", line 6, in f2 print(b) UnboundLocalError: local variable 'b' referenced before assignment

为什么会出现这样的情况呢,因为Python编译函数的时候,它判定b是局部变量,因为在函数中给它赋值了。生成的字节码正事了这种判断,Python会尝试从本地环境获取b。后面调用f2(3)时,f2的定义体会获取并打印局部变量a的值,但是尝试获取局部变量b的值时,发现b没有绑定值。这不是缺陷,而是设计选择:Python不要求声明变量,但是假定在函数体中赋值的变量是局部变量。使用dis反汇编一下,可以看到加载的b是局部变量

5 0 LOAD_GLOBAL 0 (print) 2 LOAD_FAST 0 (a) 4 CALL_FUNCTION 1 6 POP_TOP 6 8 LOAD_GLOBAL 0 (print) 10 LOAD_FAST 1 (b) #往栈里load了局部变量b 12 CALL_FUNCTION 1 14 POP_TOP 7 16 LOAD_CONST 1 (9) 18 STORE_FAST 1 (b) 20 LOAD_CONST 0 (None) 22 RETURN_VALUE None

如果在函数中赋值时想让解释器把b当做全局变量,需要用global声明:

b = 6 def f2(a): global b print(a) print(b) b = 9 #局部变量 # 运行结果 3 6 None

3|0参考书籍


《流畅的Python》


__EOF__

本文作者cnhkzyy
本文链接https://www.cnblogs.com/my_captain/p/12843358.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   cnhkzyy  阅读(236)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示