Python 之 decorator 装饰器

python 在语法上对装饰模式进行了支持。

一、问题

有如下的一个函数,

 
 
def sum(x, y):
    print "x+y:"x+y

我们需要在每次调用 sum 函数的时候打印日志,但是我们并不希望修改sum函数。

二、解决方案

Solution 1:

最 brute-force 的方法,定义一个包裹函数, 在这个包裹函数的内部调用sum 函数(包裹函数和 sum 函数最好具有相同的参数,和返回类型

 
 
def wrapper1(x, y):
    print "calling %s" % sum.__name__
    return sum(xy)
wrapper1(12)

所有之前需要调用sum函数的地方,改用新的包裹函数。这样可行,但是加入另外一个函数 func, 同样需要进行日志,我们就得重新写另外一个包裹函数。显然,有更好的方法。

Solution 2:

上面提到,包裹函数和被包裹函数最好具有相同的参数,和返回类型。 如何能够只写一个包裹函数,它可以包裹任意接口的函数呢?

 
 
def wrapper2(*args, **kw):
    print "calling %s" % func.__name__
    return sum(*args**kw)
wrapper2(12)

python中函数的参数非常灵活,(*args, **kw)可以匹配任意类型的参数,关于这两种参数的解释,会另写一篇博文。

上述的包裹函数 wrapper2 已经可以接受任意的参数类型,并且返回值即为sum 的返回值。但是,其实还没有完全达到要求,wrapper2的内部调用了函数sum, 如果我们需要包裹另一个func函数,那么sum就必须修改。

Solution 3:

我们容易想到把 sum 作为函数的参数传入,但是这使得函数的接口变了。

 
 
def wrapper3(func, *args, **kw):
    print "calling %s" % func.__name__
    return func(*args**kw)
wrapper3(sum12)

Solution 4:

另一种做法是: 在wrapper外面再包裹一层函数,仅仅用于传入函数 sum

 
 
def log(func):
    def wrapper(*args, **kw):
        print "calling %s" % func.__name__
        return func(*args**kw)
    return wrapper
#调用 
log(sum)(12)

大家可能还是不满意,能不能还是通过 sum(1, 2) 来调用包含 log 信息的版本呢? 当然可以!

 
 
sum = log(sum)
sum(12)

python中的函数名相当于 C++ 中的指针,可以通过赋值,将 sum 指向 log(sum)

Ultimate Solution:

终极版本:通过 python 的 @语法

 
 
def log(func):
    def wrapper(*args, **kw):
        print "calling %s" % func.__name__
        return func(*args**kw)
    return wrapper
 
@log
def sum(x, y):
    print "x+y:"x+y
sum(12)
 
@log
def func(x):
    print x
func(1)

任意一个函数,需要打印log信息, 仅仅需要在函数的定义前加 @log,等价于sum = log(sum)

三、练习

请编写一个decorator,能在函数调用的前后打印出'begin call'和'end call'的日志。

 
 
def log2(func):
    def wrapper(*args, **kw):
        print "begin call"
        res = func(*args**kw)
        print "end call"
        return res
    return wrapper
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值