从0.1开始学Python——[21]

学完封装之后,类的知识里面还有一个内容,那就是继承。顾名思义,继承指的是从别人能力拿来他的东西,让这样东西继续发挥作用。

继承

举个例子,一个类里面有两个功能(方法),然后我后来想再建一个类,但是类里面想好的方法涵盖了这个建好的类里面的方法,只是具体内容有所出入,那我们可以直接修改已经建好的类么?不现实,因为违反之前讲到的OCP原则。那直接复制再加上自己的方法创一个新的类呢?效率低,Python主打的就是精简,复制粘贴岂不是最繁琐的表现,那综上所述,我们需要用继承,来省去繁琐的重复部分。使用方法也很简单,之前提到可填可不填的父类(也叫超类、super、基类等)就是继承的方法。而继承父类东西的新类就是子类(衍生类),可以直接继承父类的所有属性和方法

class Dongwufriends():
    def biejiao(self):
        print('动物别叫')

    def bizui(self):
        print('动物闭嘴')

class Xuebao(Dongwufriends):
    def zhishi(self):
        print('芝士雪豹')

xb = Xuebao()
xb.zhishi()
xb.biejiao()
芝士雪豹
动物别叫

就像这样。
由此可见,继承是扩展新建的类的功能的常用方法。另外,继承后的类创建的对象,既属于子类又属于父类

print(isinstance(xb,Xuebao))
print(isinstance(xb,Dongwufriends))
True
True

子类的子类也从属于一开始的父类。

isinstance()函数和issubclass()函数

当不填父类的时候,父类默认为object,也就是说所有类都继承自object。issubclass(对象1,对象2)函数就是用来判断前者(对象1)是不是后者(对象2)子类的。而之前讲到的isinstance(对象1,对象2)函数则是判断实例(对象1)是不是属于类(对象2)的函数。

print(issubclass(Xuebao,Dongwufriends))
print(issubclass(Dongwufriends,object))
True
True

方法的重写

当子类和父类里面有相同的方法的时候,调用时会调用子类的方法,这个叫做方法的重写

class Dongwufriends():
    def biejiao(self):
        print('动物别叫')

    def bizui(self):
        print('动物闭嘴')

class Xuebao(Dongwufriends):
    def zhishi(self):
        print('芝士雪豹')

    def bizui(self):
        print('雪豹闭嘴')

xb.bizui()

可以看到子类Xuebao()里面也有bizui(self)这个方法,但是和父类里面的方法内容不同,我们调用后发现:

雪豹闭嘴

结果是调用子类方法的结果。
如果是套娃,父类的子类还有子类等情况,而且调用了最小子类的某个方法时,将会按照从最小子类依次向上面最近父类查找的顺序找这个方法,先找到哪个就用哪个,找不到就报错。

class Dongwufriends():
    def biejiao(self):
        print('动物别叫')

    def bizui(self):
        print('动物闭嘴')

class Xuebao(Dongwufriends):
    def zhishi(self):
        print('芝士雪豹')

    def bizui(self):
        print('雪豹闭嘴')

class Ou(Xuebao):
    def hhh(self):
        pass

xb = Ou()
xb.biejiao()
xb.bizui()
动物别叫
雪豹闭嘴

super()方法

父类的所有方法,包括特殊方法,会被子类继承。所以,涉及到初始化变量这种会需要新建的对象进行赋值操作的特殊方法,会导致新建子类的对象也需要赋值,即使子类没有初始化变量这样的特殊方法。

class Dongwufriends():
    def __init__(self,name):
        self._name = name

    def biejiao(self):
        print('动物别叫')

    def bizui(self):
        print('动物闭嘴')

    @property
    def name(self):
        return self._name

    @name.setter
    def name(self,name):
        self._name = name

class Xuebao(Dongwufriends):
    def zhishi(self):
        print('芝士雪豹')

    def bizui(self):
        print('雪豹闭嘴')

class Ou(Xuebao):
    def hhh(self):
        pass
xb = Ou()
Traceback (most recent call last):
  File "D:/4classcode/4classcode/lianxi.py", line 758, in <module>
    xb = Ou()
TypeError: __init__() missing 1 required positional argument: 'name'
xb = Ou('雪豹')
print(xb.name)
雪豹

可见只有对xb进行赋值name属性的操作以后才能解决问题,想要子类有其他属性,可以重写特殊方法。但是,当子类里面有其他父类没有的属性,而父类里面初始化属性太多的时候,子类属性就会写很多重复的。而你不写这些重复属性对应形参,也会有问题,那就是定义子类对应新对象的时候,你不能输入这些父类的属性,自然也无法获取这些属性的值。

上略
class Ou(Xuebao):
    def __init__(self,color):
        self._color = color

xb = Ou('雪豹','白')
Traceback (most recent call last):
  File "D:/4classcode/4classcode/lianxi.py", line 758, in <module>
    xb = Ou('雪豹','白')
TypeError: __init__() takes 2 positional arguments but 3 were given

可见输入name属性值导致错误。

xb = Ou('白')

这样就不会报错,但是对象xb是注定没有name属性的。

print(xb.name)
Traceback (most recent call last):
  File "D:/4classcode/4classcode/lianxi.py", line 759, in <module>
    print(xb.name)
  File "D:/4classcode/4classcode/lianxi.py", line 742, in name
    return self._name
AttributeError: 'Ou' object has no attribute '_name'

解决方法是在子类里面调用父类.初始化变量特殊方法(self,其他属性),但是父类写上去无法更改,更改子类的父类的时候不方便。
所以为了解决这种问题,使用super()方法,用来动态获取当前类的父类,而且这个方法不用传递self变量

前略
class Ou(Xuebao):
    def __init__(self,name,color):
        super().__init__(name)
        self._color = color
xb = Ou('雪豹','白')
print(xb.name)
雪豹

多重继承

在很多情况下,一个类可以有好多父类,一个类也可以有很多子类。后面这个情况的效果可以通过定义很多类然后填入相同父类来实现,而前面的情况则可以在定义某个类的时候把多个类写在父类里面,这就是多重继承,这时这个类可以继承所有父类的方法和属性。获取一个类的所有父类,可以采用**类名.(双下划线)bases(双下划线)**的方法。

class Ou(Xuebao,Dongwufriends):
    def __init__(self,name,color):
        super().__init__(name)
        self._color = color

print(Ou.__bases__)
(<class '__main__.Xuebao'>, <class '__main__.Dongwufriends'>)

可以看出这样写Ou类的父类就是Xuebao(),Dongwufriends()两个。不过多重继承没必要频繁使用,因为不同父类里面有相同名方法的时候,只会以括号里前面书写的父类为准去使用,只有前面的没有这个名字的方法,才找后面的有没有。

xb.bizui()
雪豹闭嘴

另外,前面书写的父类自己如果还有父类,会先找它的父类,然后找后面书写的父类以及它的父类。也就是,调用方法:先找类自己->找第一个书写的父类->找第一个书写的父类的父类,如果也是多父类也按照这个套娃的顺序找->找第二个书写的父类->找第二个书写的父类的父类,如果也是多父类也按照这个套娃的顺序找->以此类推。在哪一部找到了,就使用这个方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值