[Python学习篇] Python面向对象——继承

继承是什么

继承是面向对象编程(OOP)中的一个核心概念。继承允许一个类(称为子类或派生类)从另一个类(称为父类或基类)继承属性和方法。这样可以重用代码,提高代码的模块化和可维护性。

  • 父类(基类):提供属性和方法的类。
  • 子类(派生类):继承父类的属性和方法的类。

语法:

class 父类:
    # 父类的属性和方法
    def __init__(self, 属性1):
        self.属性1 = 属性1

    def 方法1(self):
        print("这是父类的方法")


class 子类(父类):
    # 子类的属性和方法
    def __init__(self, 属性1, 属性2):
        super().__init__(属性1)
        self.属性2 = 属性2

    def 方法2(self):
        print("这是子类的方法")
 

示例:

# 定义父类-动物
class Animal:
    def __init__(self, name):
        self.name = name

    # 定义一个空的方法,方法的具体实现由之类重写
    def speak(self):
        pass

    # 定义一个普通方法,子类继承该方法
    def eat(self):
        print(f"{self.name} 正在吃饭")


# 定义子类-狗
class Dog(Animal):
    def speak(self):
        return f"{self.name} 汪汪叫!"


# 定义子类-猫
class Cat(Animal):
    def speak(self):
        return f"{self.name} 喵喵叫!"


# 创建对象并调用方法
dog = Dog("狗")
cat = Cat("猫")

print(dog.speak())  # 输出: 狗 汪汪叫!
print(cat.speak())  # 输出: 猫 喵喵叫!

dog.eat()  # 输出: 狗 正在吃饭
cat.eat()  # 输出: 猫 正在吃饭

继承的优点

  • 代码重用:子类可以重用父类中的代码,减少重复代码。
  • 模块化:通过继承,可以将通用的功能放在父类中,实现代码模块化。
  • 可扩展性:可以在子类中添加新的功能,而不必修改父类的代码。

多继承

  • 单继承指的是一个类只继承一个父类。子类可以重用父类的属性和方法。
  • 多继承指的是一个类可以继承多个父类,从而获得所有父类的属性和方法。这在某些情况下非常有用,但也可能导致复杂性增加,比如遇到方法解析顺序(MRO)问题。
方法解析顺序(MRO)

在多继承中,方法解析顺序(Method Resolution Order,MRO)决定了在类层次结构中搜索方法和属性的顺序。Python使用C3线性化算法来计算MRO。可以使用__mro__属性或mro()方法来查看类的MRO。

示例:

在这个例子中,D类继承了B和C类,而B和C类又继承了A类。调用d.method()时,按照MRO的顺序,会调用B类的method方法,因为在MRO中B类在C类之前。(继承关系就近原则,D离B最近然后是C然后是A)。

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


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


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


class D(B, C):
    pass


d = D()
d.method()  # 输出: B method
print(D.__mro__)  # 输出: (<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>)

子类重写父类的方法和属性

在Python中,子类可以重写父类的同名方法和属性。这意味着子类可以提供自己的实现来覆盖父类中的方法和属性。这样可以使得子类具有独特的行为,同时保留与父类的接口一致性。

  • 重写方法:当子类重写父类的方法时,子类的方法会覆盖父类的方法。在调用该方法时,将执行子类的实现。
  • 重写属性:当子类重写父类的属性时,子类中的属性将覆盖父类中的同名属性。
super() 函数

有时子类需要在重写方法或属性时保留对父类实现的调用。可以使用 super() 函数来调用父类的方法。

示例:

# 父类
class Parent:
    def greet(self):
        return "父类"


# 子类
class Child(Parent):
    def greet(self):
        # 带参数的写法,写法一
        # parent_greeting = super(Child, self).greet()
        # 不带参数的写法,写法二
        parent_greeting = super().greet()
        return f"{parent_greeting} 和 子类"


child = Child()
print(child.greet())  # 输出: 父类 和 子类

重写和重载

  • 重写

重写指的是子类重新定义父类中的方法或属性。通过重写,子类可以提供自己的实现来替换父类的实现。重写主要用于多态性和定制子类行为。

  • 重载 

重载指的是在同一个作用域中定义多个具有相同名字但参数不同的方法。在许多编程语言中(例如C++和Java),重载是允许的,编译器会根据方法签名(参数的数量和类型)来区分它们。然而,在Python中,方法重载并不直接支持。Python中的函数或方法如果使用相同的名字,后面的定义会覆盖前面的定义。

尽管如此,Python可以通过默认参数和可变参数来实现类似重载的效果。

私有权限

在Python中,私有权限(Private Access)用于限制类属性和方法的访问,即私有属性和私有方法。使其只能在类内部使用。这是通过命名约定和名称改写(name mangling)机制来实现的。

_ 单下划线 (受保护)

单下划线前缀表示“受保护的”变量或方法。这是一种约定,表示这些变量或方法不应该不推荐在类外部直接使用,虽然它们仍然可以被访问。

示例:

class Hello:

    def __init__(self):
        self._protected_var = "我是受保护的属性"

    def _protected_method(self):
        return "我是受保护的方法"


hello = Hello()
# 依然可以访问到,但是不推荐不应该访问
print(hello._protected_var)          # 输出:我是受保护的属性
print(hello._protected_method())     # 输出:我是受保护的方法
__ 双下划线 (私有)

双下划线前缀用于实现名称改写(name mangling),使得属性或方法在类外部无法轻易访问。Python会将这些名称改写为 _ClassName__variableName 的形式,从而实现基本的私有化。

示例:

get 私有属性

class Hello:
    __private_var = "我是私有的属性"

    def __private_method(self):
        return "我是私有的方法"

    # 用于访问私有属性
    def get_private_var(self):
        return self.__private_var

    # 用于访问私有方法
    def get_private_method(self):
        return self.__private_method()


hello = Hello()
# 以下访问会报错
# print(hello.__private_var)      # 出异常 AttributeError
# print(hello.__private_method()) # 出异常 AttributeError

# 方式一:
# 通过类内部方法间接访问
print(hello.get_private_var())          # 输出:我是私有的属性
print(hello.get_private_method())       # 输出:我是私有的方法

# 方式二:
# 通过名称改写访问,改写规则是 `_类名__变量方法名`
print(hello._Hello__private_var)        # 输出:我是私有的属性
print(hello._Hello__private_method())   # 输出:我是私有的方法

set 私有属性

class Hello:
    __private_var = "20"

    # 获取私有属性值
    def get_private_var(self):
        return self.__private_var

    # 修改私有属性值
    def set_private_var(self, __private_var):
        self.__private_var = __private_var


hello = Hello()

# 获取修改前的数据
print(hello.get_private_var())  # 20

# 修改数据
hello.set_private_var("10")

# 获取修改后的数据
print(hello.get_private_var())  # 10
私有权限对于继承的影响
  • 私有属性和方法:在子类中无法直接访问父类的私有属性和方法。这是因为它们被名称改写,只有通过父类提供的公有方法间接访问。例如,通过get_private_var()可以访问父类的私有成员。

  • 受保护属性和方法:子类可以直接访问和调用父类的受保护属性和方法,因为单下划线只是一个约定,而不是严格的访问控制。

  • 公有属性和方法:子类可以直接访问和调用父类的公有属性和方法。

相关推荐

  1. [Python学习] Python面向对象——继承

    2024-07-09 17:56:03       11 阅读
  2. [Python学习] Python面向对象——类

    2024-07-09 17:56:03       6 阅读
  3. pythonpython面向对象之——继承

    2024-07-09 17:56:03       5 阅读
  4. python 面向对象(封装、继承、多态)

    2024-07-09 17:56:03       20 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-09 17:56:03       3 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-09 17:56:03       3 阅读
  3. 在Django里面运行非项目文件

    2024-07-09 17:56:03       2 阅读
  4. Python语言-面向对象

    2024-07-09 17:56:03       2 阅读

热门阅读

  1. 【Linux命令入门】查找文件

    2024-07-09 17:56:03       10 阅读
  2. 编码与梦想:我的CSDN创作5周年

    2024-07-09 17:56:03       8 阅读
  3. 多数据库支持在PHP框架中的实现策略与实践

    2024-07-09 17:56:03       11 阅读
  4. JVM 堆内存分配过程

    2024-07-09 17:56:03       12 阅读
  5. c++单例模式的一种写法

    2024-07-09 17:56:03       11 阅读
  6. nunjucks动态更新模版路径

    2024-07-09 17:56:03       11 阅读
  7. 【python技巧】pytorch网络可视化

    2024-07-09 17:56:03       8 阅读
  8. 单例模式的实现

    2024-07-09 17:56:03       7 阅读
  9. 【MIT 6.5840/6.824】Lab1 MapReduce

    2024-07-09 17:56:03       9 阅读