# 🐍Python 装饰器解析¶

## 什么是装饰器¶

In [0]:
def deco(func):
'''
该函数参数为另外一个函数
'''
def inner():
print('running %s' % func.__name__)
return func()
return inner


In [2]:
# 普通写法
def func1():
print('running func1()')

func1 = deco(func1)
func1()

running func1
running func1()

In [3]:
# 装饰器写法
@deco
def func2():
print('running func2()')

func2()

running func2
running func2()


## 实现一个简单的装饰器¶

In [0]:
import time

def timethis(func):
def wrapper(*args):
start = time.time()
result = func(*args)
end = time.time()
args_str = ', '.join(repr(arg) for arg in args)
print('[%0.8fs] %s(%s) -> %r' %(end-start, func.__name__, args_str, result))
return result
return wrapper


In [5]:
@timethis
def accumulate(end):
count = 0
for i in range(end):
count = count + i
return count

accumulate(100)

[0.00000906s] accumulate(100) -> 4950

Out[5]:
4950
In [6]:
@timethis
def fibonacci(n):
if n < 2:
return n
return fibonacci(n-2) + fibonacci(n-1)

fibonacci(6)

[0.00000072s] fibonacci(0) -> 0
[0.00000119s] fibonacci(1) -> 1
[0.00263357s] fibonacci(2) -> 1
[0.00000048s] fibonacci(1) -> 1
[0.00000095s] fibonacci(0) -> 0
[0.00000072s] fibonacci(1) -> 1
[0.00051475s] fibonacci(2) -> 1
[0.00090528s] fibonacci(3) -> 2
[0.00434542s] fibonacci(4) -> 3
[0.00000048s] fibonacci(1) -> 1
[0.00000072s] fibonacci(0) -> 0
[0.00000143s] fibonacci(1) -> 1
[0.00066710s] fibonacci(2) -> 1
[0.00126076s] fibonacci(3) -> 2
[0.00000024s] fibonacci(0) -> 0
[0.00000072s] fibonacci(1) -> 1
[0.00159335s] fibonacci(2) -> 1
[0.00000048s] fibonacci(1) -> 1
[0.00000072s] fibonacci(0) -> 0
[0.00000048s] fibonacci(1) -> 1
[0.00008130s] fibonacci(2) -> 1
[0.00019741s] fibonacci(3) -> 2
[0.00191045s] fibonacci(4) -> 3
[0.00326824s] fibonacci(5) -> 5
[0.00772119s] fibonacci(6) -> 8

Out[6]:
8

### 保留函数元信息¶

In [0]:
import time
from functools import wraps

def timethis2(func):
@wraps(func)
def wrapper(*args):
start = time.time()
result = func(*args)
end = time.time()
args_str = ', '.join(repr(arg) for arg in args)
print('[%0.8fs] %s(%s) -> %r' %(end-start, func.__name__, args_str, result))
return result
return wrapper

In [0]:
# 使用 @wraps 了的装饰器
@timethis2
def accumulate2(end):
count = 0
for i in range(end):
count = count + i
return count

In [9]:
accumulate2.__name__, accumulate.__name__

Out[9]:
('accumulate2', 'wrapper')

## 解除装饰器¶

In [10]:
accumulate2.__wrapped__(6)

Out[10]:
15

In [11]:
accumulate.__wrapped__(6)

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-11-6bb343b3867e> in <module>()
----> 1 accumulate.__wrapped__(6)

AttributeError: 'function' object has no attribute '__wrapped__'

## 带参数的装饰器¶

In [0]:
def timethis3(display_result=True):
def decorate(func):
@wraps(func)
def wrapper(*args):
start = time.time()
result = func(*args)
end = time.time()
args_str = ', '.join(repr(arg) for arg in args)
if(display_result):
print('[%0.8fs] %s(%s) -> %r' %(end-start, func.__name__, args_str, result))
else:
print('[%0.8fs] %s(%s)' %(end-start, func.__name__, args_str))

return result
return wrapper
return decorate


In [13]:
@timethis3(display_result=False)
def accumulate3(end):
count = 0
for i in range(end):
count = count + i
return count

accumulate3(100)

[0.00000882s] accumulate3(100)

Out[13]:
4950
In [14]:
@timethis3(display_result=True)
def accumulate4(end):
count = 0
for i in range(end):
count = count + i
return count

accumulate4(100)

[0.00000787s] accumulate4(100) -> 4950

Out[14]:
4950

## 装饰器叠加¶

In [0]:
@d1
@d2
def f():
pass


In [0]:
def f():
pass

f = d1(d2(f))