python装饰器__稀奇古怪的个人笔记

闭包(closure)

# print_msg是外围函数
def print_msg():
    msg = "I'm closure"

    # printer是嵌套函数
    def printer():
        print(msg)
	#返回嵌套函数
    return printer


# closure这里获得的就是一个闭包 得到了printer嵌套函数
closure = print_msg()
# 执行函数 输出 I'm closure
closure()

msg是一个局部变量,在print_msg函数执行之后应该就不会存在了。但是嵌套函数引用了这个变量,将这个局部变量封闭在了嵌套函数中,这样就形成了一个闭包。

闭包就是引用了自有变量的函数,这个函数保存了执行的上下文,可以脱离原本的作用域独立存在。

装饰器

装饰器@(decorator装饰器 = 高阶函数 + 闭包函数)
装饰器本质上是接受一个函数作为参数(高阶函数行为),并返回一个函数(闭包函数行为)。
返回函数即子函数 中定义添加内容后 再返回主函数的参数函数。
从而实现不修改 参数函数的基础上 在代码运行期间动态增加功能的方式。

使用:functools.wraps(func)装饰器
注意:装饰器装饰过的函数的原属性已经改变,因为装饰器内部是闭包主函数return返回了子函数。
解决办法是 通过给decorator装饰器主函数内return返回的子函数 加上装饰器functools.wraps(func) 来纠正被此装饰器装饰过的func函数属性。

import functools

def log(func):
     """
	接收一个函数作为参数,称为高阶函数
    :param func: 接收一个函数作为参数,也就是被修饰的函数
    :return: 返回子函数,称为闭包函数
    """
	# 把原函数的元信息拷贝到装饰器里面的 func 函数中
    @functools.wraps(func)
    def wrapper(*args, **kwargs):
        print('call %s():' % func.__name__)
        print('args = {}'.format(*args))
        # 返回主函数的参数函数,从而达到不修改参数函数的基础上,增加功能
        # 同时保证,被修饰的函数能拥有返回值,如果不return,则下文中的a == None
        return func(*args, **kwargs)
	
    return wrapper

这样就定义了一个打印出方法名及其参数的装饰器log。

@log
def test(p):
    print("this is" + test.__name__ + " param: " + p)
	return "this is test return"
    
a = test("I'm a param")
print(a)
"""
输出:
call test():
args = I'm a param
this is test param: I'm a param
this is test return
"""

装饰器只是个方法,与下面的调用方式没有区别:

def test(p):
    print("this is" + test.__name__ + " param: " + p)

wrapper = log(test)
wrapper("I'm a param")

@语法只是将函数传入装饰器函数,并无神奇之处

值得注意的是@functools.wraps(func),这是python提供的装饰器。它能把原函数的元信息拷贝到装饰器里面的 func 函数中。函数的元信息包括docstring、name、参数列表等等。可以尝试去除@functools.wraps(func),你会发现test.__name__的输出变成了wrapper。

整理:也就是说当使用@log修饰test()函数后,首先会将test作为参数送给log()函数,然后log()函数返回内部闭包函数wrapper。执行wrapper内部代码,作为对test()函数的功能补充。若在wrapper函数中未调用test()也就是func() 那么则不会执行test()函数的内容,所以要记得return func(*args, **kwargs)

带参数的装饰器

使用:如果装饰器decorator本身需要传入参数,那就需要编写一个返回装饰器的高阶函数(即三层嵌套装饰器函数)。

import functools

def log_with_param(text):
    def decorator(func):
        @functools.wraps(func)
        def wrapper(*args, **kwargs):
            print('call %s():' % func.__name__)
            print('args = {}'.format(*args))
            print('log_param = {}'.format(text))
            return func(*args, **kwargs)

        return wrapper

    return decorator
    
@log_with_param("param")
def test_with_param(p):
    print(test_with_param.__name__)

其函数调用的形式为:

# 传入装饰器的参数,并接收返回的decorator函数
decorator = log_with_param("param")
# 传入test_with_param函数
wrapper = decorator(test_with_param)
# 调用装饰器函数
wrapper("I'm a param")

参考:简书:聪明叉

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值