【摘】python和它的装饰器

python和它的装饰器

即使你没听过装饰器,你也一定知道@staticmethod

作为函数的装饰器,你可以这样写

def mydecorator(function):

    def wrapped(*args, **kwargs):

        # 在调用原始函数之前, 做点什么
        result = function(*args, **kwargs)
        # 在函数调用之后, 做点什么
        # 并返回结果
        return result
    # 返回warpper作为装饰函数
    return wrapped

作为一个例子,我写了个非常随意的

def print_hello(function):

    def hello(*args, **kwargs):

        print('hello start')
        result = function(*args, **kwargs)
        print('hello end')
        return 'hello %s' % result
    return hello

@print_hello
def print_world():

    print('world print')
    return 'world result'

if __name__ == '__main__':

    print(print_world())

它的结果是

hello start
world print
hello end
hello world result

作为类的装饰器,你可以这样写

class DecoratorAsClass(object):
    
    def __init__(self, function):
        
        self.funciton = function
        
    def __call__(self, *args, **kwargs):
        
        # 在调用原始函数之前, 做点什么
        result = self.funciton(*args, **kwargs)
        # 在调用函数之后, 做点什么
        # 并返回结果
        return result

作为一个例子,我依旧写了一个很随意的

class PrintWrappedClass(object):

    def __init__(self, function):

        self.function = function

    def __call__(self, *args, **kwargs):

        print('wrapped start')
        result = self.function(*args, **kwargs)
        print('wrapped end')
        return result

@PrintWrappedClass
class PrintWorld (object):

    def print_world(self):

        print('world print')
        return 'world result'

    def print_kitty(self):

        print('kitty print')
        return 'kitty result'

if __name__ == '__main__':
    print(PrintWorld().print_world())
    print('___')
    print(PrintWorld().print_kitty())

它的结果是

wrapped start
wrapped end
world print
world result
___
wrapped start
wrapped end
kitty print
kitty result

当然,装饰器也可以传参

def repeat(number=3):

    def actual_decorator(function):

        def wrapper(*args, **kwargs):

            result = None
            for _ in range(number):
                result = function(*args, **kwargs)
            return result
        return wrapper
    return actual_decorator

@repeat(2)
def print_kitty():

    print('kitty print')
    return 'kitty result'


if __name__ == '__main__':

    print(print_kitty())

它的结果是

kitty print
kitty print
kitty result

然后我想了想,为什么不像函数装饰器的模板那么写呢?

于是,我就随意地写了个错误的例子

def error_repeat(function, number=3):

    def wrapper(*args, **kwargs):

        result = None
        for _ in range(number):
            result = function(*args, **kwargs)
        return result
    return wrapper

@error_repeat
def print_world():

    print('world print')
    return 'world result'

它的结果是

world print
world print
world print
world result

很完美,但是当我想传参数进去的时候,犯难了

呃,就姑且将这个错误的示例当做个笑话看看吧

保存内省的装饰器

from functools import wraps

def preserving_decorator(function):

    @wraps(function)
    def wrapped(*args, **kwargs):

        # 包装函数内部文档
        return function(*args, **kwargs)
    return wrapped

说实话,我没看懂这段

所以摘录下书中的原话

使用装饰器的常见错误是在使用装饰器时不保存函数元数据(主要是文档字符串和原始函数名)。
前面所有示例都存在这个问题。
装饰器组合创建了一个新函数,并返回一个新对象,但却完全没有考虑原始函数的标识。这将使得调试这样装饰过的函数更加困难,也会破坏可能用到的大多数自动生成文档的工具,因为无法访问原始的文档字符串和函数签名。

摘自 《Python高级编程》

posted @ 2019-01-23 19:55  白应非  阅读(134)  评论(0编辑  收藏  举报