Python中继承的优缺点

news/2024/7/5 6:56:07 标签: python, c/c++, 数据结构与算法
导语:本文章记录了本人在学习Python基础之面向对象篇的重点知识及个人心得,打算入门Python的朋友们可以来一起学习并交流。

本文重点:

1、不要试图在内置类型的子类中重写方法,可以继承collections的可拓展类寻求变通;
2、掌握多重继承中的MRO和Super;
3、了解处理多重继承的一些建议。

一、子类化内置类型的缺点

1、内置类型的方法不会调用子类覆盖的方法

内置类可以子类化,但是内置类型的方法不会调用子类覆盖的方法。下面以继承dict的自定义子类重写__setitem__为例说明:

python">class ModifiedDict(dict):
    def __setitem__(self, key, value):
        super().__setitem__(key,[value]*2)
a=ModifiedDict(one=1)
a["two"]=2
print(a)
a.update(three=3)
print(a)#输出{'one': 1, 'two': [2, 2], 'three': 3}

从输出可以看到,键值对one=1和three=3存入a时均调用了dict的__setitem__,只有[]运算符会调用我们预先覆盖的方法。
问题的解决方式在于不去子类化dict,而是子类化colections.UserDict。

2、子类化collections中的类

用户自定义的类应该继承collections模块,如UserDict,UserList,UserString。这些类做了特殊设计,因此易于拓展。子类化UserDict的代码如下:

python">from collections import UserDict
class ModifiedDict(UserDict):
    def __setitem__(self, key, value):
        super().__setitem__(key,[value]*2)
b=ModifiedDict(one=1)
b["two"]=2
b.update(three=3)
print(b)#输出{'one': [1, 1], 'two': [2, 2], 'three': [3, 3]}

小结:上述问题只发生在C语言实现的内置类型子类化情况中,而且只影响直接继承内置类型的自定义类。相反,子类化使用Python编写的类,如UserDict或MutableMapping就不会有此问题。

二、多重继承

1、方法解析顺序(Method Resolution Order,MRO)

在多重继承中存在不相关的祖先类实现同名方法引起的冲突问题,这种问题称作“菱形问题”。Python依靠特定的顺序遍历继承图,这个顺序叫做方法解析顺序。如图,左图是类的UML图,右图中的虚线箭头是方法解析顺序。
图片描述

2、super

提到类的属性__mro__,就会提到super:

super 是个类,既不是关键字也不是函数等其他数据结构。

作用:super是子类用来调用父类方法的。
语法:super(a_type, obj);
a_type是obj的__mro__,当然也可以是__mro__的一部分,同时issubclass(obj,a_type)==true

举个例子, 有个 MRO: [A, B, C, D, E, object]
我们这样调用:super(C, A).foo()
super 只会从 C 之后查找,即: 只会在 D 或 E 或 object 中查找 foo 方法。

下面构造一个菱形问题的多重继承来深化理解:

python">class A:
    def ping(self):
        print("A-ping:",self)
class B(A):
    def pong(self):
        print("B-pong:",self)
class C(A):
    def pong(self):
        print("C-PONG:",self)
class D(B, C):
    def ping(self):
        print("D-ping:",self)
        super().ping()
    def pingpong(self):
        self.ping()
        super().ping()
        self.pong()
        super(B,D).pong(self)
d=D()
d.pingpong()
print(D.mro())

输出如下:

python">D-ping: <__main__.D object at 0x000001B77096EAC8>
A-ping: <__main__.D object at 0x000001B77096EAC8>#前两行对应self.ping()。
A-ping: <__main__.D object at 0x000001B77096EAC8>#此处super调用父类的ping方法。
B-pong: <__main__.D object at 0x000001B77096EAC8>
C-PONG: <__main__.D object at 0x000001B77096EAC8>#此处从B之后搜索父类的pong()
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]#类D的__mro__,数据以元组的形式存储。

分析:d.pingpong()执行super.ping(),super按照MRO查找父类的ping方法,查询在类B到ping之后输出了B.ping()。

3、处理多重继承的建议

(1)把接口继承和实现继承区分开;

  • 继承接口:创建子类型,是框架的支柱;
  • 继承实现:通过重用避免代码重复,通常可以换用组合和委托模式。

(2)使用抽象基类显式表示接口;
(3)通过混入重用代码;
混入类为多个不相关的子类提供方法实现,便于重用,但不会实例化。并且具体类不能只继承混入类。
(4)在名称中明确指明混入;
Python中没有把类声明为混入的正规方式,Luciano推荐在名称中加入Mixin后缀。如Tkinter中的XView应变成XViewMixin。
(5)抽象基类可以作为混入,反过来则不成立;
抽象基类与混入的异同:

  • 抽象基类会定义类型,混入做不到;
  • 抽象基类可以作为其他类的唯一基类,混入做不到;
  • 抽象基类实现的具体方法只能与抽象基类及其超类中的方法协作,混入没有这个局限。

(6)不要子类化多个具体类;
具体类可以没有,或者至多一个具体超类。
例如,Class Dish(China,Japan,Tofu)中,如果Tofu是具体类,那么China和Japan必须是抽象基类或混入。
(7)为用户提供聚合类;
聚合类是指一个类的结构主要继承自混入,自身没有添加结构或行为。Tkinter采纳了此条建议。
(8)优先使用对象组合,而不是类继承。
优先使用组合可以令设计更灵活。
组合和委托可以代替混入,但不能取代接口继承去定义类型层次结构。

注:super调用知识引自
作者: mozillazg
链接:https://segmentfault.com/a/11...


http://www.niftyadmin.cn/n/1670200.html

相关文章

foreach mysql 报错_MyBatis操作Oracle批量插入 ORA-00933: SQL 命令未正确结束

最近在使用MyBatis操作Oracle数据库的时候&#xff0c;进行批量插入数据&#xff0c;思路是封装一个List集合通过Myabtis的foreach标签进行循环插入&#xff0c;可是搬照Mysql的批量插入会产生 异常### Error updating database. Cause: java.sql.SQLSyntaxErrorException: OR…

《Windows服务器配置与管理》DNS服务器

工作任务描述公司名称是abc公司&#xff0c;搭建DNS服务器。总公司在北京&#xff0c;总公司的注册的域名为HT.com。你公司下属两个分支&#xff0c;第一个为亚洲公司(Asia)&#xff0c;公司总部在北京&#xff0c;第二个为欧洲公司(Europe)&#xff0c;请你在总公司上建立一台…

基于Apache CXF的Web Service服务端/客户端

转自&#xff1a;https://www.aliyun.com/zixun/wenji/1263190.html CXF服务端&#xff1a; [java] view plaincopy package com.sean.server; import javax.jws.WebParam; import javax.jws.WebService; WebService public interface Plus { public int add(WebP…

【 sql数据库 】把逗号分隔的字符串拆成临时表

方式一&#xff1a;通过charindex和substring。 create function func_splitstring(str nvarchar(max),split varchar(10))returns t Table (c1 varchar(100))asbegin declare i int declare s int set i1 set s1 while(i>0) begin set ichar…

计算机组成原理奉远侦,计算机组成原理所研究的内容是什么?

满意答案xzparc2015.10.16采纳率&#xff1a;46% 等级&#xff1a;12已帮助&#xff1a;6852人计算机组成原理是计算机应用和计算机软件专业以及其他相关专业必修的专业基础课&#xff0c;它主要讨论计算机各组成部件的基本概念、基本结构、工作原理及设计方法。教学实践证明…

Java 20年:JVM虚拟化技术的发展

虚拟化技术已经有了几十年的发展历史&#xff0c;并且在硬件、操作系统层面都已经得到了广泛的应用。虚拟化不但可以显著节省成本&#xff0c;而且还可以提升管理性。同样&#xff0c;虚拟化技术也可以应用在JVM中&#xff0c;以提高资源利用率&#xff0c;降低单应用的部署成本…

java中类本身是用this_Java语言:this用法

在Java语言中&#xff0c;this在JAVA中所代表的意思是当前类中的意思. 明确引用的是本类中的属性&#xff0c;希望对大家学习Java语言有所帮助。1. 在构造方法或是set方法中初始化类中的属性.class AA{String name;public AA(String name){this.namename; //如果不写this那肯定…

Weblogic新建域,Weblogic新建部署环境,Weblogic重新构建域

Weblogic新建域&#xff0c;Weblogic新建部署环境&#xff0c;Weblogic重新构建域 蕃薯耀 2018年1月29日 http://www.cnblogs.com/fanshuyao/ 看不到图片请移步&#xff1a;http://fanshuyao.iteye.com/blog/2409648 一、第一步点击&#xff1a;Configuration Wizard 二、第二…