ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Python中如何理解闭包

2022-04-06 00:35:30  阅读:164  来源: 互联网

标签:闭包 函数 Python amount 理解 print balance 变量


闭包,是函数式编程中的一个较难理解的概念,JavaScript、Python、Perl、Object-C等很多语言都支持闭包。

说白了, 闭包就是函数嵌套函数,在函数中定义并返回另一个函数
例如:

def func1():
    def func2():
        pass
    return func2

通常情况下,我们的函数直接定义在模块中,模块中的变量称为全局变量,用户及任何函数都可以直接使用并修改。
如果把模块比作大厅的话,那么闭包就是包间。闭包中的变量,则只有内部函数能直接使用。
例如:

printer1 = '打印机1'  # 全局变量,用户及所有函数可以使用和修改

def room1():   # 闭包函数
     printer2 = '打印机2'  # 闭包函数中的变量称为 自由变量
     
    def a():
        pc1 = '电脑1'   # 局部变量,只有当前函数使用
        print('我可以使用全局变量', printer1)
        print('我可以使用自由变量', printer2)
        print('我可以使用自己的局部变量', pc1)

    return a  # 不return 函数 a,则用户没办法使用这个函数
        
def b():
    pc1 = '电脑2'   # 局部变量,只有当前函数使用
    print('我可以使用全局变量', printer1)
    print('我可以使用自己的局部变量', pc2)

a = room1()  # 调用闭包函数返回内部函数
a()  # 内部函数可以使用room1中的变量printer2
b()  # 调用普通函数b,b没办法使用room1中的变量

作用域链的原则是内部可以使用外部变量,外部不能使用内部变量
使用闭包函数可以为函数开辟一个独立空间,其中的变量外部无法直接使用,只能通过函数a间接使用。因此闭包可以起到隐藏变量的作用,可以防止变量被修改和破坏。

为什么闭包函数room1中的变量printer2不是局部变量而称为“自由变量”呢?
我们知道,函数调用结束后即终止,其中的局部变量会被清理。如调用b函数结束后,其中的局部变量pc1就会清理回收(下次调用重新创建)。
而闭包函数room1调用后得到a函数,此时room1函数已经调用结束,但由于a函数还要使用变量printer2,因此printer2不会被清理,而是一直为a函数保留着。
因此,闭包会加大内存开销,甚至造成内存泄露
然而隐藏和保护变量是很重要的,比如一个存钱和取钱的功能,两个都使用需要一个名为balance的余额变量,如果使用全局变量,示例如下:

balance = 0  # 初始余额

def save(amount):   # 存钱
    global balance    # 非容器全局变量,需要显示声明其为全局变量才能修改
    if amount > 0:
        balance += amount  # 余额增加
        print('存入 %d 当前余额 %d' %(amount, balance))
    else:
        print('amount必须大于0')

def draw(amount):  # 取钱
    global balance
    if amount > 0:
        if balance > amount:
            balance -= amount  # 余额减少
            print('取出 %d 当前余额 %d' % (amount, balance))
        else:
            print('余额不足')
    else:
        print('amount必须大于0')

amount = 1000000  # 直接修改余额
draw(200)

对于非容器(如列表、字典)类型的变量balance,不能直接进行修改。
在函数中如果直接使用如balance += amount则会视为新建了一个同名的局部变量。
因此需要使用global balance进行声明其为全局变量。

使用全局变量的危险是,用户可以直接修改amount的值,不经过save存钱,便可任意draw取钱。
我们可以使用闭包来隐藏balance变量,例如:

def bank():
    balance = 0  # 初始余额

    def save(amount):   # 存钱
        nonlocal balance  # 声明不是save中的局部变量,即bank中的自由变量balance
        if amount > 0:
            balance += amount  # 余额增加
            print('存入 %d 当前余额 %d' %(amount, balance))
        else:
            print('amount必须大于0')

    def draw(amount):  # 取钱
        nonlocal balance  # 声明是bank中的自由变量
        if amount > 0:
            if balance > amount:
                balance -= amount  # 余额减少
                print('取出 %d 当前余额 %d' % (amount, balance))
            else:
                print('余额不足')
        else:
            print('amount必须大于0')
    return save, draw  # 返回两个函数,以使得用户可以使用这两个函数

save, draw = bank()  # 使用闭包得到两个功能函数
save(100)  # 存钱
draw(200)  # 取钱 (显示余额不足)

同全局变量一样,如果save、draw中直接修改balance,同样会视为新建了一个同名的局部变量,此时需要使用nonlocal来声明其不是局部变量。

为什么我们在Python中很少用到闭包?因为Python还支持类和对象呀,使用类可以轻松实现独立空间和变量私有问题。

在Python中,闭包常用作装饰器,在一个装饰器函数中定义一个新的函数来替代原函数。

标签:闭包,函数,Python,amount,理解,print,balance,变量
来源: https://www.cnblogs.com/superhin/p/16104662.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有