作用域与命名空间——nonlocal、global的用法

本文详细介绍了Python中的命名空间和作用域概念,包括命名空间的实现方式、作用域的搜索顺序、不同命名空间的生存期。通过示例代码展示了`global`和`nonlocal`关键字的使用,以及如何在函数内部访问和修改外部变量。同时,文章还提供了利用闭包创建计数器函数的示例,进一步阐述了命名空间和作用域的应用。
摘要由CSDN通过智能技术生成

作用域与命名空间

命名空间:是一个从名字到对象的映射
作用域:一个命名空间可直接访问的 Python 程序的文本区域

几条规则

  • 命名空间当前是用字典实现(笔者所用为python 3.8),函数、类、模块都有自己的命名空间。
  • 模块中的名称为全局名称,函数内定义的名称为通常为局部名称。
  • 当存在多个命名空间的时候(通常是3到4个),嵌套作用域搜索顺序遵循:最内层的作用域包含局部名称 > 外层作用域包含非局部名称和非全局名称 > 倒数第二层作用域包含模块的全局名称 > 最外层的作用域为包含内置名称。当然这一搜索顺序会被global和nonlocal声明所改变。

不同命名空间的生存期

  • 包含内置名称的命名空间是在 Python 解释器启动时创建的,永远不会被删除。
  • 模块的全局命名空间在模块定义被读入时创建;通常,模块命名空间也会持续到解释器退出。
  • 被解释器的顶层调用执行的语句,从一个脚本文件读取或交互式地读取,被认为是 main 模块调用的一部分,因此它们拥有自己的全局命名空间。
  • 一个函数的本地命名空间在这个函数被调用时创建,并在函数返回或抛出一个不在函数内部处理的错误时被删除。当然,每次递归调用都会有它自己的本地命名空间。
    !!!因此,无法从外部命名空间访问内部命名空间的对象,。

nonlocal和global的用法

如果不存在生效的 global 或 nonlocal 语句 – 则对名称的赋值总是会进入最内层作用域。
global 语句:要重新绑定在全局作用域中找到的变量,可以使用 global 语句声明为全局变量,再进行绑定。
nonlocal 语句:要重新绑定在最内层作用域以外找到的变量,可以使用 nonlocal 语句声明为非本地变量,再进行绑定。

# 示例代码1
def scope_test():
    def do_local():
        spam = "local spam"

    def do_nonlocal():
        nonlocal spam
        spam = "nonlocal spam"

    def do_global():
        global spam
        spam = "global spam"

    spam = "test spam" # 在外层作用域创建了局部变量spam
    do_local() #在最内层的作用域中创建了局部变量spam,执行完即关闭
    print("After local assignment:", spam) # 打印局部变量spam,外层的局部变量和最内层的嵌套局部变量spam虽然同名但绑定到了不同的值,而且最内层的局部命名空间已关闭,无法访问。
    do_nonlocal() # 将在外层作用域作用域中找到的名称spam绑定到新值
    print("After nonlocal assignment:", spam) # 打印当前局部变量spam
    do_global() # 创建全局变量spam
    print("After global assignment:", spam) # 在函数体内,引用当前作用域

scope_test()
print("In global scope:", spam) # 函数体之外,无法访问内部对象,所以引用当前模块的spam变量——全局变量

# 输出
After local assignment: test spam
After nonlocal assignment: nonlocal spam
After global assignment: nonlocal spam
In global scope: global spam
# 示例代码二
# 利用闭包返回一个计数器函数,每次调用它返回递增整数:

# -*- coding: utf-8 -*-
def createCounter():
    num = 0
    def counter():
        nonlocal num #重新绑定在最内层作用域以外找到的变量num需要申明为nonlocal
        num =+ num + 1
        return num
    return counter

# 测试:
counterA = createCounter()
print(counterA(), counterA(), counterA(), counterA(), counterA()) # 1 2 3 4 5
counterB = createCounter()
if [counterB(), counterB(), counterB(), counterB()] == [1, 2, 3, 4]:
    print('测试通过!')
else:
    print('测试失败!')

廖雪峰老师的Python教程-返回函数
Python官方文档-Python作用域与命名空间
菜鸟教程-Python3 命名空间和作用域

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值