Python中类的mro与继承关系详解(二)

目录
  • 前言
  • 多重继承
  • 思考片刻
  • 总结

前言

版本:

  • windows 10.0
  • python 3.8

多重继承

在Python数字比较与类结构中有简略提到类,且在Python中类的mro与继承关系详解稍有解释继承关系,用到一个基类Animal如下:

class Animal:
    property_ = '能够思考'

    def __init__(self, name, age, value):
        self.name_ = name
        self.age_ = age
        self.val_ = val

再定义Action活动作为另一个基类:

class Action:

    def __init__(self, action, val):
        self.action_ = action
        self.val_ = val
  • 现在需定义一个Dog类,不仅是动物,还能够跑,可以来继承上面两个类来定义:
class Dog(Animal, Action):

    def __init__(self, name, age, action, val):
        Animal.__init__(self, name, age, val+1)
        Action.__init__(self, action, val)

dog = Dog('大福', 8, '跑', 78)
print(dog.__dict__)
# {'name_': '大福', 'age_': 8, 'val_': 78, 'action_': '跑'}

发现打印出的实例属性,好像字典的键值更新,先初始化Animal时,val传入的值为79,而后被更新为78,这里为什么不能像继承单个类一样直接用super方法代替呢。

上一篇有提到mro解析顺序,可进行尝试,不重写__init__方法,发现Dog类只能传入三个参数,且都为Animal类的参数,因为继承的两个父类都有该方法,优先继承左边的父类方法,如果想都继承可以考虑这样的形式,然而会提高后续维护的困难性。

可以将最左边的父类改成super方式:

class Dog(Animal, Action):

    def __init__(self, name, age, action, val):
        super().__init__(name, age, val+1)
        Action.__init__(self, action, val)

mro解析顺序,与上面所述一致:

Dog.mro()
# [__main__.Dog, __main__.Animal, __main__.Action, object]
  • 祖孙类

如再进行继承,视Dog为父类,其Animal,Action都为祖父类,定义一个Pet类:

class Pet(Dog):
    pass
pet = Pet('大福', 8, '跑', 78)

传入参数,和实例化的对象跟Dog一样,如果需要改写某个方法,可以参照之前的方法进行改写,另外若在保留原方法的逻辑上进行补充则用super方法。

Pet类的mro:

Pet.mro()
# [__main__.Pet, __main__.Dog, __main__.Animal, __main__.Action, object]

思考片刻

通过上面的继承及对应的mro解析顺序,可以思考以下通过多重继承类后,输出的x属性值为多少:

class Alpha:
    def __init__(self, val):
        self.x = val

class Beta(Alpha):
    pass

class Gamma:
    def __init__(self, val):
        self.x = val + 1
class Omega(Gamma):
    def __init__(self, val):
        super().__init__(val + 1)
class Kappa(Beta, Omega):
    pass
k = Kappa(1)
print(k.x)

如果脑内没有一个mro解析顺序图,这里准备了:

[__main__.Kappa, __main__.Beta, __main__.Alpha, __main__.Omega, __main__.Gamma, object]

这里或许会有疑问,Beta后面不是Omega吗?怎么到Alpha了,可以先看下Omega,继承Gamma,而GammaAlpha并不是同源的,类似于Dog类的继承,那么优先就会使用Alpha的__init__方法,所以在传入参数值1的时候,仅运行了Alpha内的self.x = val,属性x被赋值成1,在最后print输出即为1,打印结果检查:

print(k.x)
# 1

若把Gamma类改成继承Alpha类,再次猜测print(k.x)的值为多少?

class Alpha:
    def __init__(self, val):
        self.x = val

class Beta(Alpha):
    pass

class Gamma(Alpha):
    def __init__(self, val):
        self.x = val + 1

class Omega(Gamma):
    def __init__(self, val):
        super().__init__(val + 1)

class Kappa(Beta, Omega):
    pass

k = Kappa(1)
print(k.x)

查看mro解析顺序:

[__main__.Kappa, __main__.Beta, __main__.Omega, __main__.Gamma, __main__.Alpha, object]

此时发现Alpha解析优先级排在最后,BetaOmega可以看做是BetaGamma的优先级比较,因为Omega继承Gamma,且重写了__init__方法,所以当传入参数时会对Gamma类的属性进行赋值,虽然Beta类直接继承Alpha,但Gamma类也直接继承,所以Alpha解析顺序需要排在Gamma后面,从而当Kappa类传入参数时,经过Omega的super加1,传入到Gamma处时为:self.x = val + 1中的val为2,输出的k.x的值即为3,查看打印结果:

print(k.x)
# 3

总结

通过连续两篇对类继承及mro解析顺序的说明,理解类在多重继承中的变化,无论继承多少遍,总归要回归本心,但也不能胡乱继承,有条理的,有意义的继承,才能让自己乃至他人更好理解当下写出的类。

到此这篇关于Python中类的mro与继承关系详解的文章就介绍到这了,更多相关Python mro内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Python高级编程之继承问题详解(super与mro)

    本文实例讲述了Python高级编程之继承问题.分享给大家供大家参考,具体如下: 多继承问题 1.单独调用父类: 一个子类同时继承自多个父类,又称菱形继承.钻石继承. 使用父类名.init(self)方式调用父类时: 例: class Parent(object): def __init__(self, name): self.name = name print('parent的init结束被调用') class Son1(Parent): def __init__(self, name, age

  • C3 线性化算法与 MRO之Python中的多继承

    目录 什么是 MRO New-style Class vs. Old-style Class 理解 old-style class 的 MRO 理解 new-style class 的 MRO C3线性化算法 Python 中的方法解析顺序(Method Resolution Order, MRO)定义了多继承存在时 Python 解释器查找函数解析的正确方式.当 Python 版本从 2.2 发展到 2.3 再到现在的 Python 3,MRO算法也随之发生了相应的变化.这种变化在很多时候影响

  • Python中类的mro与继承关系详解

    目录 前言 类 继承 mro 总结 前言 版本: windows 10.0 python 3.8 类 在Python数字比较与类结构中有简略提到类,那么什么是类呢? 在python中定义一个类很简单,使用关键字class就能实现. class Animal: pass 如何使用它,在类结构中称作实例化. animal = Animal() 这样,就有了一个Animal的实例. 继承 类的其中一个特性就是能够继承,把Animal类丰富下,将其作为基类: class Animal: property

  • Python多继承以及MRO顺序的使用

    多继承以及MRO顺序 1. 单独调用父类的方法 # coding=utf-8 print("******多继承使用类名.__init__ 发生的状态******") class Parent(object): def __init__(self, name): print('parent的init开始被调用') self.name = name print('parent的init结束被调用') class Son1(Parent): def __init__(self, name,

  • Python中类的mro与继承关系详解(二)

    目录 前言 多重继承 思考片刻 总结 前言 版本: windows 10.0 python 3.8 多重继承 在Python数字比较与类结构中有简略提到类,且在Python中类的mro与继承关系详解稍有解释继承关系,用到一个基类Animal如下: class Animal: property_ = '能够思考' def __init__(self, name, age, value): self.name_ = name self.age_ = age self.val_ = val 再定义Ac

  • python中类与对象之间的关系详解

    在搜索平台上关于类以及对象都已经被霸屏了,主要的问题无非就是两个,一个是理解二者,另一个就是理解二者之间的使用关系,对于小编来说,两者统一跟大家讲清,相信也很难被大家消化,这不,给大家想出来比较好理解的方式,用最简单的话,快速交大家上手,可别不信,简单易懂内容如下. 二者关系: 女生口红是一种类,但是mac.完美日记是口红里的个体,被称作是对象.这就是二者之间的关系,有人理解成包含情况也可以. 定义类/对象: class 类名(父类): class Human(object): pass man

  • 对Python Class之间函数的调用关系详解

    假设有Class A 和 Class B两个类,Class A中定义了a(),Class B中定义了b(). 现在我想在Class B中调用 Class A中的函数a().此处介绍三种调用方法: 方法一: 在Class B中所定义的fuction()中声明Class A的对象a,然后用对象a来调用Class A的函数a(). 最后在main中声明Class B的对象b,让b调用该类中的fuction(). #!/usr/bin/env python # -*- coding: utf-8 -*-

  • Python for循环与getitem的关系详解

    这篇文章主要介绍了Python for循环与getitem的关系详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 一个类里面如果由__iter__for循环就是找它取,没有的话就会找__getitem__ 前面一笔看过没有留心具体的执行情况. In [169]: class Foo: ...: def __getitem__(self, pos): ...: print(pos) ...: return range(10)[pos] ...:

  • Python中类的定义、继承及使用对象实例详解

    本文实例讲述了Python中类的定义.继承及使用对象的方法.分享给大家供大家参考.具体分析如下: Python编程中类的概念可以比作是某种类型集合的描述,如"人类"可以被看作一个类,然后用人类这个类定义出每个具体的人--你.我.他等作为其对象.类还拥有属性和功能,属性即类本身的一些特性,如人类有名字.身高和体重等属性,而具体值则会根据每个人的不同:功能则是类所能实现的行为,如人类拥有吃饭.走路和睡觉等功能.具体的形式如下: 例:类的概念: class 人类:             

  • Python面向对象之继承代码详解

    本文研究的主要是Python面向对象之继承的相关内容,具体如下. Python 继承 即一个派生类(derived class)继承基类(bass class)字段和方法.继承也允许把一个派生类的对象作为一个基类对象对待.例如,有这样一个设计,一个Cat类型的对象派生自Animal类,这是模拟"是一个(is-a)"关系(例如,Cat是一个Animal). 继承实现了代码的重用. 继承的基本语法: class 派生类名(基类名1 [, 基类名2....]): 基类名写在括号里,基本类是在

  • python多线程和多进程关系详解

    关于多线程的大概讲解: 在Python的标准库中给出了2个模块:_thread和threading,_thread是低级模块不支持守护线程,当主线程退出了时,全部子线程都会被强制退出了.而threading是高级模块,用作对_thread进行了封装支持守护线程.在大部分状况下人们只需要采用threading这个高级模块即可. 关于多进程的大概讲解: 多进程是multiprocessing模块给出远程与本地的并发,在一个multiprocessing库的采用场景下,全部的子进程全是由一个父进程运行

  • Python面向对象总结及类与正则表达式详解

    Python3 面向对象 -------------------------------------------------------------------------------- 一丶面向对象技术简介 •类(Class): 用来描述具有相同的属性和方法的对象的集合.它定义了该集合中每个对象所共有的属性和方法.对象是类的实例. •方法:类中定义的函数. •类变量:类变量在整个实例化的对象中是公用的.类变量定义在类中且在函数体之外.类变量通常不作为实例变量使用. •数据成员:类变量或者实例变

  • python之sqlalchemy创建表的实例详解

    python之sqlalchemy创建表的实例详解 通过sqlalchemy创建表需要三要素:引擎,基类,元素 from sqlalchemy import create_engine from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column,Integer,String 引擎:也就是实体数据库连接 engine = create_engine('mysql+pymysql://go

随机推荐