Python 进阶用法 (持续更新),,装饰器(Decora


装饰器(Decorator)

Python 的装饰器是任何可调用对象(callable object),用于修改函数(Function)或类(Class)。按照用途可分为:

函数装饰器类装饰器

装饰器的接口定义可概括为:

接收某个函数或类的引用作为参数;修改该函数或类并返回。

简单函数装饰器示例

理解装饰器

def my_decorator(func):    def wrapped_func(arg):        print("Before calling " + func.__name__)        func(arg)        print("After calling " + func.__name__)    return wrapped_funcdef foo(arg):    print("Hi, foo has been called with " + str(arg) )print("We call foo BEFORE decoration:")foo("no decoration"); print()print("We NOW decorate foo with my_decorator...\n")foo = my_decorator(foo)print("We call foo AFTER decoration:")foo("decoration")

程序对应的输出为:

We call foo BEFORE decoration:Hi, foo has been called with no decorationWe NOW decorate foo with my_decorator...We call foo AFTER decoration:Before calling fooHi, foo has been called with decorationAfter calling foo

上述例子中的用法在实际开发中并不常用,我们更倾向于下面的写法。

语法糖写法

Python 提供一种更简洁、直观的装饰器写法。例如我们可以把上述例子写成更简便的形式:

def my_decorator(func):    def wrapped_func(arg):        print("Before calling " + func.__name__)        func(arg)        print("After calling " + func.__name__)    return wrapped_func@my_decoratordef foo(arg):    print("Hi, foo has been called with " + str(arg) )foo("decoration")

函数装饰器应用示例

统计函数调用次数

def call_counter(func):    def func_with_counts(arg):        func_with_counts.calls += 1        return func(arg)    func_with_counts.calls = 0    return wrapped_func@call_counterdef foo(arg):    return "foo: " + str(arg)print("foo has been called {} time(s)".format(foo.calls))for i in range(0, 51, 10):    foo(i)print("foo has been called {} time(s)".format(foo.calls))

程序对应的输出结果是:

foo has been calld 0 time(s)foo: 0foo: 10foo: 20foo: 30foo: 40foo: 50foo has been calld 6 time(s)

用记忆表(Memoization1)优化 Fibonacci 数列算法

def memoize(func):    memo = {}    def memoized_func(arg):        if arg not in memo:            memo[arg] = func(arg)        return memo    return memoized_func@memoizedef fib(n):    if n == 0:        return 0    elif n = 1:        return 1    else:        return fib(n-1) + fib(n-2)for i in range(20):    print(fib(i), end=‘, ‘)print(fib(20))

程序对应的输出结果是:

    0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765

类装饰器

首先需要明确,Python 的装饰器是任何可调用对象而不仅限于函数。我们可以定义一个类并使其对象可调用。例如我们可以定义一个带缓存功能的类计算 Fibonacci:

class Fibonacci:    def __init__(self):        self.cache = {}    def __call__(self, n):        if n not in self.cache:            if n == 0:                self.cache[0] = 0            elif n == 1:                self.cache[1] = 1            else:                self.cache[n] = self.cache[n-1] + self.cache[n-2]        return cache[n]fib = Fibonacci()for i in range(20):    print(fib(i), end=‘, ‘)print(fib(20))

程序对应的输出结果是:

    0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765

因此,我们可以构建一个可调用对象并令其作为装饰器。
在下面的例子中,我们用类装饰器统计函数调用次数:

class CallCounter:    def __init__(self, func):        self.calls = 0        self.func = func    def __call__(self, arg):    self.calls += 1        return self.func(arg)@CallCounterdef foo(arg):    return "foo: " + str(arg)    print("foo has been called {} time(s)".format(foo.calls))for i in range(0, 51, 10):    foo(i)print("foo has been called {} time(s)".format(foo.calls))

Reference
Written with StackEdit.


注意 Memoization 是专业术语,不是 Memorization。?

Python 进阶用法 (持续更新)

评论关闭