在昨天的文章中,我们谈到了当子类试图覆盖父类时,它可以通过类型注释发出警告。今天就来说说如何直接禁止覆盖。Python本身并没有提供禁止子类重写父类方法的功能,所以需要我们自己实现。我们先来看看实现效果:在这段代码中,我们禁止子类重写父类的dead()和eat()方法,但是不禁止move方法。因此,当我们试图在子类Dog中重写父类中的dead()时,程序会报错。具体覆盖哪些方法可以在定义类的时候指定,传入参数metaclass=protect('method1','method2','method3',...)就可以了。那么这个保护功能是什么?我们看一下它的代码:defprotect(*protected):"""Returnsmetaclassthatprotectsallattributesgivenasstrings"""classProtect(type):has_base=Falsedef__new__(meta,name,bases,attrs):ifmeta。has_base:forattributeinattrs:ifattributeinprotected:raiseAttributeError('Overridingofattribute"%s"notallowed.'%attribute)meta.has_base=Trueklass=super().__new__(meta,name,bases,attrs)returnklassreturnProtect这里用到了Python的元类。对元类感兴趣的可以看9.13使用元类控制实例的创建——python3-cookbook3.0.0文档[1]。简单地说,元类用于定义类创建的行为。它的一般格式是:class类名(metaclass=anotherclass):...而大家看到我们用来禁止重试的函数protect返回的是一个Protect类。这个类继承自类型对象。Protect类有一个__new__方法,该方法将在使用元类的所有子类的__init__之前调用。在__new__内部,我们获取子类将定义的方法并检查它们是否在我们传递给保护的列表中。如果是这样,则不能覆盖此方法。在实现我们自己的父类Animal时,由于meta.has_base为False,所以不会触发校验逻辑。但是当我们基于Animal实现Dog子类时,由于meta.has_base为True,我们就进入了校验逻辑。Dog的所有方法名都在attrs参数中。遍历每个方法名,看它是否在禁止列表中,如果是则抛出异常。如果没有,继续后续的创建过程。元类可能难以理解。上面这段看不懂也没关系,直接拿来用就行了。参考文献[1]9.13使用元类控制实例创建——python3-cookbook3.0.0文档:https://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p13_using_mataclass_to_control_instance_creation.html本文转载自微信公众号《闻所未闻的代码》,您可以通过以下二维码关注。转载本文请联系Code公众号。
