面向对象特性:继承

单继承与多继承
Python中类的继承分为单集成和多继承

#继承例子
class ParentClass1:
    pass


class ParentClass2:
    pass


class SubClass1(ParentClass1): 这个是单继承,即只继承了一个父类的属性
    pass


class SubClsabb2(ParentClass1, ParentClass2):#这个是多继承,即继承了多个父类的属性
    pass 

继承的作用
类的继承的含义是子类获得父类的属性,这个属性包括类的数据属性和类的函数属性

class Dad:
    "这是个爸爸类"
    money = 10000

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

    def hit_son(self):
        print("%s正在打儿子" % self.name)

class Son(Dad):
    pass

f1 = Dad("Alex")
s1 = Son("Alex1")
print(s1.name)
print(s1.money)
s1.hit_son()
print(s1.__dict__)
print(f1.__dict__)

即Son继承了包括__init__在内的Dad的全部属性(不会继承类的文本)。
如果子类属性和父类属性重名,则子类的实例对象在调用某一函数的时候,会现在自己的类中找,再到父类中找(不是覆盖父类属性),即子类可以定义自己的属性

class Dad:
    "这是个爸爸类"
    money = 10000

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

    def hit_son(self):
        print("%s正在打儿子" % self.name)


class Son(Dad):
    def hit_son(self):
        print("%s从不打儿子" % self.name)


f1 = Dad("Alex")
s1 = Son("Alex1")
print(s1.name)
print(s1.money)
s1.hit_son()
print(s1.__dict__)
print(f1.__dict__)

继承的作用
当类之间有显著不同,并且较小的类是较大的类的所需组件时,用组合比较好
当类之间有很多相同的功能,提取这些相同的功能做成基类,用继承比较好

例如:

#猫和狗都会叫、吃、喝、拉、撒,区别是猫和狗的叫法不同,就可以将除了叫以外的动作定义为动物基类

class Animal:
    def eat(self):
        print("It is eating")

    def drink(self):
        print("It is eating")

    def poop(self):
        print("It is pooping ")

    def pee(self):
        print("It is peeing")


class Cat(Animal):#继承父类是一种继承
    def howl(self):#定义新的方法是一种派生
        print("喵")


class Dog(Animal):
    def howl(self):
        print("汪")

继承的两种含义
Python中继承有两种含义:
1.继承基类的方法,并且做出自己的改变或者扩展(解决代码重用)
2.声明某个子类兼容于基类,即定义一个接口类,子类承接接口类

在第一种含义中,为了避免代码重用会导致逻辑的耦合,而编程要尽量避免逻辑的耦合,所以第一种含义的意义不大,甚至常常有害

接口继承例子如下:

#模拟Linux的一切皆文件
class All_file:
    def read(self):
        pass

    def write(self):
        pass


class Disk(All_file):
    def read(self):
        print("Disk is reading")

    def write(self):
        print("Disk is writing")


class Cdrom(All_file):
    def read(self):
        print("Cdrom is reading")

    def write(self):
        print("Cdrom is writing")

这就是接口继承,表示一个类如果承接父类,那么它一定要实现所有父类中的属性,属性在父类中不实现,在子类中实现(即父类作出要求,子类需要实现)。
但是按照如上所写,子类如果不去实现依然可以调用到父类的属性,对子类是否实现没有限制,为了限制子类必须实现,采用abc模块

import abc

class All_file(metaclass=abc.ABCMeta):#注意这里定义接口类时需要传入参数
    @abc.abstractmethod#写入装饰器
    def read(self):
        pass

    @abc.abstractmethod
    def write(self):
        pass


class Disk(All_file):
    def read(self):
        print("Disk is reading")

    def write(self):
        print("Disk is writing")


class Cdrom(All_file):

    def read(self):
        print("Cdrom is reading")

    def write(self):
        print("Cdrom is writing")


C1 = Cdrom()
C1.write()

这样就做到了如果子类不实现父类要求的接口,子类的实例调用接口属性就会报错,这就是接口继承,接口本质上就是函数

接口继承的意义在于使得使用者无需具体关心细节,一视同仁的处理特定接口的所有对象,这在程序设计上叫做归一化

归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象


继承顺序

python的类可以继承多个类,java、C只能继承一个类
在python中继承顺序有深度优先和广度优先两种(先左后右是基本顺序)

class A:
    def test(self):
        print("A")


class B(A):
    def test(self):
        print("B")


class C(A):
    def test(self):
        print("C")


class D(B):
    def test(self):
        print("D")


class E(C):
    def test(self):
        print("E")


class F(D, E):
    def test(self):
        print("F")


f = F()
f.test()

如上的继承顺序,深度优先情况下会按照F-D-B-A-E-C的顺序寻找test函数
广度优先的情况下会按照F-D-B-E-C-A的顺序寻找test函数

经典类采用深度优先的继承顺序,新式类采用广度优先的继承顺序

在python3中,由于所有的类都是新式类,所以所有类的继承顺序都是广度优先
在python2中,就需要区分经典类和新式类来看继承顺序

#什么是经典类
class C1: #C1是经典类
	pass

class C2(C1):#C2是经典类
	pass
#什么是新式类
class C1(object): #C1是新式类
	pass

class C2(C1):#C2是新式类
	pass

python实现继承是通过方法解析顺序(MRO)列表,就是一个所有基类先行顺序列表的方式。

class A:
    def test(self):
        print("A")


class B(A):
    def test(self):
        print("B")


class C(A):
    def test(self):
        print("C")


class D(B):
    def test(self):
        print("D")


class E(C):
    def test(self):
        print("E")


class F(D, E):
    def test(self):
        print("F")


print(F.__mro__)

由于python3中都是新式类,所以python3中所有的类mro列表的最后一项都是object


子类调用父类的方法

有时候需要在子类中调用父类的方法

class Vehicle:
    country = "China"

    def __init__(self, name, speed, load, power):
        self.name = name
        self.speed = speed
        self.load = load
        self.power = power

    def run(self):
        print("开动啦")


class Subway(Vehicle):
    def __init__(self, name, speed, load, power, line):
        self.name = name
        self.speed = speed
        self.load = load
        self.power = power
        self.line = line

    def run(self):
        Vehicle.run(self)#此处调用了父类的run函数


s1 = Subway("地铁", "100km/h", 1000, "电力", 11)
s1.run()

__init__内有父类的代码重用,也利用父类的__init__方法

class Vehicle:
    country = "China"

    def __init__(self, name, speed, load, power):
        self.name = name
        self.speed = speed
        self.load = load
        self.power = power

    def run(self):
        print("开动啦")


class Subway(Vehicle):
    def __init__(self, name, speed, load, power, line):
        Vehicle.__init__(self, name, speed, load, power)#__init__函数本质上返回self字典,所以对子函数无影响
        self.line = line

    def run(self):
        Vehicle.run(self)


s1 = Subway("地铁", "100km/h", 1000, "电力", 11)
s1.run()

而如果父类改名,需要酱紫类中的内容全部修改,所以利用super()函数

class Vehicle:
    country = "China"

    def __init__(self, name, speed, load, power):
        self.name = name
        self.speed = speed
        self.load = load
        self.power = power

    def run(self):
        print("开动啦")


class Subway(Vehicle):
    def __init__(self, name, speed, load, power, line):
        super().__init__(name, speed, load, power)#无需self,super()内无需参数
        self.line = line

    def run(self):
        Vehicle.run(self)


s1 = Subway("地铁", "100km/h", 1000, "电力", 11)
s1.run()

super()–>same as super(class,) 所以此处的super()就相当于super(Subway)(self, name, speed, load, power)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值