Python 进阶用法 (持续更新),,装饰器(Decora
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 进阶用法 (持续更新)
评论关闭