高手也容易忽略的 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 规则入手排查吧!🎉

相关推荐
yunsr1 分钟前
python作业3
开发语言·python
历程里程碑3 分钟前
普通数组-----除了自身以外数组的乘积
大数据·javascript·python·算法·elasticsearch·搜索引擎·flask
曦月逸霜3 分钟前
Python快速入门——学习笔记(持续更新中~)
笔记·python·学习
摸鱼的春哥3 分钟前
春哥的Agent通关秘籍07:5分钟实现文件归类助手【实战】
前端·javascript·后端
喵手6 分钟前
Python爬虫实战:采集菜谱网站的“分类/列表页”(例如“家常菜”或“烘焙”频道)数据,构建高可用的美食菜谱数据采集流水线(附CSV导出)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集菜谱网站数据·家常菜或烘焙频道·构建高可用食谱数据采集系统
念念不忘 必有回响7 分钟前
viepress:vue组件展示和源码功能
前端·javascript·vue.js
喵手7 分钟前
Python爬虫实战:硬核解析 Google Chrome 官方更新日志(正则+文本清洗篇)(附 CSV 导出)!
爬虫·python·爬虫实战·零基础python爬虫教学·csv导出·监控谷歌版本发布历史·获取稳定版更新日志
小邓睡不饱耶9 分钟前
实战|W餐饮平台智能化菜品推荐方案(含Spark实操+算法选型+完整流程)
python·ai·ai编程·ai写作
草莓熊Lotso12 分钟前
Qt 主窗口核心组件实战:菜单栏、工具栏、状态栏、浮动窗口全攻略
运维·开发语言·人工智能·python·qt·ui
C澒12 分钟前
多场景多角色前端架构方案:基于页面协议化与模块标准化的通用能力沉淀
前端·架构·系统架构·前端框架