马上注册,结交更多好友,享用更多功能^_^
您需要 登录 才可以下载或查看,没有账号?立即注册
x
想学好 Python ,一定要掌握变量作用域,因为它会像幽灵一样,时不时跳出来吓你一跳。你是不是遇到过这种情况:x = 10
def func():
print(x)
func() # 还能跑
def func2():
print(y)
y = 20
func2() # 报错!UnboundLocalError: local variable 'y' referenced before assignment
同样是 print(x),x 正常输出,而 y 却报错了?Python 你是不是针对我?!别慌,今天我们就来彻底搞清楚 Python 的命名空间(Namespace)和作用域(Scope),保证你下次见到类似问题不再抓狂。
1. 什么是命名空间?
命名空间(Namespace) 就是一个存储变量名和对应值的地方,可以理解成一个大字典,里面存着所有变量的名称和它们的值。
Python 里的命名空间主要有三类:
●内置命名空间(Built-in Namespace):Python 自带的,比如 print()、len() 这些常用函数。
●全局命名空间(Global Namespace):在模块层级(也就是 .py 文件的最外层)定义的变量、函数等。局部命名空间(LocalNamespace):函数内部定义的变量、参数等。简单理解:内置命名空间 是 Python 自带的词典。
●全局命名空间 是你写的 .py 文件中的变量字典。局部命名空间 是函数内部专属的小字典。来看个示例:
# 全局命名空间
global_var = "我是全局变量"
def my_func():
# 局部命名空间
local_var = "我是局部变量"
print(local_var)
print(global_var) # ✅ 正常打印
my_func() # ✅ 正常打印
print(local_var) # ❌ NameError: name 'local_var' is not defined
函数 my_func() 里面的 local_var 只能在函数内访问,出了函数就不认识了。
2. 什么是作用域?
作用域(Scope)决定了变量能在代码的哪些位置被访问。Python 遵循 LEGB 规则,即:
Local(局部作用域):当前函数内部的命名空间。
Enclosing(闭包作用域):嵌套函数(函数里面再定义函数)外层函数的命名空间。
Global(全局作用域):当前模块的命名空间。
Built-in(内置作用域):Python 预定义的命名空间。
如果 Python 需要访问一个变量,它会按照 LEGB 顺序查找。来看个案例:x = "全局变量"
def outer():
x = "外部函数变量"
def inner():
x = "内部函数变量"
print(x) # 优先找最近的 x
inner()
print(x) # 找不到 inner 里的 x,找外部函数的
outer()
print(x) # 直接找全局的
先别急着看结果,仔细思考下会输出什么?相信好多人会栽在这里
输出结果
这个例子很清楚地展示了 LEGB 规则。Python 先找局部变量(Local),找不到就往外层找,一直找到内置命名空间为止。3. global 和 nonlocal 关键字有时候我们希望在函数内部修改外部变量,比如:x = 10
def change_global():
global x # 说明我们要修改全局变量 x
x = 20
change_global()
print(x) # 20
如果你不加 global,x = 20 只会创建一个新的局部变量,不会影响全局 x。类似的,nonlocal 用来修改闭包作用域的变量:def outer():
x = "外部变量"
def inner():
nonlocal x # 说明我们要修改外部函数的 x
x = "修改后的变量"
inner()
print(x) # "修改后的变量"
outer()
如果不加 nonlocal,inner() 里改的 x 只是一个新的局部变量,不会影响 outer() 里的 x。 4. 常见作用域坑4.1 for 循环里的变量是全局的!for i in range(5):
pass
print(i) # 4 (在别的语言里可能报错)
Python 里 for 循环变量 i 是全局的,循环结束后仍然存在!4.2 默认参数的坑def func(x=[]):
x.append(1)
print(x)
func() # [1]
func() # [1, 1](惊不惊喜?)
原因是默认参数 x=[] 只初始化一次,后续调用会复用这个列表! 5. 总结 ●Python 的命名空间可以理解成存变量的字典,有 内置、全局、局部 三种。 ●Python 遵循 LEGB 规则 查找变量,从局部到全局依次查找。global 关键字用来修改全局变量,nonlocal 关键字用来修改闭包变量。 ●for 循环变量是全局的,不像其他语言会自动销毁。 ●默认参数的可变对象会复用,导致意外行为。 希望这篇文章能让你彻底搞清楚 Python 的作用域和命名空间!下次遇到变量找不到的问题,就从 LEGB 规则入手排查吧! 转自:花小姐的春天
|