Python 装饰器
装饰器是一种函数的函数,需要传入函数或类作为参数。让其他函数在不需要做任何代码变动的前提下,进而通过实现各种功能来对这个函数的功能进行增强。
应用场景:
装饰器最大的优势是用于解决重复性的操作,比如计算函数运行时间,给函数打日志等
以下的例子实现了计算一个函数的运行时间
import time
def func(n):
time.sleep(1)
print(n,"This is function func!")
start=time.time()
func(1)
print(time.time()-start)
1 This is function func!
1.0037739276885986
如果有多个函数需要计算,代码量将会重复和复杂。此时可以定义一个函数帮助实现该功能。
def run_time(func):
def wrapper(*args, **kwargs):#wrapper包装纸,封皮的意思
start = time.time()
func(*args, **kwargs)
end = time.time()
cost_time = end - start
print(cost_time)
return wrapper
test1=run_time(func)
test1(1)
test2=run_time(func)
test2(3)
1 This is function func!
1.0043902397155762
3 This is function func!
1.0031471252441406
更简单的写法,可以用装饰器@符号
@run_time
def func(n):
time.sleep(1)
print(n,"This is function func!")
func(1)
func(3)
func('hello')
1 This is function func!
1.0044219493865967
3 This is function func!
1.0023789405822754
hello This is function func!
1.004396915435791
带参数的装饰器
如果装饰器本身需要传入参数,则需要在原来的函数上,再嵌套一层。
import logging
def run_time(info=None):
def decorator(func):
def wrapper(*args, **kwargs):
if info != None:
print(info)
return func(*args)
return wrapper
return decorator
@run_time("hello")
def func(n):
time.sleep(1)
print(n,"This is function func!")
func(7)
func(9)
hello
7 This is function func!
hello
9 This is function func!
类装饰器
除了函数,python的类也可以被装饰
举几个例子:
def singleton(cls, *args, **kw):
instances = {}
def _singleton():
if cls not in instances:
instances[cls] = cls(*args, **kw)
return instances[cls]
return _singleton
@singleton
class A():
pass
#主类会做成单例(singleton)以避免重复初始化
class Foo(object):
def __init__(self, func):
self._func = func
def __call__(self):
print ('class decorator runing')
self._func()
print ('class decorator ending')
@Foo
def bar():
print ('bar')
bar()
class decorator runing
bar
class decorator ending
functools.wraps
实现将原函数的元信息(name,doc等)拷贝到装饰器函数中,不添加此装饰器,会丢失元信息
举例:
import time
def func(n):
'''This is __doc__ of func'''
time.sleep(1)
print(n,"This is function func!")
print(func.__name__)
print(func.__doc__)
func This is __doc__ of func
def run_time(func):
def wrapper(*args, **kwargs):#wrapper包装纸,封皮的意思
start = time.time()
func(*args, **kwargs)
end = time.time()
cost_time = end - start
print(cost_time)
return wrapper
@run_time
def func(n):
'''This is __doc__ of func'''
time.sleep(1)
print(n,"This is function func!")
print(func.__name__)
print(func.__doc__)
wrapper
None
添加functools.wraps装饰器后
from functools import wraps
def run_time(func):
@wraps(func)
def wrapper(*args, **kwargs):#wrapper包装纸,封皮的意思
start = time.time()
func(*args, **kwargs)
end = time.time()
cost_time = end - start
print(cost_time)
return wrapper
@run_time
def func(n):
'''This is __doc__ of func'''
time.sleep(1)
print(n,"This is function func!")
print(func.__name__)
print(func.__doc__)
func
This is __doc__ of func
总结
@是python的语法糖,类似于@后面的东西(类或者函数)以调用的函数为参数,实现某些重复有效的功能。
0 Comments