Bootstrap

《0基础》学习Python——第十四讲__封装、继承、多态

<封装、继承、多态>

一、类和实例解析

        1、面向对象最重要的概念就是类(Class)和实例(Instance),必须牢记类是抽象的模板 ,比如Student类,而 实例是根据类创建出来的一个个具体的“对象” ,每个对象都拥有相同的方法,但各自的数据可能不同。
        2、用class 类名即可以创建一个类,类名通常是大写开头的单词

        3、 定义好了Student类,就通过类名+()创建出Student的实例,可以自由地给一个实例变量绑定属性

        4、由于类可以起到模板的作用,因此,可以在创建实例的时候,把一些必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name,score等属性绑上去:

        5、__init__前后分别有两个下划线,__init__方法的第一个参数永远是self,表示创建的实例本身,有了__init__方法,在创建实例的时候,就不能传入空的参数了,必须传入与__init__方法匹配的参数,self不需要传,Python解释器自己会把实例变量传进去

二、数据封装

        数据封装是面向对象编程中的一个概念,它指的是将数据和操作数据的方法封装成一个对象。数据封装的目的是保护数据的安全性和完整性,通过使用类和访问控制方式来限制数据的访问和修改。

        要定义一个方法,除了第一个参数是self外,其他和普通函数一样。要调用时只需要在实例变量上直接调用,除了self不用传递,其他参数正常传入。

        封装的另一个好处是可以给Student类增加新的方法,比如get_grade:

        同样的,get_grade方法可以直接在实例变量上调用,不需要知道内部实现细节

class Student:
    
    def __init__(self, name, age):
        self.__name = name
        self.__age = age
    # 封装的方法
    def get_name(self):
        return self.__name

    def set_name(self, name):
        self.__name = name
    def get_age(self):
        return self.__age

    def set_age(self, age):
        self.__age = age

if __name__ == '__main__':    
    
    student = Student("Tom", 18)
    name = student.get_name()
    age = student.get_age()
    # 输出学生的信息
    print("姓名:", name)
    print("年龄:", age)

在上面的代码中Student封装了学生的姓名和年龄数据,并提供了对应的访问和修改方法get_name()set_name()get_age()set_age()。在类的__init__方法中,我们使用双下划线__来表示私有属性,即外部无法直接访问的属性。通过使用封装的方法来间接访问和修改对象的数据,从而保护了数据的安全性和完整性。同样,其他类或模块无法直接访问和修改私有属性。

注意:Python中的封装是通过约定而不是强制来实现的。私有属性和方法的命名规范是使用双下划线__作为前缀,但实际上仍然可以直接访问和修改,只是不推荐这样做。这是因为在Python中,尊重开发者的自由和责任,更加注重一种约定俗成的编程规范。

三、继承

        在Python中,继承是面向对象编程中的一个重要概念,它允许一个类(称为子类)继承另一个类(称为父类或基类)的属性和方法。子类可以通过继承来获得父类的所有特性,并可以在此基础上添加自己独有的属性和方法。

继承的语法如下:

class 子类名(父类名):
    pass

        在这个示例中,子类名是子类的类名,父类名是要继承的父类的类名。使用关键字class定义子类后,可以在类体中添加自己的属性和方法,或者覆盖父类的方法。

例如:

# 定义一个父类
class Animal:
    def __init__(self, name):
        self.name = name
    
    def eat(self):
        print(f"{self.name} is eating.")

# 定义一个子类,继承自父类
class Dog(Animal):
    def bark(self):
        print(f"{self.name} is barking.")

if __name__ == '__main__':
    
    # 创建一个Dog实例
    dog = Dog("Buddy")

    # 调用继承自父类的方法
    dog.eat()

    # 调用子类自己的方法
    dog.bark()

在上面的代码中,Animal类是父类Dog类是子类。子类Dog继承了父类Animal属性和方法。通过创建Dog类的实例dog,我们可以调用继承自父类的方法eat(),还可以调用子类自己的方法bark()

四、继承几个重要的特点

        1、子类可以继承父类的属性和方法,包括公有属性和方法。

        2、子类可以覆盖父类的方法,即重新实现父类的方法。

        3、子类可以添加独有的属性和方法。

        4、子类可以继续被其他类继承,形成多层继承关系。

        继承是面向对象编程中实现代码重用和逻辑组织的重要方式,可以提高代码的可读性和可维护性。同时,继承也符合面向对象编程的开放封闭原则,使得程序的扩展和修改更加灵活和易于实现。

五、多态

        1、多态(Polymorphism)是指对象可以在不同的上下文中以不同的方式呈现。具体来说,多态指的是同一操作对不同对象的操作会产生不同的结果。

        2、多态实现基本机制方法重写(Method Overriding)方法重载(Method Overloading)。  

        3、方法重写指的是在子类中重新定义父类中已经存在的方法,以便在子类的对象上调用该方法时执行子类中的实现。通过方法重写,子类可以覆盖继承自父类的方法,并且在执行时会根据对象的类型选择适当的方法。

        4、方法重载指的是在同一个类中定义具有相同名字参数个数或类型不同的多个方法。在调用该方法时,编译器会根据传入的参数的类型和数量选择合适的方法执行。

class Animal:
    def sound(self):
        pass

class Dog(Animal):
    def sound(self):
        print("Dog is barking.")

class Cat(Animal):
    def sound(self):
        print("Cat is meowing.")

# 定义一个多态的方法,接受Animal对象作为参数
def make_sound(animal):
    animal.sound()

if __name__ =="__main__":
    # 创建不同的子类实例    
    dog = Dog()
    cat = Cat()

    # 调用多态的方法,分别传入不同的子类实例
    make_sound(dog)
    make_sound(cat)

        在上面的代码中,Animal类是父类,Dog类和Cat类是子类。父类中的sound()方法被子类重写,分别实现了不同的行为。通过创建不同的子类对象并调用多态的方法make_sound(),可以看到不同的子类对象调用相同的方法会产生不同的结果。

六、猴子补丁

        猴子补丁(Monkey patching)是指在运行时动态修改拓展已有的类函数模块的行为,而无需对它们进行显式的继承或修改源代码。在Python中,由于语言的动态特性,我们可以使用猴子补丁来改变已有对象的行为添加新的方法

        猴子补丁的概念源于猴子可以在树上动态改变环境,类比于我们可以在运行时动态改变代码。

# 定义一个原始的类
class Foo:
    def bar(self):
        print("Original bar")

if __name__ == '__main__':
    # 创建一个原始类的实例
    foo = Foo()

# 定义一个新的方法
def new_bar(self):
    print("New bar")

if __name__ == '__main__':
    # 将新的方法绑定到原始类上
    Foo.bar = new_bar

    # 调用原始类的方法,实际上调用了被修改后的方法
    foo.bar()  # 输出:New bar

        在上面的代码中,我们首先定义了一个原始的类 Foo,其包含一个方法 bar然后创建了 Foo 的一个实例 foo。接下来,我们定义了一个新的方法 new_bar。最后,通过将新的方法 new_bar 绑定到原始类 Foo 的 bar 方法上,从而实现了对原始类的修改。当调用foo.bar()时,实际上会调用被修改后方法 new_bar

注意:猴子补丁虽然在某些情况下可以非常方便,但它也可能导致代码变得难以理解和维护。因此,在使用猴子补丁时,应该确保清楚地理解其影响和潜在的风险,并尽量避免过度使用。

;