Python 类继承,__bases__, __mro__, super
Python是面向对象的编程语言,也支持类继承。
>>> class Base:
... pass
...
>>> class Derived(Base):
... pass
这样就定义了两个类,Derived继承了Base。issubclass(a,b)能够測试继承关系:
>>> issubclass(Derived, Base)
True
在Python中,每一个类有一个__bases__属性,列出其基类
>>> Derived.__bases__
(<class '__main__.Base'>,)
同C++,Python支持多重继承;
>>> class Derived2(Derived,Base):
... pass
...
Derived2继承了Derived和Base(实际中不会这么写)
>>> Derived2.__bases__
(<class '__main__.Derived'>, <class '__main__.Base'>)
这里,Derived,和Base的顺序不能搞反
>>> class Derived2(Base, Derived):
... pass
...
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: Cannot create a consistent
method resolution
order (MRO) for bases Derived, Base
插一段C++
|
C++代码 |
|
class Base{ }; class Derived: public Base{ }; class Derived2: public Base, public Derived{ }; int main(){ } |
|
mulit_inherit.cc:7:7: warning: direct base 'Base' inaccessible in 'Derived2' due to ambiguity [enabled by default] class Derived2: public Base, public Derived{ ^ |
|
mulit_inherit.cc:7:7: warning: direct base 'Base' inaccessible in 'Derived2' due to ambiguity [enabled by default] class Derived2: public Derived, public Base{ ^ |
能够见,C++并没有限制书写顺序。warning指示了Derrived2中不能訪问Base
Derived2 d;
Base &b = d;
error: 'Base' is an ambiguous base of 'Derived2'
Base &b = d;
^
回到Python继承,Derived2是Derived的子类,也是Base的子类
>>> issubclass(Derived2, Base)
True
>>> issubclass(Derived2, Derived)
True
__bases__类似于Javascript中Object对象的__proto__,是实现继承的基础,不同在于:__bases__不可改动,并且__bases__是类的属性而不是对象属性(Javascript是基于对象的语言);
>>> d = Derived2()
>>> d.__bases__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'Derived2' object has no attribute '__bases__'
>>> d.__class__
<class '__main__.Derived2'>
>>> d.__class__.__bases__
(<class '__main__.Derived'>, <class '__main__.Base'>)
对象的__class__属性指明了所属类型;
>>> [].__class__
<class 'list'>
>>> ().__class__
<class 'tuple'>
>>> 1.__class__
File "<stdin>", line 1
1.__class__
^
SyntaxError: invalid syntax
>>> type(1)
<class 'int'>
在Python中1,是对象还是基本类型?
__mro__
__mro__给出了method resolution order,即解析方法调用的顺序。
>>> Derived.__mro__
(<class '__main__.Derived'>, <class '__main__.Base'>, <class 'object'>)
>>> Derived2.__mro__
(<class '__main__.Derived2'>, <class '__main__.Derived'>, <class '__main__.Base'>, <class 'object'>)
看上去和__bases__相像,仅仅是最后面多了个<class 'object'>
super
super函数能够用于调用父类的方法,而后者可能被子类覆盖;类似在java中的作用,但使用起来更复杂些。
>>> class Base:
... pass
...
>>> class Derived(Base):
... pass
...
>>> class Derived2(Derived)
File "<stdin>", line 1
class Derived2(Derived)
^
SyntaxError: invalid syntax
>>> class Derived2(Derived):
... pass
...
>>> d = Derived2()
>>> super(Derived2, d)
<super: <class 'Derived2'>, <Derived2 object>>
>>> super(Derived, d)
<super: <class 'Derived'>, <Derived2 object>>
>>> super(Base, d)
<super: <class 'Base'>, <Derived2 object>>
參考https://docs.python.org/2/library/functions.html#super,
super(type[, object-or-type])
Return a proxy object that
delegates method calls to a parent or sibling class of type. This is useful for accessing inherited methods that have been overridden in a class. The
search order is same as that used by getattr() except that the type itself is skipped.
The __mro__ attribute of the type
lists the method resolution search order used by both getattr() and
super().
>>> isinstance(super(Base, d), Base)
False
>>> isinstance(super(Derived, d), Base)
False
代理对象并非类层次中某个类的实例!
结合多重继承来理解下__mro__和super
class A:
def __init__(self):
print('enter __init__@A')
super(A,self).__init__()
print('exit __init__@A')
class B(A):
def __init__(self):
print('enter __init__@B')
super(B,self).__init__()
print('exit __init__@B')
class C(A):
def __init__(self):
print('enter __init__@C')
super(C,self).__init__()
print('exit __init__@C')
class D(A):
def __init__(self):
print('enter __init__@D')
super(D,self).__init__()
print('exit __init__@D')
class E(B,C):
def __init__(self):
print('enter __init__@E')
super(E,self).__init__()
print('exit __init__@E')
class F(E,D):
def __init__(self):
print('enter __init__@F')
super(F,self).__init__()
print('exit __init__@F')
if __name__ == '__main__':
A()
print(A.__mro__)
B()
print(B.__mro__)
C()
print(C.__mro__)
D()
print(D.__mro__)
E()
print(E.__mro__)
F()
print(F.__mro__)
执行结果
|
enter __init__@A exit __init__@A (<class '__main__.A'>, <class 'object'>) enter __init__@B enter __init__@A exit __init__@A exit __init__@B (<class '__main__.B'>, <class '__main__.A'>, <class 'object'>) enter __init__@C enter __init__@A exit __init__@A exit __init__@C (<class '__main__.C'>, <class '__main__.A'>, <class 'object'>) enter __init__@D enter __init__@A exit __init__@A exit __init__@D (<class '__main__.D'>, <class '__main__.A'>, <class 'object'>) enter __init__@E enter __init__@B enter __init__@C enter __init__@A exit __init__@A exit __init__@C exit __init__@B exit __init__@E (<class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>) enter __init__@F enter __init__@E enter __init__@B enter __init__@C enter __init__@D enter __init__@A exit __init__@A exit __init__@D exit __init__@C exit __init__@B exit __init__@E exit __init__@F (<class '__main__.F'>, <class '__main__.E'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.D'>, <class '__main__.A'>, <class 'object'>) |
观察到,super的运行路径和类的__mro__列举的类顺序吻合;而__mro__的顺序能够看作是深搜的结果
A
/ | \
B C D
\ / /
E /
\ /
F
class E(B, C)中,B和C不是基-派生类关系,E.__mro__中B在C之前,须要注意;
多态
>>> class Base:
... def sayHello(self):
... print("Base says hello")
...
>>> class Derived(Base):
... pass
...
>>> d = Derived()
>>> d.sayHello()
Base says hello
Derived重写sayHello
>>> class Derived(Base):
... def sayHello(self):
... print("Derived says hello");
...
>>> d = Derived()
>>> d.sayHello()
Derived says hello
与參数默认值结合(联想起了C++)
>>> class Base:
... def sayHello(self, str="Base"):
... print("Base says: " + str)
...
>>> class Derived(Base):
... def sayHello(self, str="Derived"):
... print("Dervied says: " + str)
...
>>>
>>> d = Derived()
>>> d.sayHello()
Dervied says: Derived
>>> Base.sayHello(d)
Base says: Base
>>> super(Derived, d).sayHello()
Base says: Base
看一下,在基类构造函数中调用被覆盖方法的行为
>>> class Base:
... def sayHello(self):
... str = self.getStr()
... print("Base says: " + str)
... def getStr(self):
... return "Base"
...
>>> class Derived(Base):
... def getStr(self):
... return "Derived"
...
>>>
>>> d = Derived()
>>> d.sayHello()
Base says: Derived
>>> def Base_init(self):
... self.sayHello()
...
>>> Base.__init__ = Base_init
>>> d = Derived()
Base says: Derived
可见,行为类似Java,调用了子类的覆盖方法;
Python 类继承,__bases__, __mro__, super的更多相关文章
- [修]python普通继承方式和super继承方式
[转]python普通继承方式和super继承方式 原文出自:http://www.360doc.com/content/13/0306/15/9934052_269664772.shtml 原文的错 ...
- python 类继承演示范例的代码
把做工程过程重要的代码片段备份一次,下面的资料是关于python 类继承演示范例的代码. # a simple example of a class inheritance # tested with ...
- python 全栈开发,Day20(object类,继承与派生,super方法,钻石继承)
先来讲一个例子 老师有生日,怎么组合呢? class Birthday: # 生日 def __init__(self,year,month,day): self.year = year self.m ...
- Python类继承(转发)
目录 一.概述 二.类的继承 2.1 继承的定义 2.2 构造函数的继承 2.3 子类对父类方法的重写 三.类继承的事例 回到顶部 一.概述 面向对象编程 (OOP) 语言的一个主要功能就是“继承”. ...
- 第7.7节 案例详解:Python类继承机制
本节实现一个类继承的小程序,下面一边结合代码一边介绍相关继承的知识.例子以车.汽车为例,车为父类.汽车为子类. 一. 定义父类Vehicle class Vehicle(): def __ ...
- python类继承
面向对象的编程带来的主要好处之一是代码的重用,实现这种重用的方法之一是通过 继承 机制.继承完全可以理解成类之间的 类型和子类型 关系. 假设你想要写一个程序来记录学校之中的教师和学生情况.他们有一些 ...
- python 类 - 继承
继承 什么是继承? 编写类时,并非总要从空白开始.如果要编写的类是另一个现成类的特殊版本,可使用继承. 一个类继承另一个类时,将自动获得另一个类的所有属性和方法.现有的类称为父类,而新类称为子类. 子 ...
- python类继承的重写和super
给已经存在的类添加新的行为,继承是非常好的实现方式.但是如果要改变行为呢?比如在Python继承扩展内置类,我们的contact类只允许一个名字和一个邮箱,但是如果要对某些人增加电话号码呢?这里可以通 ...
- 【Python】python 普通继承方式和super继承方式
Python中对象方法的定义很怪异,第一个参数一般都命名为self(相当于其它语言的this),用于传递对象本身,而在调用的时候则不必显式传递,系统会自动传递.举一个很常见的例子:>>&g ...
随机推荐
- Extjs实现树形结构三连选
当项目中需要一个部门人员选择或者省市县地域连选时,就需要树形结构的连选. 再此,写了一个简单的树形结构三连选功能,模拟从后台读取数据和处理数据(欢迎大家交流指正). 代码如下: 循环创建三棵树,其中只 ...
- SpringMVC记住密码功能
CookieTool (Cookie帮助类): package com.utcsoft.common.cookie; import java.util.HashMap; import java.uti ...
- PHP学习之-1.1 PHP 可以做什么?
PHP 可以做什么? 为什么要学习PHP,"我可以用javascript来实现程序的编写."但是javascript的能力是有限的,javascript通常运行在浏览器(客户端), ...
- actor简介
今天抽时间,给team做了一次actor介绍,现附上ppt actor 简介及应用
- HDU 4070 Phage War
贪心,t 大的放到前面...因为感染所有cell需要的phage的总数是一定的,所以产生phage需要的时间是一定的,只需要考虑用来感染的时间,这样考虑的话,把 t 小的放后面的话,可以发现总时间的最 ...
- S3C6410 纯粹的裸机启动,自己写的SD BOOT启动
这几天晚上一直折腾S3C6410的裸机SD卡启动,不大想使用UBOOT,我是搞硬件的,对底层非常感兴趣,不喜欢已经写好的,因此自己一直在尝试,其实很早之前就试过SD卡启动,也就是ARM11上电后会把S ...
- 几本不错的CPU设计以及VLSI的书籍
1. Microprocessor Design Principales and Practrices with VHDL 特点:电路与VHDL一一对应,比较清楚,而且还用MAX+plus进行仿真 ...
- 【ASP.NET Web API教程】5.4 ASP.NET Web API批处理器
原文:[ASP.NET Web API教程]5.4 ASP.NET Web API批处理器 注:本文是[ASP.NET Web API系列教程]的一部分,如果您是第一次看本系列教程,请先看前面的内容. ...
- 【PHP SDK for OpenStack/Rackspace APIs】身份验证
在你使用php-opencloud之前必须先取得云服务提供商的身份验证.这是整个过程中最简单也是最让人沮丧的部分. 说它最简单是因为你只需要两部分信息: 云服务提供商的身份验证端点 用来身份验证的证书 ...
- HDU 4981 Goffi and Median(水)
HDU 4981 Goffi and Median 思路:排序就能够得到中间数.然后总和和中间数*n比較一下就可以 代码: #include <cstdio> #include <c ...