=Start=
之前在学习Python装饰器的时候看了很多文章,但没有及时整理、总结,最近在写程序的时候发现很多装饰器具有较强的实用价值,所以抽出时间整理如下:
函数执行耗时统计
import time def timing(f): def wrap(*args): print '<function name: {0}>'.format(f.func_name) time1 = time.time() ret = f(*args) time2 = time.time() print '[timecosts: {0} ms]'.format((time2-time1)*1000.0) return ret return wrap
使用方法:
@timing def hello(name): print "hello, %s" % name hello('tom')
给函数调用做缓存
from functools import wraps def memo(fn): cache = {} miss = object() @wraps(fn) def wrapper(*args): result = cache.get(args, miss) if result is miss: result = fn(*args) cache[args] = result return result return wrapper
使用方法:
@memo def fib(n): if n < 2: return n return fib(n - 1) + fib(n - 2) fib(100) #这里其实可以使用上面的函数耗时统计的decorator进行耗时比对 fib(101) #用以判断memo装饰器是否起到作用
失败重试函数
import time import math # Retry decorator with exponential backoff def retry(tries, delay=3, backoff=2): '''Retries a function or method until it returns True. delay sets the initial delay in seconds, and backoff sets the factor by which the delay should lengthen after each failure. backoff must be greater than 1, or else it isn't really a backoff. tries must be at least 0, and delay greater than 0.''' if backoff <= 1: raise ValueError("backoff must be greater than 1") tries = math.floor(tries) if tries < 0: raise ValueError("tries must be 0 or greater") if delay <= 0: raise ValueError("delay must be greater than 0") def deco_retry(f): def f_retry(*args, **kwargs): mtries, mdelay = tries, delay # make mutable rv = f(*args, **kwargs) # first attempt while mtries > 0: if rv is True: # Done on success return True mtries -= 1 # consume an attempt time.sleep(mdelay) # wait... mdelay *= backoff # make future wait longer rv = f(*args, **kwargs) # Try again return False # Ran out of tries :-( return f_retry # true decorator -> decorated function return deco_retry # @retry(arg[, ...]) -> true decorator
使用方法:
@retry(5) def some_func(): pass some_func()
超时退出函数
这个函数的作用在于可以给任意可能会hang住的函数添加超时功能,这个功能在编写外部API调用 、网络爬虫、数据库查询的时候特别有用
import signal, functools class TimeoutError(Exception): pass #定义一个Exception,在超时情况下抛出 def timeout(seconds, error_message = 'Function call timed out'): def decorated(func): def _handle_timeout(signum, frame): raise TimeoutError(error_message) def wrapper(*args, **kwargs): signal.signal(signal.SIGALRM, _handle_timeout) signal.alarm(seconds) try: result = func(*args, **kwargs) finally: signal.alarm(0) return result return functools.wraps(func)(wrapper) return decorated
使用方法:
@timeout(5) #限定下面的slowfunc函数如果在5s内不返回就强制抛TimeoutError Exception结束 def slowfunc(sleep_time): import time time.sleep(sleep_time) #这个函数就是休眠sleep_time秒 slowfunc(3) #sleep 3秒,正常返回,没有异常 slowfunc(10) #被终止
打印调试信息函数
import sys, os, linecache def trace(f): def globaltrace(frame, why, arg): if why == "call": return localtrace return None def localtrace(frame, why, arg): if why == "line": filename = frame.f_code.co_filename lineno = frame.f_lineno bname = os.path.basename(filename) print "{}({}): {}".format(bname, lineno, linecache.getline(filename, lineno)), return localtrace def _f(*args, **kwds): sys.settrace(globaltrace) result = f(*args, **kwds) sys.settrace(None) return result return _f
使用方法:
@trace def simple_print(): print 1 print 22 print 333 simple_print() #调用
参考链接:
- https://wiki.python.org/moin/PythonDecoratorLibrary
- http://stackoverflow.com/questions/5478351/python-time-measure-function
- http://www.huyng.com/posts/python-performance-analysis/
- http://coolshell.cn/articles/11265.html
=END=
《 “一些实用的Python装饰器” 》 有 4 条评论
[译]Python之装饰器知必会
http://kissg.me/2016/07/16/translation-about-python-decorator/
Python装饰器的前世今生
http://zhangchuzhao.site/2018/05/25/python-decorator/
`
一、史前故事
二、开天辟地
三、Pythonic世界的初探
四、多元化百家争鸣
1、带参数的装饰器
2、让装饰器同时支持带参数或不带参数
3、类装饰器
4、装饰函数 -> 装饰类
五、上古神器
1、@property -> getter/setter方法
2、@classmethod、@staticmethod
3、@functools.wraps
4、Easter egg
`
Python @property decorator
https://www.programiz.com/python-programming/property
How does the @property decorator work?
https://stackoverflow.com/questions/17330160/how-does-the-property-decorator-work
https://docs.python.org/2/library/functions.html#property
https://docs.python.org/3/howto/descriptor.html
使用@property
https://www.liaoxuefeng.com/wiki/897692888725344/923030547069856
`
@property广泛应用在类的定义中,可以让调用者写出简短的代码,同时保证对参数进行必要的检查,这样,程序运行时就减少了出错的可能性。
@property的实现比较复杂,我们先考察如何使用。把一个getter方法变成属性,只需要加上@property就可以了,此时,@property本身又创建了另一个装饰器@score.setter,负责把一个setter方法变成属性赋值,于是,我们就拥有一个可控的属性操作。
`
Python property() 函数
https://www.runoob.com/python/python-func-property.html
Python中的函数缓存装饰器,可以用在传入相同参数返回相同结果的函数调用处,减少资源消耗,提高响应时效
26. Function caching
https://book.pythontips.com/en/latest/function_caching.html
统计函数执行时长的装饰器,可以和上面的装饰器共用,看看缓存的效果如何
Python decorator to measure execution time
https://dev.to/kcdchennai/python-decorator-to-measure-execution-time-54hk