提到元这个字,你也许会想到元数据,元数据就是描述数据本身的数据,元类就是类的类,相应的元编程就是描述代码本身的代码,元编程就是关于创建操作源代码(比如修改、生成或包装原来的代码)的函数和类。主要技术是使用装饰器、元类、描述符类。本文的主要目的是向大家介绍这些元编程技术,并且给出实例来演示它们是怎样定制化源代码的行为。
装饰器
装饰器就是函数的函数,它接受一个函数作为参数并返回一个新的函数,在不改变原来函数代码的情况下为其增加新的功能,比如最常用的计时装饰器:
from functools import wraps
def timeit(logger=None):
"""
耗时统计装饰器,单位是秒,保留 4 位小数
"""
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.time()
result = func(*args, **kwargs)
end = time.time()
if logger:
logger.info(f"{func.__name__} cost {end - start :.4f} seconds")
else:
print(f"{func.__name__} cost {end - start :.4f} seconds")
return result
return wrapper
return decorator
(注:比如上面使用 @wraps(func) 注解是很重要的, 它能保留原始函数的元数据) 只需要在原来的函数上面加上 @timeit() 即可为其增加新的功能:
@timeit()
def test_timeit():
time.sleep(1)
test_timeit()
#test_timeit cost 1.0026 seconds
上面的代码跟下面这样写的效果是一样的:
test_timeit = timeit(test_timeit)
test_timeit()
装饰器的执行顺序
当有多个装饰器的时候,他们的调用顺序是怎么样的?
假如有这样的代码,请问是先打印 Decorator1 还是 Decorator2 ?
from functools import wraps
def decorator1(func):
@wraps(func)
def wrapper(*args, **kwargs):
print('Decorator 1')
return func(*args, **kwargs)
return wrapper
def decorator2(func):
@wraps(func)
def wrapper(*args, **kwargs):
print