闭包和装饰器总结

本文主要介绍Python中的闭包和装饰器。闭包是内层函数对外层非全局变量的引用,会一直存在内存中。装饰器本质是闭包,可在不修改被装饰对象源代码和调用方式的前提下添加新功能,还介绍了统计函数执行时长的方法及参数错误的解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

闭包和装饰器

闭包部分参考文档:https://www.cnblogs.com/bailo/p/9096937.html

闭包函数:

定义:内层函数对外层函数非全局变量的引用,就叫做闭包函数。

           闭包会一直存在内存当中,不会因为函数执行结束而被释放。

# 闭包函数
def wrapper():
    name = 'alex'
    def inner():
        # 内层函数对外层函数非局部变量的引用
        print(name)
    inner()
wrapper()

判断是否为闭包函数

name = 'alex'
def wrapper():
    def inner():
        print(name)
    inner()
    print(inner.__closure__)  # None   说明该函数不是闭包函数
wrapper()
上述函数改写为闭包函数如下
name = 'alex'
def wrapper(x):
    x = name
    def inner():
        print(x)
    inner()
    print(inner.__closure__)  # <cell at 0x0000000000130C48: str object at 0x0000000001E8A260>  有类似的打印信息说明该函数为闭包函数
wrapper(name)

应用场景:

# 功能获取网页内容
from urllib.request import urlopen

def zhua(url):
    def get():
        return urlopen(url).read()
    return get
zhua('www.baidu.com')

 

总结:通过闭包的方式,在该函数外层包一层作用域(即再定义一个函数),将需要的非全局变量包在外部函数中

 

装饰器:

定义:用来装饰其他函数,装饰器本身可以是任意可调用对象,被装饰的对象也可以是任意可调用对象。装饰器的本质就是闭包

原则:

  1、不修改被装饰对象的源代码。

  2、不修改被装饰对象的调用方式。

 

功能:在遵循原则的前提,为被装饰对象添加上新功能。

python提出了一个语法糖 @,python解释器如果到@符号就将正下方的函数名作为一个参数传给@符号后面跟着的函数。

统计函数的执行时长

# 例如 很多方法 要统计下函数的执行时长
def add(a, b):
    return a+b

add(1, 2)

方法一:

import time


def add():
    print("add run")
    start_time = time.time()
    time.sleep(3)
    end_time = time.time()
    print("add end")
    print("last_time:{}".format(end_time-start_time))


add()

方法二:

# 例如 很多方法 都要统计下函数的执行时长
import time
# 装饰器加载过程
# 在函数还未调用时 就已经加载执行了装饰器对应的 print("dec started")
# 所以要采用闭包函数,把其他要执行的内容 放于内部的函数,防止一开始就直接执行了
# 可以将main函数注释掉 只运行方法,发现是可以打印 “dec started“


def time_dec(func):
    print("dec started")

    def wrapper():
        start_time = time.time()
        func()
        end_time = time.time()
        print("last_time:{}".format(end_time - start_time))
    return wrapper


# @语法糖表示:将其修饰的函数add,传入至@后面的方法time_dec中
@time_dec
def add():
    print("add run")
    time.sleep(3)
    print("add end")


if __name__ == '__main__':
    add()

在方法二的代码中,如果执行 add(a, b),使a+b,会出现参数错误,解决方案见方法三:

用到了functools.wraps(),和参数传递的*args,**kwargs

# 例如 很多方法 都要统计下函数的执行时长
import time
import functools


def time_dec(func):
    print("dec started")

    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        start_time = time.time()
        func(*args, **kwargs)
        end_time = time.time()
        print("last_time:{}".format(end_time - start_time))
    return wrapper


# @语法糖表示:将其修饰的函数add,传入至@后面的方法time_dec中
@time_dec
def add(a, b):
    print("add run")
    time.sleep(3)
    print("a+b:{}".format(a+b))
    print("add end")


if __name__ == '__main__':
    add(1, 2)

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值