2022
我们一起努力

禁止 Python 子类覆盖父类具体方法

当实现我们自己的父类Animal的时候,由于meta.has_base为 False,所以不会触发检查逻辑。但当我们基于Animal实现Dog子类的时候,由于meta.has_base是True,所以进入检查逻辑。Dog的所有方法名都在attrs参数里面。循环检查每一个方法名是否在禁止的列表中,如果在,就抛出异常。如果不在,就继续后面的创建过程。

禁止 Python 子类覆盖父类具体方法

当子类试图覆盖父类的时候,可以通过类型标注来发出警告。今天,我们来讲讲如何直接禁止覆盖。

Python 原生是没有提供禁止子类覆盖父类的方法的功能,因此我们需要自己来实现。

先来看一下实现效果:

禁止 Python 子类覆盖父类方法禁止 Python 子类覆盖父类方法
禁止 Python 子类覆盖父类方法禁止 Python 子类覆盖父类方法

在这段代码里面,我们禁止子类覆盖父类的dead()和eat()方法,但不禁止move方法。所以,当我们在子类Dog里面尝试覆盖父类中的dead()时,程序就报错了。具体要覆盖哪些方法,可以在定义类的时候指定,传入的参数metaclass=protect(‘方法1’, ‘方法2’, ‘方法3’, …)就可以了。

那么这个protect函数是个什么东西呢?我们来看看它的代码:

def protect(*protected):
   """Returns a metaclass that protects all attributes given as strings"""
   class Protect(type):
       has_base = False
       def __new__(meta, name, bases, attrs):
           if meta.has_base:
               for attribute in attrs:
                   if attribute in protected:
                       raise AttributeError('Overriding of attribute "%s" not allowed.'%attribute)
           meta.has_base = True
           klass = super().__new__(meta, name, bases, attrs)
           return klass
   return Protect

这里,用到了 Python 的元类。如果大家对元类有兴趣,可以看9.13 使用元类控制实例的创建 — python3-cookbook 3.0.0 文档[1]。简单的来说,元类用来定义类的创建行为。它一般的格式为:

class 类名(metaclass=另一个类):
  ...

而大家看我们用来禁止重试的这个函数protect,它返回的就是一个Protect类。这个类继承于type对象。

Protect类有一个new方法,这个方**在使用了元类的所有子类的init之前被调用。在new里面,我们拿到了子类要定义的方法,并且检查他们是不是在我们传给protect的列表里面。如果在,说明这个方法不能被覆盖。

当实现我们自己的父类Animal的时候,由于meta.has_base为 False,所以不会触发检查逻辑。但当我们基于Animal实现Dog子类的时候,由于meta.has_base是True,所以进入检查逻辑。Dog的所有方法名都在attrs参数里面。循环检查每一个方法名是否在禁止的列表中,如果在,就抛出异常。如果不在,就继续后面的创建过程。

元类在理解上可能比较困难。如果大家无法理解上面这一段也没有关系,直接用就是了。

本文来源:www.lxlinux.net/9559.html,若引用不当,请联系修改。

赞(0)
文章名称:《禁止 Python 子类覆盖父类具体方法》
文章链接:https://www.fzvps.com/235544.html
本站文章来源于互联网,如有侵权,请联系管理删除,本站资源仅供个人学习交流,请于下载后24小时内删除,不允许用于商业用途,否则法律问题自行承担。
图片版权归属各自创作者所有,图片水印出于防止被无耻之徒盗取劳动成果的目的。

评论 抢沙发

评论前必须登录!