Python Class 类的继承与多继承

本文介绍了Python中的类继承概念,包括继承的访问控制、示例、多继承及其解决冲突的算法、类装饰器的使用、类抽象方法以及函数和类方法名称的注意事项。通过多个示例详细阐述了如何在Python中实现和使用继承,特别是多继承的应用和潜在问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、继承概念

  • 面向对象的三要素之一:继承 inheritance

  • 在面向对象的世界中,从父类继承,就可以直接拥有父类的属性和方法,这样可以减少代码、多复用。子类可以定义自己的属性和方法

  • 继承: class 子类(父类) 这种形式就是从父类继承,括号中写上继承的类的列表。继承可以让子类从父类获取特征(属性和方法)

  • 父类:也称为 基类 超类

  • 子类:也称为 派生类

  • 定义:

    class 子类名(基类1[, 基类2, ...]):
        语句块
    
  • 如果定义时,没有基类列表,等同于继承object

  • 在Python3中, object类是所有对象的根基类

  • Python支持多继承,继承也可以多级

  • 查看继承的特殊属性和方法有:
    在这里插入图片描述

2、继承中的访问控制

  • 从父类继承,自己没有的,就可以到父类中找
  • 私有的都是不可以访问的,但是本质上依然是改了名称放在这个属性所在类或实例的__dict__中,知道这个新名称就可以直接找到这个隐藏的变量,这是个黑魔法技巧,慎用
  • 继承时,共有的,子类和实例都可以随意访问;私有成员被隐藏,子类和实例不可直接访问,但私有变量所在的类内的方法中可以访问这个私有变量
  • 私有属性最好只在当前类中使用,修改名称时,在哪个类里修改为哪个类的名称
  • 实例属性查找顺序:实例的__dict__ ===> 类__dict__ === 如果有继承 ===> 父类__dict
  • 继承关系中,同一种方法,在不同的类中有不同的表现方法,这就叫Python的多态
  • 自己的私有属性,就该自己的方法读取和修改,不要借助其他类的方法,即使是父类或者派生类的方法
  • 作为好的习惯,如果父类定义了__init__方法,就该在子类的__init__中调用它

3、示例

3.1 示例 1

class Animal:
    def __init__(self, name):
        self._name = name
        
    def shout(self):
        print('{} shouts.'.format(self.__class__.__name__))
        
    @property
    def name(self):
        return self._name
    
a = Animal('Monster')
a.shout()  # Animal shouts.
a.name  # 'Monster'

class Dog(Animal):
    pass

dog = Dog('Maltese')
dog.shout()  # Dog shouts.
dog.name  # 'Maltese'

class Cat(Animal):
    pass

cat = Cat('Garfield')
cat.shout()  # Cat shouts.
cat.name  # 'Garfield'
Cat.__base__  # __main__.Animal   
Cat.__bases__  # (__main__.Animal,)
Cat.__mro__  # (__main__.Cat, __main__.Animal, object)
Cat.mro()  # [__main__.Cat, __main__.Animal, object]
Animal.__subclasses__()  # [__main__.Dog, __main__.Cat]

3.2 示例 2

看懂如下示例,继承就可以完全get了。

class Animal:
    __COUNT = 100  # _Animal__COUNT
    HEIGHT = 0
    
    def __init__(self, age, weight, height):
        self.__COUNT += 1  # slef._Animal__COUNT
        self.age = age
        self.__weight = weight  # self._Animal__COUNT
        self.HEIGHT = height
    
    def eat(self):
        print("{} eat".format(self.__class__.__name__))
        
    def __getweight(self):
        print(self.__weight)  # self._Animal__COUNT
        
    @classmethod
    def showcount1(cls):
        print(cls)
        print(cls.__dict__)
        print(cls.__COUNT)  # cls._Animal__COUNT
    
    @classmethod
    def __showcount2(cls):
        print(cls.__COUNT)  # cls._Animal__COUNT
        
    def showcount3(self):
        print(self.__COUNT)  # self._Animal__COUNT
        

class Cat(Animal):
    NAME = 'CAT'
    __COUNT = 200

c = Cat(3, 5, 15)
print(c.__dict__)  # {'_Animal__COUNT': 101, 'age': 3, '_Animal__weight': 5, 'HEIGHT': 15}
print(c.HEIGHT)  # 15
# print(c.__COUNT)  # 'Cat' object has no attribute '__COUNT'
# c.__getweight()  #  'Cat' object has no attribute '__getweight'
c._Animal__getweight()  # 5  【注意,隐藏属性改名的只和当前类有关系,设置私有属性的当前类,在谁里面改谁的名】
c.showcount1()  # 自己没有的,会和父类去要
    # <class '__main__.Cat'>
    # {'__module__': '__main__', 'NAME': 'CAT', '_Cat__COUNT': 200, '__doc__': None}
    # 100 

# c.__showcount2()  # 'Cat' object has no attribute '__showcount2'
c._Animal__showcount2()  # 100
c.showcount3()  # 101
print(Cat.__dict__)  # {'__module__': '__main__', 'NAME': 'CAT', '_Cat__COUNT': 200, '__doc__': None}
print(c._Cat__COUNT)  
### Python 多继承用法及方法解析顺序 (MRO) 在 Python 中,可以支持多重继承,这意味着一个子可以从多个父派生。当涉及多重继承时,Python 使用一种称为 **Method Resolution Order (MRO)** 的机制来决定如何查找属性和方法。 #### 多重继承的基本语法 定义一个多继承非常简单,只需在括号中列出所有的基即可: ```python class Base1: pass class Base2: pass class Derived(Base1, Base2): pass ``` 在这个例子中,`Derived` 是 `Base1` 和 `Base2` 的子[^1]。 #### 方法解析顺序 (MRO) 当调用某个方法或访问某个属性时,如果该方法或属性不存在于当前,则会按照 MRO 来寻找它。Python 3 使用了一种名为 C3 线性化的算法来计算 MRO。C3 线性化确保了以下几点: - 子总是优先于其父。 - 如果有多个父,则它们保持声明时的顺序。 - 对于共同祖先,线性化过程遵循一致性和单调性的原则。 可以通过 `__mro__` 属性或者 `mro()` 方法查看某的方法解析顺序: ```python print(Derived.__mro__) # 或者 print(Derived.mro()) ``` 这将返回一个元组,表示从最具体的到最通用的序列[^2]。 #### 超级函数 (`super`) 的作用 在多重继承场景下,`super()` 函数变得尤为重要。它可以用来调用父中的方法而无需显式指定父名称。这样不仅减少了代码耦合度,还使得维护更加容易。 考虑下面的例子: ```python class A: def __init__(self): print("A") class B(A): def __init__(self): super().__init__() print("B") class C(A): def __init__(self): super().__init__() print("C") class D(B, C): def __init__(self): super().__init__() print("D") d_instance = D() ``` 运行这段代码将会打印出如下内容: ``` A C B D ``` 这里展示了即使存在复杂的继承关系,通过合理使用 `super()` 可以让初始化逻辑清晰且可扩展[^3]。 #### 钻石型继承问题及其解决方式 钻石型继承是指两个继承自同一个基的情况,在某些编程语言里可能会引发歧义问题。然而由于 Python 实现了良好的 MRO 计算策略,因此能够很好地处理这种情况并避免冲突发生。 例如: ```python class GrandParent: def greet(self): return 'GrandParent' class Parent1(GrandParent): def greet(self): result = super().greet() return f'Parent1 -> {result}' class Parent2(GrandParent): def greet(self): result = super().greet() return f'Parent2 -> {result}' class Child(Parent1, Parent2): def greet(self): result = super().greet() return f'Child -> {result}' child_obj = Child() print(child_obj.greet()) ``` 输出将是: ``` Child -> Parent1 -> Parent2 -> GrandParent ``` 此行为完全由 MRO 控制,并且符合预期结果[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值