一日一技:如何禁止 Python 子类覆盖父类方法?

简介: 一日一技:如何禁止 Python 子类覆盖父类方法?

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


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

先来看一下实现效果:


640.png


在这段代码里面,我们禁止子类覆盖父类的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_baseFalse,所以不会触发检查逻辑。但当我们基于Animal实现Dog子类的时候,由于meta.has_baseTrue,所以进入检查逻辑。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】获取更多精彩文章。

目录
相关文章
|
1天前
|
SQL 关系型数据库 数据库连接
使用 Python 访问数据库的基本方法
【5月更文挑战第12天】在Python中操作数据库涉及安装数据库驱动(如mysql-connector-python, psycopg2, pymongo)、连接数据库、执行查询/更新、处理结果集及关闭连接。使用ORM(如SQLAlchemy)可简化操作。通过上下文管理器(with语句)能更好地管理资源和错误。注意根据实际需求处理事务、错误和安全性,例如使用SSL连接。
11 2
|
2天前
|
Python
【Python进阶(二)】——程序调试方法
【Python进阶(二)】——程序调试方法
|
4天前
|
存储 Linux Shell
python移除/删除非空文件夹/目录的最有效方法是什么?
python移除/删除非空文件夹/目录的最有效方法是什么?
8 0
|
6天前
|
Python
【Python 基础】Python中的实例方法、静态方法和类方法有什么区别?
【5月更文挑战第6天】【Python 基础】Python中的实例方法、静态方法和类方法有什么区别?
|
6天前
|
数据处理 Python
Python中每个字段增加多条数据的高效方法
Python中每个字段增加多条数据的高效方法
13 1
|
7天前
|
存储 数据挖掘 Python
Python技术分享:实现选择文件或目录路径的方法
Python技术分享:实现选择文件或目录路径的方法
17 2
|
7天前
|
数据处理 Python
Python中按指定数量分割列表字符串的方法
Python中按指定数量分割列表字符串的方法
9 1
|
11天前
|
Python
使用Python pandas的sort_values()方法可按一个或多个列对DataFrame排序
使用Python pandas的sort_values()方法可按一个或多个列对DataFrame排序。示例代码展示了如何按'Name'和'Age'列排序 DataFrame。先按'Name'排序,再按'Age'排序。sort_values()的by参数接受列名列表,ascending参数控制排序顺序(默认升序),inplace参数决定是否直接修改原DataFrame。
23 1
|
12天前
|
机器学习/深度学习 数据可视化 前端开发
【Python机器学习专栏】机器学习模型评估的实用方法
【4月更文挑战第30天】本文介绍了机器学习模型评估的关键方法,包括评估指标(如准确率、精确率、召回率、F1分数、MSE、RMSE、MAE及ROC曲线)和交叉验证技术(如K折交叉验证、留一交叉验证、自助法)。混淆矩阵提供了一种可视化分类模型性能的方式,而Python的scikit-learn库则方便实现这些评估。选择适合的指标和验证方法能有效优化模型性能。
|
13天前
|
机器学习/深度学习 算法 Python
【Python机器学习专栏】Python中的特征选择方法
【4月更文挑战第30天】本文介绍了机器学习中特征选择的重要性,包括提高模型性能、减少计算成本和增强可解释性。特征选择方法主要包括过滤法(如相关系数、卡方检验和互信息)、包装法(如递归特征消除和顺序特征选择)和嵌入法(如L1正则化和决策树)。在Python中,可利用`sklearn`库的`feature_selection`模块实现这些方法。通过有效的特征选择,能构建更优的模型并深入理解数据。