Python中的装饰器

2017-12-29  本文已影响37人  fisher爱吃鱼

Python中的装饰器

不带参数的装饰器

#!coding:utf-8


def use_logging(func):

    def wrapper(*args, **kwargs):
        print("%s is running" % func.__name__)
        return func(*args)
    return wrapper


@use_logging
def foo():
    print("i am foo")


@use_logging
def bar():
    print("i am bar")

foo()
bar()

带参数的装饰器

#!coding:utf-8


def use_logging(level):

    def decorator(func):
        def wrapper(*args, **kwargs):
            print("[%s]%s is running" % (level, func.__name__))
            return func(*args)
        return wrapper
    return decorator


@use_logging(level='error')
def foo():
    print("i am foo")


@use_logging(level='warn')
def bar():
    print("i am bar")

foo()
bar()

类装饰器

#!coding:utf-8


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()

functools.wraps

使用装饰器极大地复用了代码,但是他有一个缺点就是原函数的元信息不见了,比如函数的 docstring__name__、参数列表,先看例子:

#!coding:utf-8


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

print(f.__name__)    # prints 'with_logging'
print(f.__doc__)     # prints None

函数 f 等价于:

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

不难发现,函数 fwith_logging 取代了,当然它的 docstring__name__ 就是变成了with_logging函数的信息了。

这个问题就比较严重的,好在我们有 functools.wrapswraps 本身也是一个装饰器,它能把原函数的元信息拷贝到装饰器函数中,这使得装饰器函数也有和原函数一样的元信息了。

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__)  # prints 'f'
print(f.__doc__)   # prints 'does some math'

内置装饰器

@staticmathod@classmethod@property

装饰器的顺序

@a
@b
@c
def f ():

等效于

f = a(b(c(f)))
上一篇下一篇

猜你喜欢

热点阅读