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
和两个实例属性 name
和 age
。 __init__
方法是一个特殊的方法,被称为类的构造函数或初始化方法。当创建类的新实例时,它会自动被调用。在类方法定义中,第一个参数总是 self
,self
是一个对实例自身的引用,它代表类的实例对象本身。
对象(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_dog
是 Dog
类的一个对象。我们使用 my_dog.name
和 my_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
类,它描述了动物的基本属性(如 name
和 age
)和一个方法(如 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
类同时继承了 Mammal
和 Animal
类。它继承了 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
方法。
然后,我们定义了两个类 Rectangle
和 Circle
,它们都实现了 Shape
接口的 area
方法。
最后,我们定义了一个 calculate_area
函数,它接受一个 Shape
类型的参数并调用其 area
方法。由于 Rectangle
和 Circle
都实现了 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()}")
|