4.2 类的继承

在编程中,类的好处我们知道了,通过类我们可以源源不断的实例化出对象,这些对象用有相同的属性和方法,大大提高了程序代码的复用性。
在某些情况下,如果想要创建一个新的类,这个类除了要有旧类的所有属性和方法,还有一些其他的属性和方法,那么重新再去定义它显示是不明智的,这个时候可以通过继承来实现。
继承是指一种代码组织方式,它允许同一个类中的成员共享它们的方法和数据结构。在编程中,继承通常是指使用同一个类的成员来创建新的类,而不是创建一个新的类。这是因为继承可以使代码更易于编写和维护,并且可以简化代码组织方式。
继承的优点:

  1. 增强代码的可扩展性:通过使用继承,可以创建多种不同类型的类,这些类可以被扩展到不同的应用场景。
  2. 提高代码的可维护性:通过使用继承,可以将相同类型的对象划分为多个小类,从而提高代码的可维护性。
    举个例子:现在创建了一个动物类:Animal,这个动物类具有两个方法,分别是,那么在程序中可以如此定义:
class Animal:
    def eat(self):
        print('我饿了')

    def sleep(self):
        print('我困了')
animal = Animal()
animal.eat()
animal.sleep()

我饿了
我困了

一般动物都具有这2个方法,这个Animal作为动物类的模板,具有动物最基本的方法。这个时候如果还要创建新的类,比如哺乳动物类、鸟类,那么就可以通过继承动物类来创建:

class Mammal(Animal):
    def walk(self):
        print('我会走')


class Bird(Animal):
    def fly(self):
        print('我会飞')


mammal = Mammal()
bird = Bird()
mammal.walk()
mammal.sleep()
bird.fly()
bird.eat()

我会走
我困了
我会飞
我饿了

我们看到,哺乳动物类和鸟类都继承了动物类的eatsleep方法,而他们各自又新建了新方法,分别是walkfly
在上面的例子中,Animal类Mammal类Bird类继承,则称Animal类Mammal类Bird类父类基类超类。而Mammal类Bird类Animal类子类
注意,子类是无法继承父类的私有属性和私有方法的:

from icecream import ic

class Animal:
    def __init__(self):
        self.a = 'A'
        self.__b = 'B'

    def __eat(self):
        ic('我饿了')

    def sleep(self):
        ic('我困了')

class Mammal(Animal):
    ...

mammal = Mammal()
ic(mammal.a)
mammal.sleep()
try:
    ic(mammal.__b)
except AttributeError as err:
    ic(err)
try:
    mammal.__eat()
except AttributeError as err:
    ic(err)

14:28:56|> mammal.a: ‘A’
14:28:57|> ‘我困了’
14:28:57|> err: AttributeError(“‘Mammal’ object has no attribute ‘__b’”)
14:28:57|> err: AttributeError(“‘Mammal’ object has no attribute ‘__eat’”)

4.2.1 __init__方法

在类的定义中,默认有一些以__开头和结尾的特殊方法,这些方法一般是用来处理一些特别的事情,这类方法通常称为魔术方法或魔法方法。
__init__方法就是众多魔法方法中一个非常重要的方法。在类的初始化成对象时会调用这个方法,一般是用来定义一些类的属性,运行一些需要在类初始化时就需要运行的自定义方法。

from icecream import ic


class Animal:
    def __init__(self, leg=4):
        self.leg = leg


a = Animal()
ic(a.leg)
b = Animal(3)
ic(b.leg)

14:49:39|> a.leg: 4
14:49:39|> b.leg: 3

在上面代码中,因为大部分动物都是4条腿,于是直接将Animal类的leg设置为4,这样在初始化后,a.leg输出的就是默认4。而后又用Animal类初始化了一个对象b,只不过这次传入的leg是3,那么在初始化是调用__init__方法后,输出b.leg就是3了。

4.2.2 super方法

通常子类可以直接调用父类中的方法,如果子类和父类同时都有__init__方法需要定义一些初始化的属性,那么在子类中直接调用__init__方法传入参数显然是不行的。

from icecream import ic


class Animal:
    def __init__(self, leg=4):
        self.leg = leg
        self.type = '双足动物' if self.leg == 2 else '非双足动物'


class Mammal(Animal):
    def __init__(self, leg):
        self.leg = leg


a = Animal()
ic(a.leg)
ic(a.type)
m = Mammal(leg=2)
ic(m.leg)
ic(m.type)

15:11:48|> a.leg: 4
15:11:48|> a.type: ‘非双足动物’
15:11:48|> m.leg: 2
Traceback (most recent call last):
File “E:\t3.py”, line 21, in
ic(m.type)
AttributeError: ‘Mammal’ object has no attribute ‘type’

我们看到,虽然Mammal类继承了Animal类,但是无法调用Animal类的self.type属性。这是因为初始化后仅运行了Mammal类中的__init__方法而未运行Animal类中的__init__方法导致的。
要想达到传入参数同时被子类和父类初始化引入,则只需要稍微修改一下代码,在子类初始化方法__init__中调用父类的__init__并传入相应的参数即可:

from icecream import ic


class Animal:
    def __init__(self, leg=4):
        self.leg = leg
        self.type = '双足动物' if self.leg == 2 else '非双足动物'


class Mammal(Animal):
    def __init__(self, leg):
        super().__init__(leg)


a = Animal()
ic(a.leg)
ic(a.type)
m = Mammal(leg=2)
ic(m.leg)
ic(m.type)

15:16:38|> a.leg: 4
15:16:39|> a.type: ‘非双足动物’
15:16:39|> m.leg: 2
15:16:39|> m.type: ‘双足动物’

4.2.3 issubclass (x, A_tuple)、isinstance(x, A_tuple)方法

这2个方法返回x是派生自另一个类还是同一个类。A_tuple可以是一个类也可以是包含多个类的tuple。如果是tuple,则:
issubclass(x, (A, B, …))等价于:isinstance(x, A) or isinstance(x, B)…
isinstance(x, (A, B, …))等价于:isinstance(x, A) or isinstance(x, B)…
这2个方法区别在于第一个参数x,对于issubclass方法,第一个参数x必须是类,而isinstance则必须是对象。

from icecream import ic


class Animal:
    ...


class Mammal(Animal):
    ...


class Bird:
    ...


class Person(Mammal):
    ...


a = Animal()
m = Mammal()
b = Bird()
p = Person()
ic(issubclass(m.__class__, a.__class__))
ic(issubclass(m.__class__, b.__class__))
ic(isinstance(p.__class__, a.__class__))
ic(isinstance(p, p.__class__))

15:36:24|> issubclass(m.class, a.class): True
15:36:24|> issubclass(m.class, b.class): False
15:36:24|> isinstance(p.class, a.class): False
15:36:24|> isinstance(p, p.class): True

物联沃分享整理
物联沃-IOTWORD物联网 » Python中类的继承详解

发表评论