Python之变量作用域、Closure闭包

这里介绍Python变量作用域中的global关键字和nonlocal关键字、Closure闭包

Python之变量作用域、Closure闭包
abstract.png

global关键字

在内层作用域(比如,函数中),如果对全局变量进行读取/修改, 可通过global关键字来声明该变量是一个全局变量。其实如果只是读取变量不修改的话,当内层作用域找不到变量定义时,其会到外层作用域去找。需要注意的是,如果在内层作用域定义了一个与全局变量同名的局部变量,则在内层作用域操作的是局部变量,而不是全局变量

print("----------- 变量作用域 -----------------------")

# 全局变量
b = 1000

def f1(a): 
    print(f"[f1]: a -->> {a}")
    # 只读不修改时,当内层作用域找不到变量b时,其会到外层作用域去找 
    print(f"[f1]: b -->> {b}")

def f2(a): 
    print(f"[f2]: a -->> {a}")
    # 内层作用域定义的变量(即使其与全局变量同名)为局部变量
    b = 22
    print(f"[f2]: b -->> {b}")

def f3(a): 
    # 如果确实想在内层作用域中对全局变量进行修改, 可通过global关键字来声明变量是一个全局变量
    global b
    print(f"[f3]: a -->> {a}")
    print(f"[f3]: b -->> {b}")
    b = 500
    print(f"[f3]: after modify, b -->> {b}")


print("n--------------- Test f1 函数 ---------------------")
f1(1.1)

print("n--------------- Test f2 函数 ---------------------")
f2(2.2)
# 全局变量b的值未变,说明f2中修改的确实是局部变量
print(f"b --->> {b}")

print("n--------------- Test f3 函数 ---------------------")
f3(3.3)
# 全局变量b的值变了,说明f3中修改的确实是全局变量
print(f"b --->> {b}")
Python之变量作用域、Closure闭包
figure 1.png

当我们对全局变量进行修改时,如果不使用global关键字来声明该变量是一个全局变量,即会因为找不到变量定义而报错

num = 996

def func3():
    # 对全局变量进行修改时,需要通过 global关键字来声明该变量是一个全局变量
    # 否则即会因为找不到变量定义而报错
    num += 50000
    print(f"num -->> {num}")

func3()
Python之变量作用域、Closure闭包
figure 2.png

Closure闭包

在外层函数中嵌套定义一个内层函数时,一方面:在内层函数定义中使用了外层函数中定义的变量;另一方面,外层函数直接返回了内层函数,使得该内层函数可以在其定义环境外被执行。这样的一个内层函数我们称之为Closure闭包

title = "闭包定义"
print(f"------------ {title} -------------------")

def f1():
    name = "Aaron"

    # 这里内层函数f2使用了外层函数f1的变量name,此时就产生了闭包。其中f2就是一个闭包函数
    def f2():
        msg  = f"{name}: Hello ..."
        print(msg)

    print(f"f2 函数: {f2}")    
    return f2

f2_new = f1()
# f2_new变量指向的就是f2函数
print(f"f2_new变量 --->>> {f2_new}")    

print("函数f2中局部变量的名称:", f2_new.__code__.co_varnames)
print("函数f2中自由变量的名称:", f2_new.__code__.co_freevars)

# 从下不难看出,对于闭包函数f2而言,
# 它会保留 定义f2函数时对name变量的绑定,这样当我们在f1函数的外面调用f2函数。
# 虽然f1函数的作用域已经不存在了,但是仍能使用name变量 

for cell in f2_new.__closure__:
    print("函数f2中自由变量对应的值:", cell.cell_contents)

# 在f1函数外面调用f2函数,依然可以访问name变量
f2_new()
Python之变量作用域、Closure闭包
figure 3.png

nonlocal关键字

在Python中,如果内层函数需要访问外层函数的变量,可使用nonlocal关键字来进行声明

def make_averager():
    count = 0
    sum = 0

    def avg(num):
        # 由于在函数中变量进行修改,Python解释器会将其视为局部变量
        # 为解决此问题,Python 3中引入了nonlocal关键字
        # 表明其不是局部变量, 而是外层函数的变量
        nonlocal count, sum
        count += 1
        sum += num
        return sum / count

    return avg

avg = make_averager()
print(f"计算平均值: {avg(20)}")
print(f"计算平均值: {avg(10)}")
print(f"计算平均值: {avg(3)}")
Python之变量作用域、Closure闭包
figure 4.png

参考文献

  1. Python编程·第3版:从入门到实践 Eric Matthes著
  2. Python基础教程·第3版 Magnus Lie Hetland著
  3. 流畅的Python·第1版 Luciano Ramalho著


原文始发于微信公众号(青灯抽丝):Python之变量作用域、Closure闭包

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/296367.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!