当前位置: 首页 > news >正文

2025-08-21 Python进阶8——命名空间作用域

文章目录

  • 1 命名空间(Namespace)
    • 1.1 命名空间的定义
    • 1.2 命名空间的类型
    • 1.3 命名空间的查找顺序
    • 1.4 命名空间的生命周期
    • 1.5 命名空间实例
  • 2 作用域(Scope)
    • 2.1 作用域的定义
    • 2.2 作用域的类型(LEGB 规则)
    • 2.3 作用域实例
    • 2.4 作用域的特殊说明
  • 3 全局变量和局部变量
    • 3.1 全局变量(Global Variables)
    • 3.2 局部变量(Local Variables)
    • 3.3 全局变量与局部变量的冲突
  • 4 global 和 nonlocal
    • 4.1 global 关键字
    • 4.2 nonlocal 关键字
    • 4.3 常见错误与解决
  • 5 总结

1 命名空间(Namespace)

1.1 命名空间的定义

命名空间是从名称到对象的映射,大多数命名空间通过 Python 字典实现。它的主要作用是避免名称冲突,不同命名空间中的同名名称不会相互干扰。

可以将命名空间类比为文件系统:

  • 每个文件夹(命名空间)中不能有相同的文件名(名称)
  • 不同文件夹(命名空间)中可以有相同的文件名(名称)

1.2 命名空间的类型

Python 中主要有三种命名空间:

  • 内置名称(built-in names)
    • Python 语言内置的名称
    • 例如:函数名 abs()print();异常名称 BaseExceptionException
    • 这些名称在 Python 解释器启动时就存在
  • 全局名称(global names)
    • 模块中定义的名称
    • 包括:函数、类、导入的模块、模块级变量和常量
    • 在模块被加载时创建,通常持续到解释器退出
  • 局部名称(local names)
    • 函数或类中定义的名称
    • 包括:函数参数、局部变量、内部函数等
    • 在函数 / 类被调用时创建,在执行结束后销毁

1.3 命名空间的查找顺序

当使用一个名称时,Python 会按以下顺序查找:

  1. 局部命名空间(当前函数 / 类内部)
  2. 全局命名空间(当前模块)
  3. 内置命名空间(Python 内置)

如果在所有命名空间中都找不到该名称,会引发 NameError 异常:

print(undefined_variable)  # 报错:NameError: name 'undefined_variable' is not defined

1.4 命名空间的生命周期

  • 内置命名空间:在 Python 解释器启动时创建,直到解释器退出时销毁
  • 全局命名空间:在模块被导入时创建,通常直到解释器退出时销毁
  • 局部命名空间:在函数 / 类被调用时创建,在执行结束后销毁

特点:无法从外部命名空间访问内部命名空间的对象

1.5 命名空间实例

# 全局命名空间
var1 = 5def some_func():# 局部命名空间(some_func的)var2 = 6def some_inner_func():# 局部命名空间(some_inner_func的)var3 = 7

2 作用域(Scope)

2.1 作用域的定义

作用域是 Python 程序中可以直接访问某个命名空间的文本区域。“直接访问” 指无需使用前缀即可引用名称。

2.2 作用域的类型(LEGB 规则)

Python 中有四种作用域,遵循 LEGB 查找顺序

  • L(Local,局部作用域)
    • 最内层作用域
    • 包含当前函数 / 方法内部定义的变量
    • 例如:函数的参数、在函数内定义的变量
  • E(Enclosing,嵌套作用域)
    • 包含非局部也非全局的变量
    • 适用于嵌套函数场景,指外层函数的作用域
    • 例如:函数 A 中定义了函数 B,则 A 的作用域对 B 来说是嵌套作用域
  • G(Global,全局作用域)
    • 当前模块的最外层作用域
    • 包含模块级别的变量、函数、类等
  • B(Built-in,内置作用域)
    • 包含 Python 内置的名称
    • 最后被搜索的作用域

查找顺序:Local → Enclosing → Global → Built-in

2.3 作用域实例

g_count = 0  # 全局作用域(G)def outer():o_count = 1  # 嵌套作用域(E,对于inner来说)def inner():i_count = 2  # 局部作用域(L)print(i_count)  # 查找顺序:L → E → G → Binner()
outer()

2.4 作用域的特殊说明

  • 只有模块、类、函数(deflambda)会创建新的作用域

  • 以下代码块

    不会

    创建新的作用域:

    • if/elif/else 条件语句
    • try/except 异常处理语句
    • for/while 循环语句
    • with 语句
    • 代码块({}

实例

# if语句不会创建新作用域
if True:msg = 'Hello'
print(msg)  # 可以访问,输出:Hello# 循环语句不会创建新作用域
for i in range(3):num = i
print(num)  # 可以访问,输出:2

3 全局变量和局部变量

3.1 全局变量(Global Variables)

  • 定义在函数外部的变量
  • 可以在整个模块中被访问(函数内外均可)
  • 如果函数内部没有同名局部变量,函数可以直接访问全局变量
x = 10  # 全局变量def my_function():print(x)  # 可以访问全局变量my_function()  # 输出:10

3.2 局部变量(Local Variables)

  • 定义在函数内部的变量
  • 仅在定义它的函数内部有效
  • 函数外部无法访问
  • 优先级高于全局变量(同名时优先使用局部变量)
def my_function():x = 5  # 局部变量print(x)  # 访问局部变量my_function()  # 输出:5
print(x)  # 报错:NameError: name 'x' is not defined

3.3 全局变量与局部变量的冲突

当函数内部存在与全局变量同名的局部变量时,局部变量会覆盖全局变量:

total = 0  # 全局变量def sum(arg1, arg2):total = arg1 + arg2  # 局部变量,与全局变量同名print("函数内(局部):", total)  # 输出:30return totalsum(10, 20)
print("函数外(全局):", total)  # 输出:0(全局变量未被修改)

4 global 和 nonlocal

4.1 global 关键字

用于在函数内部修改全局变量,声明变量为全局变量:

num = 1  # 全局变量def fun1():global num  # 声明num为全局变量print(num)  # 输出:1num = 123   # 修改全局变量print(num)  # 输出:123fun1()
print(num)  # 输出:123(全局变量已被修改)

注意:如果在函数中仅读取全局变量而不修改,不需要使用 global 声明

4.2 nonlocal 关键字

用于在嵌套函数中修改外层函数的变量(非全局变量):

def outer():num = 10  # 外层函数的变量def inner():nonlocal num  # 声明num为外层函数的变量num = 100     # 修改外层函数的变量print(num)    # 输出:100inner()print(num)  # 输出:100(外层变量已被修改)outer()

4.3 常见错误与解决

尝试在函数中修改全局变量而不使用 global 声明:

a = 10def test():a = a + 1  # 错误:试图修改全局变量但未声明print(a)test()  # 报错:UnboundLocalError: local variable 'a' referenced before assignment

解决方法

a = 10def test():global a  # 声明为全局变量a = a + 1print(a)  # 输出:11test()

5 总结

  1. 命名空间是名称到对象的映射,避免名称冲突,主要有三种类型:内置、全局、局部
  2. 作用域是可以直接访问命名空间的区域,遵循 LEGB 查找规则
  3. 全局变量在函数外定义,可在整个模块访问;局部变量在函数内定义,仅在函数内有效
  4. global 关键字用于在函数内修改全局变量
  5. nonlocal 关键字用于在嵌套函数中修改外层函数的变量
  6. 只有模块、类、函数会创建新的作用域,其他代码块不会
http://www.xdnf.cn/news/1340857.html

相关文章:

  • gRPC 与 HTTP 性能对比分析
  • 微算法科技(NASDAQ:MLGO)构建去中性化区块链预言机,实现跨链信息互通
  • 使用 X11 转发服务器界面
  • 整体设计 之定稿 “凝聚式中心点”原型 --整除:智能合约和DBMS的在表层挂接 能/所 依据的深层套接 之2
  • 迅为R3568开发板OpeHarmony学习开发手册-配置远程访问环境
  • Typescript入门-函数讲解
  • 面试后的跟进策略:如何提高录用几率并留下专业印象
  • Shell 变量全解析:从基础到高级技巧
  • C语言基础习题——01
  • mac的m3芯片安装JDK8、JDK17
  • QWidget/QMainWindow与QLayout的布局
  • 家里Windows,公司Linux?通过cpolar,WSL开发环境无缝切换
  • 【STM32】HAL库中的实现(九):SPI(串行外设接口)
  • 智能求职推荐系统演示说明
  • 封装FTPSClient连接ftps服务器
  • 27、设备状态监测与维护管理 (模拟电机振动) - /安全与维护组件/device-condition-monitoring
  • 【用户管理】修改文件权限
  • DeepSeek V3.1正式发布,专为下代国产芯设计
  • opencv学习:图像边缘检测
  • 8.21IPSEC安全基础后篇,IKE工作过程
  • 基于Matlab的饮料满瓶检测图像处理
  • 面试压力测试破解:如何从容应对棘手问题与挑战
  • 火语言 RPA 进阶功能:让自动化更实用​
  • 利用DeepSeek编写调用系统命令用正则表达式替换文件中文本的程序
  • vmware安装centos7
  • 大数据毕业设计选题推荐-基于大数据的鲍鱼多重生理特征数据可视化分析系统-Spark-Hadoop-Bigdata
  • 代码随想录算法训练营27天 | ​​56. 合并区间、738.单调递增的数字、968.监控二叉树(提高)
  • 嵌入式-中断的概念,优先级,编程-Day17
  • 亚马逊站外推广效能重构:自然排名提升的逻辑与实操边界
  • 底层逻辑颠覆者:Agentic BI如何通过“Data + AI Agent”架构重构数据价值链?