跳转至

Python 笔记 | 面向对象

在 Python 中,类(Class)是对象的蓝图或模板,它定义了对象应有的属性(数据成员)和方法(函数成员)。对象则是根据类创建的实例,它拥有类的所有属性和方法。

类(Class)

类是用于描述具有相同属性和方法的对象的集合。在 Python 中,类使用 class 关键字进行定义。以下是一个简单的类定义示例:

Python
class Dog:
    # 类属性(可选,通常在类内部作为常量使用)
    species = "Canis lupus familiaris"

    # 初始化方法(构造方法),用于创建对象时初始化属性,self表示实例本身
    def __init__(self, name, age):
        self.name = name  # 实例属性
        self.age = age    # 实例属性

    # 实例方法
    def bark(self):
        print(f"{self.name} says: Woof!")

在这个例子中,Dog 是一个类,它有一个类属性 species 和两个实例属性 nameage__init__ 方法是一个特殊的方法,被称为类的构造函数或初始化方法。当创建类的新实例时,它会自动被调用。在类方法定义中,第一个参数总是 selfself 是一个对实例自身的引用,它代表类的实例对象本身。

对象(Object)

对象是类的实例化结果。要创建一个对象,你需要使用类名并传递所需的参数(如果有的话)来调用它。以下是如何创建 Dog 类的一个对象的示例:

Python
# 创建一个Dog对象
my_dog = Dog("Buddy", 3)

# 访问对象的属性
print(my_dog.name)  # 输出: Buddy
print(my_dog.age)   # 输出: 3

# 调用对象的方法
my_dog.bark()  # 输出: Buddy says: Woof!

# 访问类的属性(如果需要的话)
print(Dog.species)  # 输出: Canis lupus familiaris

在这个例子中,my_dogDog 类的一个对象。我们使用 my_dog.namemy_dog.age 来访问对象的属性,并使用 my_dog.bark() 来调用对象的方法。

总之,类是对象的蓝图,它定义了对象的属性和方法;而对象则是根据类创建的实例,它拥有类的所有属性和方法。

在 Python 中,继承和多态是面向对象编程的两个核心概念,它们进一步丰富了类的定义和对象的行为。

继承(Inheritance)

继承是面向对象编程中的一个重要特性,它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性和方法。子类可以继承父类的所有公有(public)属性和方法,同时还可以添加新的属性或方法,或者重写父类的某些方法。

继承的类型

  • 单继承:子类只继承一个父类的属性和方法。
  • 多继承:子类可以继承多个父类的属性和方法。在 Python 中,这种多继承是通过在定义子类时,将多个父类作为基类参数来实现的。

继承的语法

在 Python 中,继承的语法结构大致如下:

Python
class ParentClass:
    # 父类定义
    def method1(self):
        # 方法实现,这里的 pass 代表什么也不做的意思,只是占位
        pass

class ChildClass(ParentClass):
    # 子类继承自ParentClass
    def method2(self):
        # 子类自己的方法
        pass

在上面的例子中,ChildClass 继承了 ParentClass ,因此它拥有 ParentClass 的所有公有属性和方法(如 method1 ),同时还可以添加自己的方法(如 method2 )。

示例

单继承

假设我们有一个 Animal 类,它描述了动物的基本属性(如 nameage )和一个方法(如 speak ):

Python
class Animal:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def speak(self):
        print(f"{self.name} makes a sound")

# 定义一个Dog类,继承自Animal类
class Dog(Animal):
    def __init__(self, name, age, breed):
        # super()是内置函数,用于调用父类(基类)
        super().__init__(name, age)  # 调用父类初始化方法,初始化 name 和 age 属性
        self.breed = breed  # 初始化子类自己的属性 breed

    def speak(self):
        # 重写父类的speak方法
        print(f"{self.name} says Woof!")

# 创建一个Dog对象并调用其方法
my_dog = Dog("Buddy", 3, "Golden Retriever")
my_dog.speak()  # 输出: Buddy says Woof!

在这个例子中,Dog 类继承了 Animal 类,因此它拥有了 Animal 类的所有属性和方法。此外,Dog 类还添加了一个新的属性 breed ,并重写了 speak 方法以提供狗特有的行为。

多继承

多继承允许一个类继承自多个父类。以下是一个简单的多继承示例:

Python
class Mammal:
    def give_birth(self):
        print("Mammals give birth to live young.")

class Canine(Mammal, Animal):  # Canine继承自Mammal和Animal
    def __init__(self, name, age, breed):
        super().__init__(name, age)  # 调用Animal类的初始化方法
        self.breed = breed

    def bark(self):
        print(f"{self.name} barks.")

my_canine = Canine("Max", 2, "German Shepherd")
my_canine.speak()  # 假设Animal的speak方法在Canine中没有被重写
my_canine.give_birth()  # 调用从Mammal继承的方法
my_canine.bark()  # Canine类自己的方法

在这个例子中,Canine 类同时继承了 MammalAnimal 类。它继承了 Mammal 类的 give_birth 方法和 Animal 类的 speak 方法(尽管在这个例子中 speak 方法没有在 Canine 类中重写)。此外,Canine 类还添加了自己的 bark 方法。

多态(Polymorphism)

多态是面向对象编程的三大特性之一(另外两个是封装和继承)。多态指的是不同的对象对同一消息做出不同的响应,即同一操作作用于不同的对象,可以有不同的执行结果。在 Python 中,多态是通过方法重写和接口来实现的。

方法重写

子类可以重写父类的方法,即在子类中定义与父类同名的方法。当子类对象调用该方法时,将执行子类中的方法,而不是父类中的方法。这体现了多态性,因为不同类的对象对同一方法调用可能产生不同的结果。

接口

在 Python 中,没有像 Java 或 C# 那样的显式接口概念,但可以通过抽象基类(ABC,Abstract Base Classes)和抽象方法(通过装饰器 @abstractmethod 定义)来模拟接口。抽象基类不能被直接实例化,但可以作为其他类的基类。抽象方法则必须在子类中实现。通过这种方式,可以定义一组方法的契约,要求子类必须实现这些方法,从而实现多态性。

示例

多态允许我们使用统一的接口来处理不同类型的对象。在 Python 中,多态通常通过方法重写来实现。以下是一个简单的多态示例:

Python
class Shape:
    def area(self):
        pass  # 抽象方法,在子类中实现

class Rectangle(Shape):
    def __init__(self, width, height):
        self.width = width
        self.height = height

    def area(self):
        return self.width * self.height

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):
        return 3.14 * self.radius ** 2

def calculate_area(shape):
    return shape.area()  # 无论传入的是Rectangle还是Circle对象,都调用其area方法

rect = Rectangle(4, 5)
print(calculate_area(rect))  # 输出: 20.0

circle = Circle(3)
print(calculate_area(circle))  # 输出: 约28.27

在这个例子中,我们定义了一个 Shape 接口(虽然 Python 中没有显式的接口概念,但这里我们将其视为一个接口),它有一个 area 方法。

然后,我们定义了两个类 RectangleCircle ,它们都实现了 Shape 接口的 area 方法。

最后,我们定义了一个 calculate_area 函数,它接受一个 Shape 类型的参数并调用其 area 方法。由于 RectangleCircle 都实现了 area 方法,因此我们可以将它们的对象传递给 calculate_area 函数,并得到正确的结果。这体现了多态性。

总结

  • 继承使得代码更加模块化和可重用,子类可以在不改变父类代码的情况下扩展其功能。
  • 多态增加了代码的灵活性和可扩展性,使得程序能够处理多种类型的对象,并做出不同的响应。通过继承和方法重写,Python 中的类可以实现多态性。

实践

Python
# 定义一个学生类  
# 要求:  
# 1.属性包括学生姓名、学号,以及语数英三科的成绩  
# 2.能够设置学生某科目的成绩  
# 3.能够打印出该学生的所有科目成绩  

class Student:  
    def __init__(self, name, student_id):  
        self.name = name  
        self.student_id = student_id  
        self.score = {"语文": 0, "数学": 0, "英语": 0}  

    def set_score(self, subject, score):  
        if subject in self.score.keys():    # 这里不加keys()也是一样的,因为默认迭代字典键名  
            self.score[subject] = score  
        else:  
            print("参数错误!")  

    def get_score(self):  
        print(f"学生 {self.name}({self.student_id}) 的成绩分别为:")  
        for subject in self.score.keys():    # 这里不加keys()也是一样的,因为默认迭代字典键名  
            print(f"{subject}: {self.score[subject]}")  


student = Student("李华", 200488)  
student.set_score("数学", 114)  
student.set_score("语文", 102)  
student.set_score("英语", 132)  

student.get_score()
Python
# 类继承练习:人力系统  
# 员工分为两类:全职员工 FullTimeEmployee、兼职员工 PartTimeEmployee。  
# 全职和兼职都有 "姓名 name"、"工号 id" 属性,  
# 都具备"打印信息 print_info"(打印姓名、工号)方法。  
# 全职有"月薪 monthly_salary"属性,  
# 兼职有"日薪 daily_salary"属性、"每月工作天数 work_days"的属性。  
# 全职和兼职都有"计算月薪 calculate_monthly_pay"的方法,但具体计算过程不一样。  

class Employee:  
    def __init__(self, name, user_id):  
        self.name = name  
        self.user_id = user_id  

    def get_info(self):  
        print(f"姓名:{self.name},工号:{self.user_id}")  

    def calculate_monthly_pay(self):  
        pass    # 抽象方法,子类实现(多态)  


class FullTimeEmployee(Employee):  
    def __init__(self, name, user_id, monthly_salary):  
        super().__init__(name, user_id)  # 调用基类构造函数  
        self.monthly_salary = monthly_salary  

    def calculate_monthly_pay(self):  
        return self.monthly_salary  


class PartTimeEmployee(Employee):  
    def __init__(self, name, user_id, daily_salary, work_days):  
        super().__init__(name, user_id)  
        self.daily_salary = daily_salary  
        self.work_days = work_days  

    def calculate_monthly_pay(self):  
        return self.daily_salary * self.work_days  


empol_01 = FullTimeEmployee("小黑", 20020, 3000)  
empol_02 = PartTimeEmployee("房东", 20021, 150, 16)  


empol_01.get_info()  
print(f"月薪:{empol_01.calculate_monthly_pay()}")  
empol_02.get_info()  
print(f"月薪:{empol_02.calculate_monthly_pay()}")