提到元这个词,你可能会想到元数据。元数据是描述数据本身的数据。元类是类的类。相应的元编程是描述代码本身的代码。编程就是创建操作源代码的函数和类,例如修改、生成或包装原始代码。主要技术是使用装饰器、元类、描述符类。本文的主要目的是介绍这些元编程技术,并举例说明它们如何自定义源代码的行为。装饰器装饰器是函数的函数,它接受一个函数作为参数并返回一个新的函数,在不改变原函数代码的情况下向其添加新的函数,比如最常用的时序装饰器:fromfunctoolsimportwrapsdeftimeit(logger=None):"""耗时统计装饰器,单位秒,保留小数点后4位"""defdecorator(func):@wraps(func)defwrapper(*args,**kwargs):start=time.time()result=func(*args,**kwargs)end=time.time()iflogger:logger.info(f"{func.__name__}cost{end-f})se:.else:print(f"{func.__name__}cost{end-start:.4f}seconds")returnresultreturnreturnwrapperreturndecorator(注意:重要的是保留原始@wraps(func)注解,例如上面的函数元数据)只需在原函数中添加@timeit()即可添加新函数:@timeit()deftest_timeit():time.sleep(1)test_timeit()#test_timeitcost1.0026seconds以上代码与f的效果相同如下:test_timeit=timeit(test_timeit)test_timeit()装饰器的执行顺序当有多个装饰器时,它们的调用顺序是怎样的?如果有这样一段代码,我应该先打印Decorator1还是Decorator2呢?fromfunctoolsimportwrapsdefdecorator1(func):@wraps(func)defwrapper(*args,**kwargs):print('Decorator1')@returnfunc(*args,**kwargs)undecreturnfwrapper:wraps(func)defwrapper(*args,**kwargs):print('Decorator2')返回func(*args,**kwargs)returnwrapper@decorator1@decorator2defadd(x,y):add+yreturn(x1,2)#Decorator1#Decorator2在回答这个问题之前,先给大家打个形象比喻。装饰器就像一个穿衣服的函数。例子中decorator1是上衣,decorator2是内衣add=decorator1(decorator2(add))调用函数时,就像脱衣服一样,先把最外面的decorator1去掉,即先打印Decorator1,然后执行returnfunc(*args,**kwargs)会取消decorator2,然后打印Decorator2,再次执行returnfunc(*args,**kwargs)时执行add()函数。注意印刷品的位置很重要。如果打印字符串的代码位于调用函数之后,如下所示,输出正好相反:defdecorator1(func):@wraps(func)defwrapper(*args,**kwargs):Result=Func(*ARGS,**KWARGS)Print('Decorator1')返回结果RETURNWRAPPERDEFDecorator2(FUNC):@Wraps(Func)deferper(*ARGS,**Kwargs):resurs):result:resurs):resurs:resurs):resurs:resurs):resurs:resurs):result:result:resurs):result:resurs):result:result:resurs):result:result):resurs.args,**kwargs)print('Decorator2')returnresultreturnwrapper装饰器不仅可以定义为函数,也可以定义为类,只要你确保它实现了__call__()和__get__()方法。元类Python中所有类(对象)的元类是类型类,也就是说Python类的创建行为由默认的类型类控制。打个比方,类型类是所有类的祖先。我们可以通过编程方式实现一些自定义对象创建行为。指定一个类继承类型类A,然后让其他类的元类指向A,就可以控制A的创建行为。典型的实现是使用元类来实现单例:classSingleton(type):def__init__(self,*args,**kwargs):self._instance=Nonesuper().__init__(*args,**kwargs)def__call__(self,*args,**kwargs):如果self._instance无:self._instance=super()。=Singleton):def__init__(self):print("Spam!!!")元类Singleton的__init__和__new__方法会在Spam定义时执行,__call__方法会在Spam实例化时执行。描述符类(descriptorclass)描述符是任何定义了__get__()、__set__()或__delete__()的对象。描述符允许对象自定义属性查找、存储和删除操作。下面是官方文档[1]中的一个自定义验证器的例子。定义一个验证器类,它是一个描述符类和一个抽象类:fromabcimportABC,abstractmethodclassValidator(ABC):def__set_name__(self,owner,name):self.private_name='_'+namedef__get__(self,obj,objtype=None):returngetattr(obj,self.private_name)def__set__(self,obj,value):self.validate(value)setattr(obj,self.private_name,value)@abstractmethodself,value):通过自定义验证器需要继承自Validator并且必须提供validate()方法来根据需要测试各种约束。以下是三个有用的数据验证工具:OneOf验证一个值是一组受限选项中的一个。classOneOf(Validator):def__init__(self,*options):self.options=set(options)defvalidate(self,value):ifvaluenotinself.options:raiseValueError(f'Value}{是一个{self.options!r}')Number来验证值是整数还是浮点数。根据可选参数,它还可以验证该值是否介于给定的最小值或最大值之间。类号(验证器):def__init__(self,minvalue=None,maxvalue=None):self.minvalue=minvalueself.maxvalue=maxvaluedefvalidate(self,value):如果不是isinstance(value,(int,float)):raiseTypeError(f'Expected{value!r}tobeanintorfloat')ifself.minvalueisnotNoneandvalue
