如何禁止 Python 子类覆盖父类方法?

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

[[428429]]

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

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

先来看一下实现效果:

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

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

  1. def protect(*protected): 
  2.     """Returns a metaclass that protects all attributes given as strings""" 
  3.     class Protect(type): 
  4.         has_base = False 
  5.         def __new__(meta, name, bases, attrs): 
  6.             if meta.has_base: 
  7.                 for attribute in attrs: 
  8.                     if attribute in protected: 
  9.                         raise AttributeError('Overriding of attribute "%s" not allowed.'%attribute) 
  10.             meta.has_base = True 
  11.             klass = super().__new__(meta, name, bases, attrs) 
  12.             return klass 
  13.     return Protect 

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

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

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

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

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

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

参考文献

[1] 9.13 使用元类控制实例的创建 — python3-cookbook 3.0.0 文档: https://python3-cookbook.readthedocs.io/zh_CN/latest/c09/p13_using_mataclass_to_control_instance_creation.html

本文转载自微信公众号「未闻Code」,可以通过以下二维码关注。转载本文请联系未闻Code公众号。

 

责任编辑:武晓燕 来源: 未闻Code
相关推荐

2021-10-11 20:02:49

Python父类方法

2009-12-16 09:43:35

Ruby父类Objec

2009-08-21 14:22:22

C# new和over

2009-09-09 11:28:40

Scala类

2023-08-08 08:01:52

Java程序变量

2010-03-18 14:16:52

Java Thread

2020-12-17 08:05:27

JavaSuper用法

2021-04-21 10:01:53

Python类方法静态方法

2012-04-10 11:07:41

Java

2023-12-05 16:01:12

模板方法设计模式算法结构

2009-06-16 10:20:05

多继承C#

2019-12-27 15:05:51

Python类方法装饰器

2014-12-29 10:19:01

Java

2021-05-21 09:01:56

Python继承多态

2016-03-29 10:39:46

iOS函数初始化

2010-08-26 15:24:04

DHCP服务功能

2010-07-22 11:06:31

禁止Telnet 23

2020-05-26 08:52:36

Java JVM多态

2009-12-10 13:37:16

PHP parent

2011-09-06 14:08:22

IIS
点赞
收藏

51CTO技术栈公众号