18.Python面向对象之:继承

一:什么面向对象的继承?

比较官方的说法就是:

  继承(英语:inheritance)是面向对象软件技术当中的一个概念。

如果一个类别A“继承自”另一个类别B,就把这个A称为“B的子类别”,

而把B称为“A的父类别”也可以称“B是A的超类”。继承可以使得子类别

具有父类别的各种属性和方法,而不需要再次编写相同的代码。在令子

类别继承父类别的同时,可以重新定义某些属性,并重写某些方法,即覆

盖父类别的原有属性和方法,使其获得与父类别不同的功能。另外,为子类

别追加新的属性和方法也是常见的做法。 一般静态的面向对象编程语言,继承

属于静态的,意即在子类别的行为在编译期就已经决定,无法在执行期扩充。

字面意思就是:子承父业,合法继承家产,就是如果你是独生子,而且你也

很孝顺,不出意外,你会继承你父母所有家产,他们的所有财产都会由你使用

(败家子儿除外)。

那么用一个例子来看一下继承:

class Person:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex

class Cat:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex

class Dog:
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex

# 继承的用法:
class Aniaml(object):
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex

class Person(Aniaml):
pass

class Cat(Aniaml):
pass

class Dog(Aniaml):
pass

继承的有点也是显而易见的:

1,增加了类的耦合性(耦合性不宜多,宜精)。

2,减少了重复代码。

3,使得代码更加规范化,合理化。

二 继承的分类

就向上面的例子:

Aminal 叫做父类,基类,超类。
Person Cat Dog: 子类,派生类。
继承:可以分单继承,多继承

这里需要补充一下python中类的种类(继承需要):

在python2x版本中存在两种类.:
  ?个叫经典类. 在python2.2之前. ?直使?的是经典类. 经典类在基类的根如果什么都不写.
  ?个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使?的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

三.单继承

3.1 类名,对象执行父类方法

class Aniaml(object):
type_name = ‘动物类‘

def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex

def eat(self):
print(self)
print(‘吃东西‘)

class Person(Aniaml):
pass

class Cat(Aniaml):
pass

class Dog(Aniaml):
pass

# 类名:
print(Person.type_name) # 可以调用父类的属性,方法。
Person.eat(111)
print(Person.type_name)

# 对象:
# 实例化对象
p1 = Person(‘春哥‘,‘男‘,18)
print(p1.__dict__)
# 对象执行类的父类的属性,方法。
print(p1.type_name)
p1.type_name = ‘666‘
print(p1)
p1.eat()

类名,对象分别调用父类方法

3.2 执行顺序

class Aniaml(object):
type_name = ‘动物类‘
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex

def eat(self):
print(self)
print(‘吃东西‘)

class Person(Aniaml):

def eat(self):
print(‘%s 吃饭‘%self.name)

class Cat(Aniaml):
pass

class Dog(Aniaml):
pass

p1 = Person(‘barry‘,‘男‘,18)
# 实例化对象时必须执行__init__方法,类中没有,从父类找,父类没有,从object类中找。
p1.eat()
# 先要执行自己类中的eat方法,自己类没有才能执行父类中的方法。

执行顺序

3.3同时执行类以及父类方法

方法一:

如果想执行父类的func方法,这个方法并且子类中夜用,那么就在子类的方法中写上:

父类.func(对象,其他参数)

举例说明:

class Aniaml(object):
type_name = ‘动物类‘
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex

def eat(self):
print(‘吃东西‘)

class Person(Aniaml):
def __init__(self,name,sex,age,mind):
‘‘‘
self = p1
name = ‘春哥‘
sex = ‘laddboy‘
age = 18
mind = ‘有思想‘
‘‘‘
# Aniaml.__init__(self,name,sex,age) # 方法一
self.mind = mind

def eat(self):
super().eat()
print(‘%s 吃饭‘%self.name)
class Cat(Aniaml):
pass

class Dog(Aniaml):
pass

# 方法一: Aniaml.__init__(self,name,sex,age)
# p1 = Person(‘春哥‘,‘laddboy‘,18,‘有思想‘)
# print(p1.__dict__)

# 对于方法一如果不理解:
# def func(self):
# print(self)
# self = 3
# func(self)

方法二:

利用super,super().func(参数)

class Aniaml(object):
type_name = ‘动物类‘
def __init__(self,name,sex,age):
self.name = name
self.age = age
self.sex = sex

def eat(self):
print(‘吃东西‘)

class Person(Aniaml):
def __init__(self,name,sex,age,mind):
‘‘‘
self = p1
name = ‘春哥‘
sex = ‘laddboy‘
age = 18
mind = ‘有思想‘
‘‘‘
# super(Person,self).__init__(name,sex,age) # 方法二
super().__init__(name,sex,age) # 方法二
self.mind = mind

def eat(self):
super().eat()
print(‘%s 吃饭‘%self.name)
class Cat(Aniaml):
pass

class Dog(Aniaml):
pass
# p1 = Person(‘春哥‘,‘laddboy‘,18,‘有思想‘)
# print(p1.__dict__)

单继承练习题:

# 1
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)

class Foo(Base):
pass
obj = Foo(123)
obj.func1() # 123 运?的是Base中的func1

# 2
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
class Foo(Base):
def func1(self):
print("Foo. func1", self.num)
obj = Foo(123)
obj.func1() # Foo. func1 123 运?的是Foo中的func1

# 3
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
class Foo(Base):
def func1(self):
print("Foo. func1", self.num)
obj = Foo(123)
obj.func1() # Foo. func1 123 运?的是Foo中的func1
# 4
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print("Base.func2")
class Foo(Base):
def func2(self):
print("Foo.func2")
obj = Foo(123)
obj.func1() # 123 Foo.func2 func1是Base中的 func2是?类中的
# 再来
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print(111, self.num)
class Foo(Base):
def func2(self):
print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
obj.func2() # 111 1 | 111 2 | 222 3

# 再来
class Base:
def __init__(self, num):
self.num = num
def func1(self):
print(self.num)
self.func2()
def func2(self):
print(111, self.num)
class Foo(Base):
def func2(self):
print(222, self.num)
lst = [Base(1), Base(2), Foo(3)]
for obj in lst:
obj.func1() # 那笔来吧. 好好算

四.多继承

class ShenXian: # 神仙
def fei(self):
print("神仙都会?")
class Monkey: # 猴
def chitao(self):
print("猴?喜欢吃桃?")
class SunWukong(ShenXian, Monkey): # 孙悟空是神仙, 同时也是?只猴
pass
sxz = SunWukong() # 孙悟空
sxz.chitao() # 会吃桃?
sxz.fei() # 会?

此时, 孙悟空是?只猴?, 同时也是?个神仙. 那孙悟空继承了这两个类. 孙悟空?然就可以执?这两个类中的?法.

多继承?起来简单. 也很好理解. 但是多继承中, 存在着这样?个问题. 当两个?类中出现了重名?法的时候.

这时该怎么办呢? 这时就涉及到如何查找?类?法的这么?个问题.即MRO(method resolution order) 问题.

在python中这是?个很复杂的问题. 因为在不同的python版本中使?的是不同的算法来完成MRO的.

这里需要补充一下python中类的种类(继承需要):

在python2x版本中存在两种类.:
  ?个叫经典类. 在python2.2之前. ?直使?的是经典类. 经典类在基类的根如果什么都不写.
  ?个叫新式类. 在python2.2之后出现了新式类. 新式类的特点是基类的根是object类。
python3x版本中只有一种类:
python3中使?的都是新式类. 如果基类谁都不继承. 那这个类会默认继承 object

4.1经典类的多继承

虽然在python3中已经不存在经典类了. 但是经典类的MRO最好还是学?学. 这是?种树形结构遍历的?个最直接的案例.

在python的继承体系中. 我们可以把类与类继承关系化成?个树形结构的图. 来, 上代码:

class A:
pass
class B(A):
pass
class C(A):
pass
class D(B, C):
pass
class E:
pass
class F(D, E):
pass
class G(F, D):
pass
class H:
pass
class Foo(H, G):
pass

代码示例

对付这种mro画图就可以:

继承关系图已经有了. 那如何进?查找呢? 记住?个原则. 在经典类中采?的是深度优先,遍历?案. 什么是深度优先.

就是?条路走到头. 然后再回来. 继续找下?个.

图中每个圈都是准备要送鸡蛋的住址. 箭头和?线表?线路. 那送鸡蛋的顺序告诉你入?在最下?R. 并且必须从左往右送. 那怎么送呢?

如图. 肯定是按照123456这样的顺序来送. 那这样的顺序就叫深度优先遍历. ?如果是142356呢? 这种被称为?度优先遍历. 好了.

深度优先就说这么多. 那么上?那个图怎么找的呢? MRO是什么呢? 很简单. 记住. 从头开始. 从左往右. ?条路跑到头, 然后回头.

继续?条路跑到头. 就是经典类的MRO算法.

4.2.1 mro序列

MRO是一个有序列表L,在类被创建时就计算出来。
通用计算公式为:

mro(Child(Base1,Base2)) = [ Child ] + merge( mro(Base1), mro(Base2), [ Base1, Base2] )(其中Child继承自Base1, Base2)

类的MRO: Foo-> H -> G -> F -> E -> D -> B -> A -> C. 你猜对了么?

如果继承至一个基类:class B(A) 
这时B的mro序列为

mro( B ) = mro( B(A) )
= [B] + merge( mro(A) + [A] )
= [B] + merge( [A] + [A] )
= [B,A]如果继承至多个基类:class B(A1, A2, A3 …) 这时B的mro序列
mro(B) = mro( B(A1, A2, A3 …) )
= [B] + merge( mro(A1), mro(A2), mro(A3) ..., [A1, A2, A3] )
= ...计算结果为列表,列表中至少有一个元素即类自己,如上述示例[A1,A2,A3]。merge操作是C3算法的核心。

4.2.2. 表头和表尾
表头: 
  列表的第一个元素

表尾: 
  列表中表头以外的元素集合(可以为空)

示例 
  列表:[A, B, C] 
  表头是A,表尾是B和C

4.2.3. 列表之间的+操作
+操作:

[A] + [B] = [A, B]
(以下的计算中默认省略)
---------------------

merge操作示例:

如计算merge( [E,O], [C,E,F,O], [C] )
有三个列表 : ① ② ③
merge不为空,取出第一个列表列表①的表头E,进行判断
各个列表的表尾分别是[O], [E,F,O],E在这些表尾的集合中,因而跳过当前当前列表
取出列表②的表头C,进行判断
C不在各个列表的集合中,因而将C拿出到merge外,并从所有表头删除
merge( [E,O], [C,E,F,O], [C]) = [C] + merge( [E,O], [E,F,O] )
进行下一次新的merge操作 ......
---------------------

计算mro(A)方式:

mro(A) = mro( A(B,C) )

原式= [A] + merge( mro(B),mro(C),[B,C] )

mro(B) = mro( B(D,E) )
= [B] + merge( mro(D), mro(E), [D,E] ) # 多继承
= [B] + merge( [D,O] , [E,O] , [D,E] ) # 单继承mro(D(O))=[D,O]
= [B,D] + merge( [O] , [E,O] , [E] ) # 拿出并删除D
= [B,D,E] + merge([O] , [O])
= [B,D,E,O]

mro(C) = mro( C(E,F) )
= [C] + merge( mro(E), mro(F), [E,F] )
= [C] + merge( [E,O] , [F,O] , [E,F] )
= [C,E] + merge( [O] , [F,O] , [F] ) # 跳过O,拿出并删除
= [C,E,F] + merge([O] , [O])
= [C,E,F,O]

原式= [A] + merge( [B,D,E,O], [C,E,F,O], [B,C])
= [A,B] + merge( [D,E,O], [C,E,F,O], [C])
= [A,B,D] + merge( [E,O], [C,E,F,O], [C]) # 跳过E
= [A,B,D,C] + merge([E,O], [E,F,O])
= [A,B,D,C,E] + merge([O], [F,O]) # 跳过O
= [A,B,D,C,E,F] + merge([O], [O])
= [A,B,D,C,E,F,O]
---------------------

结果OK. 那既然python提供了. 为什么我们还要如此?烦的计算MRO呢? 因为笔
试.......你在笔试的时候, 是没有电脑的. 所以这个算法要知道. 并且简单的计算要会. 真是项?
开发的时候很少有?这么去写代码. 
这个说完了. 那C3到底怎么看更容易呢? 其实很简单. C3是把我们多个类产?的共同继
承留到最后去找. 所以. 我们也可以从图上来看到相关的规律. 这个要?家??多写多画图就
能感觉到了. 但是如果没有所谓的共同继承关系. 那?乎就当成是深度遍历就可以了

原文地址:https://www.cnblogs.com/xuweng/p/12181526.html

时间: 2024-07-29 13:28:04

18.Python面向对象之:继承的相关文章

Python面向对象特性 - 继承

面向对象有3大特性:继承.多态.封装,本章介绍 Python中的 继承 特性~? 什么是继承 继承是创建类的一种方式,在 Python中支持多继承,即在创建类的时候可以继承一个或者多个父类.在继承关系中,被继承的类通常称为父类(或超类,基类),新建的类则称为子类(或派生类).?继承的优势在于可以有效地重用代码,提高代码的可读性~?继承示例: class Fu_1: # 父类 pass class Fu_2: # 父类 pass class Zi_1(Fu_1): # 单继承 pass class

python面向对象之继承与派生

一.继承 继承是一种创建新的类的方式,在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类. python中类的继承分为:单继承和多继承,如果是多继承的话,继承顺序有深度和广度2种 示例: class ParentClass1: #定义父类 pass class ParentClass2: #定义父类 pass class SubClass1(ParentClass1): #单继承,基类是ParentClass1,派生类是SubClass pass

python面向对象之继承/多态/封装

老师说,按继承/多态/封装这个顺序来讲. 子类使用父类的方法: #!/usr/bin/env python # coding:utf-8 class Vehicle: def __init__(self,name,speed,load,power): self.name = name self.speed = speed self.load = load self.power = power def run(self): print("开动啦.") class Benz(Vehicle

十七、Python面向对象之继承

在面向对象,继承是一个很重要的特性 子类与父类,子类是对父类的一种扩展,在父类的属性和方法上进行一些扩展 示例:没带继承 #定义一个带编号和状态的门的类 class Door(object): def __init__(self,num,status): self.num = num self.status = status def open(self): self.status = 'open' def close(self): self.status = 'close' #定义一个可以锁的门

Python面向对象之继承

python不支持多态 代码区: 1 class UniversityMember: 2 def __init__(self, name, age): 3 self.name = name; 4 self.age = age; 5 6 # 实例方法 7 def getName(self): 8 return self.name; 9 10 def getAge(self): 11 return self.age; 12 13 # 子类学生类继承父类 14 class Student(Univer

python 面向对象四 继承和多态

一.继承 1 class Animal(object): 2 def run(self): 3 print('Animal is running...') 4 5 class Dog(Animal): 6 7 def run(self): 8 print('Dog is running...') 9 10 def eat(self): 11 print('Eating meat...') 12 13 dog = Dog() 14 dog.run() 1 Dog is running... 当子类

python面向对象的继承

无话可说,继承主要是一些父类继承,代码是非常具体的 #!/usr/bin/env python #coding:utf-8 class Father(object):#新式类 def __init__(self): self.name='Liu' self.FamilyName='Yan' def Lee(self): print '我是父类函数Lee' def Allen(self): print "我是父类函数Allen" class Son(Father): def __init

Python 面向对象编程——继承和多态

1.1   继承和多态 1.1.1   继承 当我们定义一个class的时候,可以从某个现有的class继承,新的class称为子类(Subclass),而被继承的class称为基类.父类或超类(Base class.Super class). >>> class Animal(object): ...    def run(self): ...        print('Animal is running...') #父类 ... >>> class Dog(Ani

Java ,python面向对象的继承及其区别

JAVA JAVA继承基本样式 class Demo extends Object{ Demo(int a){ this(); } Demo(){ super(); } } java默认继承Object 类, 并一定会在构造函数中调用super()方法,对父类进行实例化.注意:this()和super()不能同时出现在同一个构造函数中,但super()必须在其中一个构造函数中出现! Java实例化过程 运行父类的静态代码部分 再运行子类的静态代码部分 执行父类成员代码 执行父类构造函数 -- 父