继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

我对python装饰器的理解-秒懂

慕士塔格
关注TA
已关注
手记 8
粉丝 20
获赞 124

因为高阶函数的存在,可以接受函数传参,这就让不改变原有函数的前提下,“装饰”原有函数成为可能。也就是增强其功能。

不带参数的装饰器

实现不带参数的装饰器至少需要这样两步操作:
图片描述
可以看出,不带参数的装饰器实现有两个步骤:

  1. 传入原函数名
  2. 传入原函数参数列表,增加功能代码,调用原函数
    两个步骤之间的链接,是用return返回函数名进行指向(闭包)。
带参数的装饰器

类比不带参数的装饰器实现步骤,每一次传参,就需要定义一次函数,并完成内外层函数的指向调用,类似与递归。
因此不难想象,当我们本身的装饰器也需要参入特定参数时,我们就需要把不带参数的装饰器再进行一次封装,在传入原函数前,增加一个传参和指向的过程。
如下:
图片描述
可以看出,带参数的装饰器实现就多了一个传送装饰参数的过程,就多了一层。

实例对比

不带参数的装饰器


        def log_decorator(f):
            def wrapper(*args,**kw):
                print '%s()...'%f.__name__
                return f(*args,**kw)
            return wrapper

带参数的装饰器

 def log(prefix):
        def log_decorator(f):
            def wrapper(*args,**kw):
                print '[%s]%s()...'%(prefix,f.__name__)
                return f(*args,**kw)
            return wrapper
        return log_decorator

从上面两个实例对比可以看出,带参数与不带参数,就是多了一层封装,多的这一层,提供了传参的入口。

类装饰器

类装饰器,相比函数装饰器,具有灵活度大、高内聚、封装性等优点。

class Foo(object):
    def __init__(self, func):
        self._func = func

    def __call__(self):
        print 'class decorator runing'
        self._func()
        print 'class decorator ending'

@Foo
def bar():
    print 'bar'

bar()

使用装饰器极大复用了代码,但是也有缺点就是原函数元信息不见了,比如函数的docstring、name、参数列表

装饰器

def logged(func):
    def with_logging(*args, **kwargs):
        print func.__name__ + 'was called'
        return func(*args, **kwargs)
    return with_logging

函数

@logged
def f(x):
    """does some math"""
    return x + x*x

# 等价于f = logged(f)

不难发现,函数f被with_logging取代了,当然它的docstring,name就是变成了with_logging函数的信息了。

print f.__name__    # 'with_logging'
print f.__doc__       # 'None'

怎么解决,这里有个functools.wraps,wraps本身也是一个装饰器,它能把元函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。

from functools import wraps
def logged(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print func.__name__ + 'was called'
        return func(*args, **kwargs)
    return with_logging

@logged
def f(x):
    """does some math"""
    return x + x*x

print f.__name__       # 'f'
print f.__doc__          # 'does some math'
内置装饰器

@staticmethod

@classmethod

@property

装饰器的顺序
@a
@b
@c
def f():
    pass

# 等效于 
f = a(b(c(f)))
打开App,阅读手记
6人推荐
发表评论
随时随地看视频慕课网APP