def copy_properties(src):
def _copy(dest):
dest.name = src.name
dest.doc = src.doc
return dest
return _copy
def logger(fn):
@copy_properties(fn) # copy_properties(add)(wrapper)
def wrapper(*args,**kwargs):
print(’------before------’)
start = datetime.datetime.now()
ret = fn(*args,**kwargs)
delta = (datetime.datetime.now()-start).total_seconds()
print(‘so slowly’) if delta > 5 else print(‘so fast’) return ret
return wrapper
@logger
def add(x,y):
time.sleep(6)
return x + y
print(add(5,6))
(1) 首先要进行 def copy_properties(src) 的定义
(2) def logger(fn) 定义logger
(3) @logger 调用装饰器
(4) 进而调用 def logger(fn)
(5) 执行到第八行 @copy_properties(fn)时转而调用第一行的 def copy_properties(src)
(6) 在这层函数里定义 def _copy(dest),并返回_copy值
(7) 在返回_copy值得时候就调用了def _copy函数 把wrapper作为参数提上去
(8) fn 属于被包装函数,wrapper属于包装函数。src 是源 dest 是目标 用 fn 的属性去覆盖 src 的属性去覆盖
(9) 返回的是 dest 也就是返回的是 wrapper
(10) 然后return wrapper 给logger ,到此时logger已经全部执行完成,返回到18行
(11) print(add(5,6)) 时,调用到第10行,打印 before
(12) ret = fn(*args,**kwargs),解构进行结果计算,返回ret 再给add结果
def partial(func,*args,**kwargs):
def newfunc(*fargs,**fkeywords):
nwekeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*args,*fargs,**newkeywords)
newfunc.func = func
newfunc.args = args
newfunc.keywords = keywords
return newfunc
def add(x,y):
print(x,y,x+y)
foo = partial(add,y=5)
print(callable(foo))
(1) 首先定义partial 函数
(2) 定义 add 函数
(3) 在执行foo = partial(add,y=5)时,调用第一行的partial函数
def partial(add,*args,x=y):
def newfunc(*fargs,**fkeywords): # 这是传入的参数
newkeywords = keywords.copy()
newkeywords.update(fkeywords)
return func(*args,*fargs,**newkeywords)
newfunc.func = add #原来add的属性给 newfunc.func
newfunc.args = args #原来的可变位置变量给 newfunc.args
newfunc.keywords = y= 5 #把原函数add的可变关键字变零给newfunc.keywords
return newfunc # 返回 newfunc,在这调用内层函数,return newfunc
#在56行def newfunc(*fargs,fkeywords)中传入的函数是foo(4,6)中的新参数
#57行的newkeywords已经是y=5了,而且在foo(4,6)中没有关键字参数,所以就不更
# 新关键字参数,在return func(*args,*fargs,**newkeywords)中解构,(4,6)元
# 组解构,关键字参数解构,y 有两个值,一个是4,一个是y = 5.
def update_wrapper(wrapper,
wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):…
def wraps(wrapped,
assigned = WRAPPER_ASSIGNMENTS,
updated = WRAPPER_UPDATES):
return partial (update_wrapper, wrapped = wrapped,
assigned = assigned, updated = updated)
执行update_wrapper 时,一共有四个参数,有两个参数已经有了缺省值,只剩wrapper和
wrapped没有参数,当执行wraps时,返回值中需要调用update_wrapper,所以return值
只缺wrapper一项的参数,把这个把这个结果返回给wraps,当wraps下面用 def 定义函数时
def x(),这个x就是wrapper需要的参数,所以把已有缺省值的参数固定不管,只传没有缺省
值的参数就可以,缺的参数在下面定义的函数中补上就可以
def lru_cache(maxsize=128, typed=False):
if maxsize is not None and not isinstance(maxsize,int):
def decorating_function(user_function):
wrapper = lru_cache_wrapper(user_function,maxsize,typed,_CacheInfo):
return update_wrapper(wrapper,user_function)
return decorating_function
定义了lru_cacahe这个函数最大记录的条数为128条,定义了装饰器函数wrapper就是
lru_cache语句的返回值,返回的就是一个wrapper
def _lru_cache_wrapper(user_function,maxsize,typed,_CacheInfo):
cache = {} # cache 是一个空字典
hits = misses = 0
full = False
cache_get = cache.get #从字典里面拿
cache_len = cache.__len__
lock = RLock()
root = []
root [:] = [root,root,None,None]
if maxsize == 0: #如果记录条数为0
def wrapper(*args,**kwds):
nonlocal misses
result = user_function(*args,**kwds)
misses += 1
return result
elif maxsize is None: #如果记录条数没有上限
def wrapper(*args,**kwds):
nonlocal hits,misses
key = make_key(args,kwds,typed) #先得知道一个key值
result = cache_get(key,sentinel)#先看字典里有没有这个key值,如果有从字典里拿
if result is not sentinel:#如果有
hits += 1 #则命中一次
return result
result = user_function(*args,**kwds)#如果没有就用fn算一下
cache[key] = result #将结果保存到字典当中去
misses += 1 #记录丢失一次
return result
def _make_key(args,kwds,typed,
kwd_mark = (object(),), #创建所有对象祖先类的实例
fasttypes = (int,str,frozenset,type,(None)),
tuple = tuple,type = type ,len = len):
key = args #key值是一个元组
if kwds: #字典不为空
key += kwd_mark #位置参数已经满了,关键字参数不为空,加object()分隔开
for item in kwds.items():#在元组里面加一个元组
key += items
if typed:
key += tuple(type(v) for v in args)#不管元组有几个都要遍历一下送进来的字典,将args里面
if kwds: #的所有值遍历出来后取它的类型,凑成一个元祖并跟在key后面,如果可变关键字参数非空
key += tuple(type(v) for v in kwds.values()) #将里面的值遍历出来取它的类型跟在后面
elif len[key] == 1 and type[key[0]] in fasttypes: #如果如果元组里面只有一个元素且是快速类型
return key[0] #那么把这一个元素返回回去,否则返回key
return _HashedSeq(key)