我是靠谱客的博主 诚心高跟鞋,最近开发中收集的这篇文章主要介绍Python带参装饰器的入门练习Python带参装饰器的入门套路Python带参装饰器的应用,觉得挺不错的,现在分享给大家,希望可以做个参考。
概述
Python带参装饰器的入门套路
在学习带参装饰器前我们首先复习一下无参装饰器的写法:
def add(x, y):
return x + y
def logger(fn):
def wrapper(*args, **kwargs): # 这里是形参的传入,可以传入类型最终由fn|add决定
print("before the fn/add")
ret = fn(*args, **kwargs) # 这里是实参结构
print("after the fn/add")
return ret
return wrapper
add = logger(add)
add(4, 5)
# ===========output=============>
before the fn/add
after the fn/add
9
带参装饰器练习:装饰器文档字符串被改变
import time
import datetime
def logger(fn):
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
print("Funtion{} took {}s.".format(fn.__name__,delta))
return ret
return wrapper
@logger # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
""" add's doc ~~~"""
time.sleep(1)
return x+y
print(add.__name__, add.__doc__)
# ==output不是add的document,而是wrapper的document=============>
wrapper wrapper's document
如上,使用装饰器后add的函数名和文档都被改变了。如何解决呢?
因为现在访问add函数,实际上是在执行wrapper函数,所以使用原来定义的add函数的名称和文档属性,覆盖wrapper的对应属性就可以了:
import time
import datetime
def logger(fn):
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
print("Funtion{} took {}s.".format(fn.__name__,delta))
return ret
def copy_properties(src, dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
copy_properties(fn, wrapper)
return wrapper
@logger # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
"""add's doc ~balabala~"""
time.sleep(1)
return x+y
print(add.__name__, "n", add.__doc__)
# ==output不是add的document,而是wrapper的document=============>
add
add's doc ~balabala~
写成函数的方式
import time
import datetime
def logger(fn):
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
print("Funtion{} took {}s.".format(fn.__name__,delta))
return ret
wrapper.__name__ = fn.__name__
wrapper.__doc__ = fn.__doc__
return wrapper
@logger # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
""" add's doc ~~~"""
time.sleep(1)
return x+y
print(add.__name__,"n", add.__doc__)
# ==output不是add的document,而是wrapper的document=============>
add
add's doc ~~~
BTW:
类似copy_properties这种函数往往是公用的,所以定义成全局的比较合适,在调用时候,使用装饰器调用。
import time
import datetime
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
return dst #这里注意return的返回值很重要,如果没有返回值,
# 如果没有返回值就是None。那么 带参装饰器里的wrapper - > copy_propertiest(fn)-> _copy -> copy(dst) - None
#这样,如果要print(add.__name__)->print(wrapper._name__)..................................print(None.__name__)
return _copy
def logger(fn):
@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
print("Funtion{} took {}s.".format(fn.__name__,delta))
return ret
# def copy_properties(src, dst): # 这是带参装饰器的原始状态
# dst.__name__ = src.__name__
# dst.__doc__ = src.__doc__
# copy_properties(fn, wrapper)
return wrapper
@logger # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
"""add's doc ~balabala~"""
time.sleep(1)
return x+y
print(add.__name__, "n", add.__doc__)
# ==output不是add的document,而是wrapper的document=============>
add
add's doc ~balabala~
这样,一个带参装饰器就完成了。
import time
import datetime
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
# return dst #这里注意return的返回值很重要,如果没有返回值,
# 如果没有返回值就是None。那么 带参装饰器里的wrapper - > copy_propertiest(fn)-> _copy -> copy(dst) - None
#这样,如果要print(add.__name__)->print(wrapper._name__)..................................print(None.__name__)
return _copy
def logger(fn):
@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
print("Funtion{} took {}s.".format(fn.__name__,delta))
return ret
# def copy_properties(src, dst): # 这是带参装饰器的原始状态
# dst.__name__ = src.__name__
# dst.__doc__ = src.__doc__
# copy_properties(fn, wrapper)
return wrapper
@logger # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
"""add's doc ~balabala~"""
time.sleep(1)
return x+y
print(add.__name__, "n", add.__doc__)
# ===============返回值Return因一个返回值的缺失而报错=============>
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-63-8df557fa2dde> in <module>
38 return x+y
39
---> 40 print(add.__name__, "n", add.__doc__)
41 # ===============返回值Return因一个返回值的缺失而报错=============>
AttributeError: 'NoneType' object has no attribute '__name__'
带参装饰器的覆盖问题
将记录提取到控制台,或者记录到日志里面。
import time
import datetime
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
return dst #这里注意return的返回值很重要,如果没有返回值,
# 如果没有返回值就是None。那么 带参装饰器里的wrapper - > copy_propertiest(fn)-> _copy -> copy(dst) - None
#这样,如果要print(add.__name__)->print(wrapper._name__)..................................print(None.__name__)
# 另外,如果return不是dst而是src,就会导致新add失效
return _copy
def logger(fn):
@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
print("Funtion{} took {}s.".format(fn.__name__,delta))
return ret
# def copy_properties(src, dst): # 这是带参装饰器的原始状态
# dst.__name__ = src.__name__
# dst.__doc__ = src.__doc__
# copy_properties(fn, wrapper)
return wrapper
@logger # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
"""add's doc ~balabala~"""
time.sleep(1)
return x+y
print(add.__name__, "n", add.__doc__)
add(4,5)
# ==output不是add的document,而是wrapper的document=============>
add
add's doc ~balabala~
before the fn
after the fn
Funtionadd took 1.001673s.
9
Python带参装饰器的应用
检查函数执行时间。
import time
import datetime
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
return dst #
return _copy
def logger(fn):
@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
if delta > 3:
print("Function {} took {}s. It is SLOW.".format(fn.__name__, delta))
else:
print("Function {} took {}s. The speed is OK.".format(fn.__name__, delta))
print("Funtion{} took {}s.".format(fn.__name__,delta))
return ret
return wrapper
@logger # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
"""add's doc ~balabala~"""
time.sleep(5)
return x+y
print(add.__name__, "n", add.__doc__)
add(4,5)
# ==output不是add的document,而是wrapper的document=============>
add
add's doc ~balabala~
before the fn
after the fn
Function add took 5.001807s. It is SLOW.
Funtionadd took 5.001807s.
9
我们可以把delta阈值提出作为一个参数,这样就可以自定义了:
import time
import datetime
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
return dst #
return _copy
def logger(duration = 3):
def _logger(fn):
@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
if delta > duration:
print("Function {} took {}s. It is SLOW.".format(fn.__name__, delta))
else:
print("Function {} took {}s. The speed is OK.".format(fn.__name__, delta))
print("Funtion{} took {}s.".format(fn.__name__,delta))
return ret
return wrapper
return _logger
@logger(6) # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
"""add's doc ~balabala~"""
time.sleep(5)
return x+y
print(add.__name__, "n", add.__doc__)
add(4,5)
# ==output不是add的document,而是wrapper的document=============>
add
add's doc ~balabala~
before the fn
after the fn
Function add took 5.001199s. The speed is OK.
Funtionadd took 5.001199s.
9
修改为便于阅读的三元表达式:
import time
import datetime
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
return dst #
return _copy
def logger(duration = 3):
def _logger(fn):
@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
# print("Function {} took {}s. It is .".format(fn.__name__, delta)) if delta > duration else print("Function {} took {}s. The speed is OK.".format(fn.__name__, delta))
print("Function {} took {}s. It is {}.".format(fn.__name__, delta,
"slow"if delta > duration else "fast"))
return ret
return wrapper
return _logger
@logger(6) # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
"""add's doc ~balabala~"""
time.sleep(5)
return x+y
print(add.__name__, "n", add.__doc__)
add(4,5)
# ==output不是add的document,而是wrapper的document=============>
add
add's doc ~balabala~
before the fn
after the fn
Function add took 5.001629s. It is fast.
9
为了灵活,我们对超出阈值的信息使用一个函数记录:
import time
import datetime
def copy_properties(src):
def _copy(dst):
dst.__name__ = src.__name__
dst.__doc__ = src.__doc__
return dst #
return _copy
def logger(duration = 3, output = lambda name, delta: print("slow.{} took {}s )".format(name, delta))):
def _logger(fn):
@copy_properties(fn) #wrapper = copy_properties(fn)(wrapper)
def wrapper(*args, **kwargs):
"""wrapper's document"""
print("before the fn")
start = datetime.datetime.now()
ret = fn(*args, **kwargs)
print("after the fn")
delta = (datetime.datetime.now() - start).total_seconds()
if delta > duration:
output(fn.__name__, delta) #这里的output指代的是函数一个函数,
return ret
return wrapper
return _logger
@logger(2) # equal to: add = logger(add) # add指向了wrapper
def add(x,y):
"""add's doc ~balabala~"""
time.sleep(3)
return x+y
print(add.__name__, "n", add.__doc__)
add(4,5)
# ==output不是add的document,而是wrapper的document=============>
add
add's doc ~balabala~
before the fn
after the fn
slow.add took 3.000753s )
9
最后
以上就是诚心高跟鞋为你收集整理的Python带参装饰器的入门练习Python带参装饰器的入门套路Python带参装饰器的应用的全部内容,希望文章能够帮你解决Python带参装饰器的入门练习Python带参装饰器的入门套路Python带参装饰器的应用所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复