Python


342 浏览 5 years, 11 months

10.3 实现装饰器

版权声明: 转载请注明出处 http://www.codingsoho.com/

实现装饰器

使用函数作为装饰器

  • 简单容易实现
  • 支持不同种类的被装饰对象
def wrapper_decor(f):
    def wrapper(*args):
        print("Change behavior of original function")
        print("Call original function")
        f(*args)
        print("Call originnal function done")
    return wrapper
@wrapper_decor
def hello(name):
    print("How are you? {}".format(name))
参数的传递
  • 装饰器如何处理拥有不同参数被装饰函数
  • *args - 变长位置参数
  • **kwargs - 变长关键字参数
  • ,* 在定义的时候收集变长参数,在调用函数时候扩展变长参数
print(*[1,2,3]) -> print(1,2,3)
Functions With Arbitrary Positional Arguments
  • Functions that contains variable number of arguments
print(1)
print(1,2,3,4)
print(1,2,3,4,5,6,7)

How to collect these arguments?
Definition

def func(arg1, *args)

举例:

def foo(name, age, *attrs):
    print(name, age, attrs)

foo(Zhang San, 18, male, China)
# Zhang San 18 (male, China)
  • Functions that contains variable number of keyword arguments
datetime.datetime(2014,3,20, hour=12, minute=20, second=55)
datetime.datetime(2014,3,20, hour=12, minute=20)
datetime.datetime(2014,3,20)

How to collect these arguments?
Definition

def func(arg1, **kws)

举例:

def foo(name, age, **attrs):
    print(name, age, attrs)

foo(Zhang San, 18, male, China)
# TypeError Traceback (most recent call last) <ipython-input-223-660e7e4e6b91> in <module>() ----> 1 foo(Zhang San, 18, male, China)
# TypeError: foo() takes 2 positional arguments but 4 were given

foo(Zhang San, 18, sex=male, nationality=China)
# Zhang San 18 {nationality: China, sex: male}

使用类作为装饰器

  • 类可以作为一个很好的容器来存放要被装饰函数的一些信息
  • 类的实例必须可以像函数一样使用__call__()方法
class decor():
    def __init__(self, number):
        print("Decorate funtion")
        self.number = number
    def __call__(self, f):
        print("Second decorating")
        def wrapper(*args, **kws):
            print("Before running original function")
            for x in range(self.number):
                f(*args, **kws)
            print("Aftere running original function")
        return wrapper

@decor(3)
def hello(name):
    print(name)
练习

用类来实现一个装饰器,其对被装饰函数的执行时间进行统计,统计其执行了多少秒。要求: – 用类来实现这个装饰器 – 可以通过参数来控制执行的次数 – 被装饰函数的参数类型,个数任意

装饰过程中的类型转换

  • 将函数装饰成类的实例
  • 将类装饰成函数
将函数装饰成类的实例
def decor_to_class(func):
    class Wrapper():
        def __call__(self, *args, **kws):
            print("Inside a callable")
            func(*args, **kws)
    return Wrapper() # 返回一个callable对象

@decor_to_class
def hello(name):
    print("Hello", name)
将类装饰成函数
def decor_to_func(cls):
    def wrapper(*args, **argv):
        print("Add some behavior here")
        ins = cls(*args, **argv)
        return ins
    return wrapper #返回一个函数对象

@decor_to_func
class Foo():
    def hello(self, name):
        print("Hello", name)