装饰器

装饰器相关问题整理

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需要的参数,所以把已有缺省值的参数固定不管,只传没有缺省
值的参数就可以,缺的参数在下面定义的函数中补上就可以

lru_cache

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)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值