之前去面試缴渊,有一道裝飾器的面試題沒有答上來永部。
所以專門寫這篇裝飾器的文章阁苞,主要是為了給自己看尊残,不用再網(wǎng)上去搜別人寫的東西。
可參考廖雪峰的這篇文章
裝飾器
在不改變原函數(shù)情況下進(jìn)行功能擴(kuò)展窟哺。
這個不改變包括函數(shù)內(nèi)部的邏輯枷餐,和函數(shù)的調(diào)用代碼残黑。
只需要在原來函數(shù)上方加一個魔術(shù)方法注盈。
裝飾器學(xué)習(xí)
"""調(diào)試用的代碼"""
import time
def foo():
print(time.time())
return ""
def decorator(func, *arg, **kwargs):
print(time.time(), 'decorator')
def wrapper(*arg, **kwargs):
t1 = time.time()
ret = func(*arg, **kwargs)
t2 = time.time()
print('time count:', t2 - t1)
return ret
return wrapper
t = 0
def decorator_arg(*args_d, **kwargs_d):
print(time.time())
def decorator_3(func):
print(time.time(), 'decorator')
def wrapper(*args, **kwargs):
t1 = time.time()
ret = func(*args, **kwargs)
t2 = time.time()
print('time count:', t2 - t1, args_d, kwargs_d)
return ret
return wrapper
return decorator_3
t1 = 0
a = 0
# @decorator(f3)
@decorator_arg('99999')
def f1(name="hyman"):
text = "This func is f1, name is %s!" % name
for i in range(9999999):
pass
print(text)
return text
a1 = 0
@decorator
def f2(name="hyman"):
text = "This func is f2, name is %s!" % name
print(text)
return text
def f3(*arg, **kwargs):
print('f3', arg, kwargs)
# print(f1())
# print(f2('llll'))
我覺得可以這么理解晃危,把@后面的代碼視為一個整體foo, 這個foo實際上是一個函數(shù),
這個foo可以用一個變量名表示(即函數(shù)名)老客,也可以用執(zhí)行函數(shù)的返回結(jié)果(這個結(jié)果必須是函數(shù))表示僚饭。
而@符號相當(dāng)于調(diào)用foo()
,foo的輸入是固定的胧砰,即@下面函數(shù)func鳍鸵,返回也是固定的,是一個新的函數(shù)尉间。
這個新的函數(shù)是有擴(kuò)展功能的函數(shù)偿乖,他取代了原來函數(shù)func的引用。所以當(dāng)你去調(diào)用func的時候,
他執(zhí)行的@運(yùn)算所生成的新函數(shù)哲嘲。foo就是裝飾器贪薪,@運(yùn)算會調(diào)用foo來生成一個新的函數(shù)來取代func函數(shù).
可以把代碼全打上斷點,看代碼的運(yùn)行流程撤蚊。
面試題
** 設(shè)計一個裝飾器古掏,使api請求資源時會讀取緩存损话,并且可以設(shè)置緩存的超時時間侦啸。**
代碼
"""設(shè)計一個裝飾器,使api請求資源時會讀取緩存丧枪,并且可以設(shè)置緩存的超時時間"""
import time
from datetime import datetime
from flask import Flask
app = Flask(__name__)
created = 0
cache_response = None
def cache(timeout=5):
"""緩存請求的資源光涂,默認(rèn)緩存失效時間為5秒"""
def decorator(func):
def wrapper(*arg, **kwargs):
global created, cache_response
now = time.time()
if now - created > timeout:
created = now
cache_response = func(*arg, **kwargs)
return cache_response
return wrapper
return decorator
# 添加header的裝飾器
def set_header(headers):
def decorator(func):
def wrapper(*args, **kwargs):
response = func(*args, **kwargs)
response.headers.update(headers)
return response
wrapper.__name__ = func.__name__
return wrapper
return decorator
@app.route('/')
@cache(15)
def index():
return datetime.now().strftime("%Y-%m-%d %H:%M:%S") + " > Hello! "
if __name__ == '__main__':
app.run(debug=True)