Python面向对象特性 - 继承

面向对象有3大特性:继承、多态、封装,本章介绍 Python中的 继承 特性~
?

什么是继承

继承是创建类的一种方式,在 Python中支持多继承,即在创建类的时候可以继承一个或者多个父类。
在继承关系中,被继承的类通常称为父类(或超类,基类),新建的类则称为子类(或派生类)。
?
继承的优势在于可以有效地重用代码,提高代码的可读性~
?
继承示例:

class Fu_1:    # 父类
    pass

class Fu_2:    # 父类
    pass

class Zi_1(Fu_1):   # 单继承
    pass

class Zi_2(Fu_1, Fu_2):    # 多继承
    pass

?
上述示例中,Fu_1 和 Fu_2 没有继承任何类,在 Python3 中,这样就会默认继承object类,而在 Python2 中,默认不会继承 object类,注意区分 ~
?
可通过 类的内置属性 __bases__ 查看这个类 继承的所有父类

print(Zi_1.__bases__)
print(Zi_2.__bases__)

# 输出结果:
(<class ‘__main__.Fu_1‘>,)
(<class ‘__main__.Fu_1‘>, <class ‘__main__.Fu_2‘>)

重用与派生

重用

在开发过程中,若新建的一个类和已创建的另一个类 属性及方法大致相同,则可以让新建的类(子类)继承已创建的类(父类),这样子类会继承父类的所有属性,包括数据属性和函数属性,实现了代码重用,代码变得简洁,可以有效缩短开发周期~

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

    def say(self):
        print(‘Hello !‘)

class Son(Father):
    pass

p = Son(‘baby‘, 19)
p.say()

# 输出结果:
Hello !

?

派生

在继承过程中,子类也可以添加或者重新定义这些属性,当父类和子类中有同名的属性时(包括数据属性和函数属性),会先调用子类中的属性(操作的是子类的实例化对象)

class Father:
    city = ‘NB‘
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def say(self):
        print(‘Hello !   ‘ + self.city)

class Son(Father):
    city = ‘HZ‘
    def say(self):
        print(‘你好 ~   ‘ + self.city)

    def eat(self):
        pass

p = Son(‘baby‘, 19)
p.say()

# 输出结果:
你好 ~   HZ

super

在子类的函数中,若是要重用父类中某个函数的功能,可以直接通过 super 来调用父类中的函数,当然也可以通过 类名.func() 来调用,只不过这样与调用普通函数无异。这个经常使用在需要对父类的同名方法进行扩展的场景~

class Father:
    def say(self):
        print(‘Hello !‘)

    def introduce(self):
        print(‘Father‘)

class Son(Father):
    def say(self):
        super().say()
        # Father.say(self)   # 通过 类名.func(),输出结果一致
        print(‘你好 ~‘)

p = Son()
p.say()

# 输出结果
Hello !
你好 ~

上述示例中,使用 super的时候省略了2个参数:Son(当前类名称,注意不是父类),self(当前对象)

super().say()
# 等同于
super(Son, self).say()

由于 super 方法中已经默认传递了self参数,所以后面的函数不需要再次传递self~
?
注意:super关键字只在新式类中有,Python3中所有的类都是新式类...
?
在子类的函数中使用super方法,不一定仅调用同名的父类函数,也可以调用其他的父类函数~

def say(self):
        super().introduce()
        print(‘你好 ~‘)

?
如下示例中子类对父类的 init方法 进行了扩展,这是一种较为常用的使用方式~

class Father:
    def __init__(self, name, age):
        self.name = name
        self.age = age
    def say(self):
        print(‘Hello !‘)

class Son(Father):
    def __init__(self, name, age, hobby):
        super().__init__(name, age)
        self.hobby = hobby

    def say(self):
        super().say()
        print(‘你好 ~‘)

?
super方法不光可以在类的内部使用,也可以在类的外部的使用,在类的外部使用时,super方法不可以省略参数

# 外部使用super
p = Son()
super(Son, p).say()

# 输出结果:
Hello !

Python中多继承的继承顺序

上面已经说过,Python3 中所有的类都是新式类,新建的类没有继承任何类的时候,会默认继承 object 类。
在 Python2中,经典类和新式类并存,新建的类若是没有继承任何类,则这个类为经典类,只有显示地继承了 object 类或其子类,这个类才是新式类~

# Python2中
class C1:        # 经典类
    pass

class C2(C1):   # 经典类
    pass

class C3(object):   # 新式类
    pass

# Python3中
class N1:         # 新式类
    pass

class N2(N1):   # 新式类
    pass

class N3(object):   # 新式类
    pass

?
在Python中支持多继承,新式类和经典类的继承顺序有所差异,以下以钻石继承为例给出示例:

class A(object):
    def fun(self):
        print(‘from A‘)

class B(A):
    def fun(self):
        print(‘from B‘)

class C(A):
    def fun(self):
        print(‘from C‘)

class D(B):
    def fun(self):
        print(‘from D‘)

class E(C):
    def fun(self):
        print(‘from E‘)

class F(D, E):
    # def fun(self):
    #     print(‘from F‘)
    pass

上述多个类的继承关系如下图所示:

当前环境为Python3,即新式类,可通过内置的__mro__方法查看继承顺序:

f1 = F()
# f1.fun()
print(F.__mro__)

# 输出结果:
(<class ‘__main__.F‘>, <class ‘__main__.D‘>, <class ‘__main__.B‘>, <class ‘__main__.E‘>, <class ‘__main__.C‘>, <class ‘__main__.A‘>, <class ‘object‘>)

即新式类的继承顺序:F->D->B->E->C->A,广度优先。
那什么是继承顺序呢?就是寻找父类的顺序,例如这里调用 f1对象(F类的实例化对象)的 fun方法,若F类中没有这个方法,就去D类中寻找,若D类中也没有,就去B类中寻找,然后是E类,C类,A类,即按照 MRO列表上 从左到右查找基类~
?
若这里的类是经典类,则继承顺序为:F->D->B->A->E->C ,深度优先~
广度优先 与 深度优先 的区别在于,广度优先算法在查找基类的时候,若之后能找到的,则之后再进行查找,若之后找不到的,现在就去查找。例如,通过E,C也能再次找到A,则先不找A,但是通过E,C不能再次找到B,所以查找D之后就找B,查找B之后不会去查找A,而是在C之后再去查找A~
?
再看如下示例,由于B和C只能通过一条途径找到,所以新式类和经典类的继承顺序一致:

新式类继承顺序:F->D->B->E->C
经典类继承顺序:F->D->B->E->C

结合super的多继承顺序

若是在钻石继承中用到了 super 关键字,super 会去调用父类的对应方法,但是 super 的本质并不是直接找父类,而是根据调用者的节点位置的广度优先顺序来查找的。即 按照广度优先的继承顺序找到上一个类~
Tip:super 关键字只有在新式类中有,所以肯定是按照广度优先的继承顺序来进行查找的~
?

class A:
    def func(self):
        print(‘A‘)

class B(A):
    def func(self):
        super().func()
        print(‘B‘)

class C(A):
    def func(self):
        super().func()
        print(‘C‘)

class D(B, C):
    def func(self):
        super().func()
        print(‘D‘)

d = D()
d.func()

# 输出结果:
A
C
B
D

上述多个类的继承关系如下图所示:

当前使用的是新式类,继承顺序为:D->B->C->A(经典类的继承顺序为:F->B->A->C)
?
其中super的调用过程如下:
D类的 func() 方法中的 super().func() 会调用 B类的 func() 方法,B类的 func() 方法中的super().func() 会调用 C类的 func() 方法,C类的 func() 方法中的 super().func() 会调用 A类的 func() 方法~
?
当然在单继承中不会有这样的问题~
?
.................^_^

原文地址:http://blog.51cto.com/ljbaby/2348410

时间: 2024-12-27 21:55:16

Python面向对象特性 - 继承的相关文章

Python 面向对象特性二 多态(3-7)

接口类: 继承有两种用途: 一:继承基类的方法,并且做出自己的改变或者扩展(代码重用) 二:声明某个子类兼容于某基类,定义一个接口类Interface,接口类中定义了一些接口名(就是函数名)且并未实现接口的功能,子类继承接口类,并且实现接口中的功能 在Python中是没有接口的概念的(接口是在Java里的) from abc import ABCMeta,abstractmethod#调用abc模块中的抽象方法 # 接口类 : 接口类就是一个规范 接口类一般是项目设计人员写好的 class Pa

十七、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中,新建的类可以继承自一个或者多个父类,原始类称为基类或超类,新建的类称为派生类或子类. 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面向对象特性 - 封装

类中的私有属性 私有属性包括私有变量和私有方法,在 Python 中,在变量名或者方法名前面加上双下划线,这个属性就成为了类的私有属性.? class Person: def __init__(self, name, age): self.__name = name self.__age = age def __fun(self): print(self.__class__) def say(self): self.__fun() # 自动转换为 调用 _Person__fun 方法 print

python -- 面向对象编程(继承、重写)

一.继承 子类可以继承父类的所有公有成员,但不能直接访问父类的私有成员,只能通过父类的公有方法间接访问私有属性或私有方法. 如: class DerviedClassName(BaseClassName1[,BaseClassName2,......]): 语句1 语句2 ....... 语句N 公有属性既可以在类的内部进行访问,也可以在外部程序中使用. 派生类(子类)继承了基类(父类)的行为和属性之后,还可以增加某些特定的行为和属性. 继承分为单继承和多继承 A.单继承 # ---------

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面向对象之继承

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.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