高手也容易忽略的 Python 命名空间与作用域

想学好 Python ,一定要掌握变量作用域,因为它会像幽灵👻一样,时不时跳出来吓你一跳。你是不是遇到过这种情况:

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 文件的最外层)定义的变量、函数等。
  • 局部命名空间(Local Namespace):函数内部定义的变量、参数等。

简单理解:

  • 内置命名空间 是 Python 自带的词典。
  • 全局命名空间 是你写的 .py 文件中的变量字典。
  • 局部命名空间 是函数内部专属的小字典。

来看个示例:

python 复制代码
# 全局命名空间
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 规则,即:

  1. Local(局部作用域):当前函数内部的命名空间。
  2. Enclosing(闭包作用域):嵌套函数(函数里面再定义函数)外层函数的命名空间。
  3. Global(全局作用域):当前模块的命名空间。
  4. Built-in(内置作用域):Python 预定义的命名空间。

如果 Python 需要访问一个变量,它会按照 LEGB 顺序查找。来看个案例:

python 复制代码
x = "全局变量"

def outer():
    x = "外部函数变量"
    
    def inner():
        x = "内部函数变量"
        print(x)  # 优先找最近的 x
    
    inner()
    print(x)  # 找不到 inner 里的 x,找外部函数的

outer()
print(x)  # 直接找全局的

先别急着看结果,仔细思考下会输出什么?相信好多人会栽在这里 | | | | | | | | | V

输出结果:

复制代码
内部函数变量
外部函数变量
全局变量

这个例子很清楚地展示了 LEGB 规则。Python 先找局部变量(Local),找不到就往外层找,一直找到内置命名空间为止。

3. globalnonlocal 关键字

有时候我们希望在函数内部修改外部变量,比如:

python 复制代码
x = 10

def change_global():
    global x  # 说明我们要修改全局变量 x
    x = 20

change_global()
print(x)  # 20

如果你不加 globalx = 20 只会创建一个新的局部变量,不会影响全局 x

类似的,nonlocal 用来修改闭包作用域的变量:

python 复制代码
def outer():
    x = "外部变量"
    
    def inner():
        nonlocal x  # 说明我们要修改外部函数的 x
        x = "修改后的变量"
    
    inner()
    print(x)  # "修改后的变量"

outer()

如果不加 nonlocalinner() 里改的 x 只是一个新的局部变量,不会影响 outer() 里的 x

4. 常见作用域坑

4.1 for 循环里的变量是全局的!

python 复制代码
for i in range(5):
    pass

print(i)  # 4 (在别的语言里可能报错)

Python 里 for 循环变量 i 是全局的,循环结束后仍然存在!

4.2 默认参数的坑

python 复制代码
def func(x=[]):
    x.append(1)
    print(x)

func()  # [1]
func()  # [1, 1](惊不惊喜?)

原因是默认参数 x=[] 只初始化一次,后续调用会复用这个列表!

5. 总结

  • Python 的命名空间可以理解成存变量的字典,有 内置、全局、局部 三种。
  • Python 遵循 LEGB 规则 查找变量,从局部到全局依次查找。
  • global 关键字用来修改全局变量,nonlocal 关键字用来修改闭包变量。
  • for 循环变量是全局的,不像其他语言会自动销毁。
  • 默认参数的可变对象会复用,导致意外行为。

希望这篇文章能让你彻底搞清楚 Python 的作用域和命名空间!下次遇到变量找不到的问题,就从 LEGB 规则入手排查吧!🎉

相关推荐
我爱吃干果6 分钟前
ZoomCharts使用方法
前端·javascript·笔记·zoom
〆、风神11 分钟前
Spring Boot 自定义 Redis Starter 开发指南(附动态 TTL 实现)
spring boot·redis·后端
Yharim16 分钟前
wxPython官方文档中文翻译 - TipProvider概述
python
旧厂街小江16 分钟前
LeetCode 第111题:二叉树的最小深度
前端·算法·程序员
&白帝&17 分钟前
vue实现大转盘抽奖
前端·javascript·vue.js
Asthenia041218 分钟前
HashMap 扩容机制与 Rehash 细节分析
后端
DataFunTalk19 分钟前
不是劝退,但“BI”基础不佳就先“别搞”ChatBI了!
前端·后端
星星电灯猴20 分钟前
flutter项目 发布Google Play
后端
古德奈特24 分钟前
npm 和 npx 的区别详解
前端
猿榜25 分钟前
深入浅出 Python 面向对象编程
javascript·python