Python 装饰器

知道python 装饰器这个名字很久了,也在很多代码中看到,但是感觉始终没有很透彻的了解,所以今天花了些时间来弄懂它,我会尝试用通俗易懂的例子来解释。

首先,给一个定义,可能不严谨(根据我自己的理解)。装饰器就是一种方法,能够对新的函数进行装饰(或封装),使他们有相同的特性或功能。

假设你正在开发一个计算器。要求是能够实现加减这些简单的功能,同时在进行计算时输出 ‘hello user’。很简单,只需要如下两个简单的函数。但是这个写法有一个问题,print('hello user') 起相同的作用,但是在不同函数中需要重复写。假设你有100个方法,那么就造成很多重复语句。并且,如果你哪天不想打印 hello user 了,要一个一个改。

#code 1
def plus(a, b):
    print('hello user')
    result = a+b
    return result

def sub(a, b):
    print('hello user')
    result = a-b
    return result

a = 10
b = 5

result_plus = plus(a, b)
result_sub = sub(a, b)

这个问题可以被解决,如下所示。 很简单,只需要定义另一个函数,将相同的功能固定,但是传入不同的计算方法来获得不同的结果即可。但是,这会导致另外一个问题(我猜测的,我也没有被这个解释说服 :)。这看起来不 ‘优雅’。因为第一眼看上去调用的是decorator()这个函数,实际上在很多代码中就是这么用的。需要至少两次跳转才知道具体执行的哪个函数。那么,怎么解决呢。

#code 2
def decorator(fun, a, b):
    print('hello user')
    result = fun(a, b)
    return result

def plus(a, b):
    result = a+b
    return result

def sub(a, b):
    result = a-b
    return result

a = 10
b = 5

result = decorator(plus, a, b)
result = decorator(sub, a, b)

最终,developer 们开发了另一个 ‘fancy’ 的用法。具体原理跟如上相似,也是把新定义的函数当作参数传入另一个函数。案例如下。结果跟上面完全相同,但是一眼就知道执行的是哪个函数。

#code 3
def decorator(fun):
    def wrapper(a, b):
        print('hello user')
        result = fun(a, b) 
    return wrapper

@decorator
def plus(a, b):
    result = a+b
    return result

@decorator
def sub(a, b):
    result = a-b
    return result

a = 10
b = 5

result = plus(a, b)
result = sub(a, b)

这里有一个问题我困惑了很久。为什么decorator()里边要再多套一层 wrapper()。同样的功能完全可以实现只使用一个decorator() 函数,只需要加上类似@decorator 的骚操作, 如下所示 (应该无法运行)。我认为最主要的原因是,开发者希望decorator() 返回的是一个函数, 即 wrapper。 只使用一层函数,无法实现这个功能,自己也可以试一下。比如:

def decorator(fun, a, b):
    print('hello user')
    result = fun(a, b) 
    return decorator 

:)

#code 4. 应该不能运行
def decorator(fun, a, b):
    print('hello user')
    result = fun(a, b) 
    return result

@decorator
def plus(a, b):
    result = a+b
    return result

@decorator
def sub(a, b):
    result = a-b
    return result

a = 10
b = 5

result = plus(a, b)
result = sub(a, b)

好了,主要原理已经解释完了,最后添加一点补充。基于 #code 3的代码, wrapper() 的需要的参数是 a, b,这是由 fun() 决定的。 很明显,如果你定义的fun() 通常使用不同的参数,那么这样必然会报错。最终,代码可以这样修改来解决这个问题。

#code 5
def decorator(fun):
    def wrapper(*args, **kwargs):
        print('hello user')
        result = fun(*args, **kwargs) 
    return wrapper

@decorator
def plus(a, b):
    result = a+b
    return result

@decorator
def sub(a, b):
    result = a-b
    return result

a = 10
b = 5

result = plus(a, b)
result = sub(a, b)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值