3. Python 面向对象编程
引言
面向对象编程(Object-Oriented Programming, OOP)是一种强大的编程范式,它将数据和操作数据的方法组织在一起。Python 是一门完全支持面向对象的语言,理解 OOP 对于编写可维护、可扩展的代码至关重要。
本教程特点:
- 每个概念都配有可直接运行的代码示例
- 代码可以直接复制到 Python 解释器中执行
- 循序渐进,从基础到高级
- 包含实际应用场景和最佳实践
学习建议:
- 阅读每个示例代码
- 复制代码到 Python 解释器或 IDE 中运行
- 尝试修改代码,观察结果变化
- 完成每个部分的练习
第一部分:面向对象基础
1. 什么是类和对象?
类比理解
类(Class) 就像蓝图或模板:
- 定义了一类事物的共同特征和行为
- 例如:"汽车"这个类定义了所有汽车都有轮子、引擎等特征
对象(Object) 就像根据蓝图建造的房子:
- 是类的具体实例
- 例如:一辆红色的特斯拉就是"汽车"类的一个对象
第一个类:定义和使用
# 示例 1:定义一个简单的类
class Dog:
"""这是一个表示狗的类"""
def __init__(self, name, age):
"""初始化方法,创建对象时自动调用"""
self.name = name # self.name 是实例属性
self.age = age
def bark(self):
"""狗叫的方法"""
return f"{self.name} 在叫:汪汪!"
def get_info(self):
"""获取狗的信息"""
return f"这是一只名叫 {self.name} 的狗,{self.age} 岁了"
# 创建对象(实例化)
dog1 = Dog("旺财", 3)
dog2 = Dog("小黑", 5)
# 使用对象
print(dog1.bark()) # 输出:旺财 在叫:汪汪!
print(dog2.get_info()) # 输出:这是一只名叫 小黑 的狗,5 岁了
print(dog1.name) # 输出:旺财
print(dog1.age) # 输出:3
运行结果:
旺财 在叫:汪汪!
这是一只名叫 小黑 的狗,5 岁了
旺财
3
关键概念解释
class:定义类的关键字__init__:构造方法,创建对象时自动调用self:指向当前对象的引用- 方法:定义在类中的函数
- 属性:对象的特征(如 name、age)
2. 属性和方法
实例属性
# 示例 2:实例属性的使用
class Student:
def __init__(self, name, student_id, grade):
self.name = name
self.student_id = student_id
self.grade = grade
self.courses = [] # 可以初始化为列表
def add_course(self, course_name):
"""添加课程"""
self.courses.append(course_name)
print(f"{self.name} 添加了课程:{course_name}")
def show_courses(self):
"""显示所有课程"""
if self.courses:
print(f"{self.name} 的课程:{', '.join(self.courses)}")
else:
print(f"{self.name} 还没有选课")
# 创建学生对象
student1 = Student("张三", "2023001", 85)
student2 = Student("李四", "2023002", 90)
# 使用对象
student1.add_course("Python编程")
student1.add_course("数据结构")
student1.show_courses()
student2.add_course("机器学习")
student2.show_courses()
运行结果:
张三 添加了课程:Python编程
张三 添加了课程:数据结构
张三 的课程:Python编程, 数据结构
李四 添加了课程:机器学习
李四 的课程:机器学习
类属性
# 示例 3:类属性(所有实例共享)
class Circle:
# 类属性
pi = 3.14159
count = 0 # 记录创建的圆的数量
def __init__(self, radius):
# 实例属性
self.radius = radius
Circle.count += 1 # 每次创建对象时,计数加1
def area(self):
"""计算面积"""
return Circle.pi * self.radius ** 2
def circumference(self):
"""计算周长"""
return 2 * Circle.pi * self.radius
@classmethod
def get_count(cls):
"""获取创建的圆的数量"""
return cls.count
# 创建对象
circle1 = Circle(5)
circle2 = Circle(10)
circle3 = Circle(7)
# 访问类属性
print(f"π 的值:{Circle.pi}")
print(f"创建的圆的数量:{Circle.get_count()}")
# 使用实例方法
print(f"圆1的面积:{circle1.area():.2f}")
print(f"圆2的周长:{circle2.circumference():.2f}")
运行结果:
π 的值:3.14159
创建的圆的数量:3
圆1的面积:78.54
圆2的周长:62.83
第二部分:封装
1. 私有属性和方法
Python 使用命名约定来实现封装:以双下划线 __ 开头的属性和方法是私有的。
# 示例 4:私有属性和方法
class BankAccount:
def __init__(self, account_number, initial_balance=0):
self.account_number = account_number # 公开属性
self.__balance = initial_balance # 私有属性(双下划线)
self.__transaction_history = [] # 私有属性
def deposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
self.__transaction_history.append(f"存款:+{amount}")
return f"存款成功,当前余额:{self.__balance}"
else:
return "存款金额必须大于0"
def withdraw(self, amount):
"""取款"""
if amount > 0 and amount <= self.__balance:
self.__balance -= amount
self.__transaction_history.append(f"取款:-{amount}")
return f"取款成功,当前余额:{self.__balance}"
else:
return "取款失败:余额不足或金额无效"
def get_balance(self):
"""获取余额(公开方法)"""
return self.__balance
def get_transaction_history(self):
"""获取交易历史"""
return self.__transaction_history.copy() # 返回副本,保护原始数据
# 创建账户
account = BankAccount("123456", 1000)
# 使用公开方法
print(account.deposit(500))
print(account.withdraw(200))
print(f"当前余额:{account.get_balance()}")
# 查看交易历史
print("交易历史:")
for transaction in account.get_transaction_history():
print(f" {transaction}")
# 尝试直接访问私有属性(不推荐,但Python允许通过特殊方式访问)
# print(account.__balance) # 会报错:AttributeError
# print(account._BankAccount__balance) # 可以访问,但不推荐
运行结果:
存款成功,当前余额:1500
取款成功,当前余额:1300
当前余额:1300
交易历史:
存款:+500
取款:-200
2. 属性装饰器(Property)
使用 @property 装饰器可以创建"计算属性",让访问属性像访问方法一样。
# 示例 5:使用 @property 装饰器
class Rectangle:
def __init__(self, width, height):
self._width = width # 使用单下划线表示"受保护"的属性
self._height = height
@property
def width(self):
"""获取宽度"""
return self._width
@width.setter
def width(self, value):
"""设置宽度(带验证)"""
if value > 0:
self._width = value
else:
raise ValueError("宽度必须大于0")
@property
def height(self):
"""获取高度"""
return self._height
@height.setter
def height(self, value):
"""设置高度(带验证)"""
if value > 0:
self._height = value
else:
raise ValueError("高度必须大于0")
@property
def area(self):
"""计算面积(只读属性)"""
return self._width * self._height
@property
def perimeter(self):
"""计算周长(只读属性)"""
return 2 * (self._width + self._height)
# 创建矩形
rect = Rectangle(5, 3)
# 像访问属性一样使用(不需要括号)
print(f"宽度:{rect.width}")
print(f"高度:{rect.height}")
print(f"面积:{rect.area}")
print(f"周长:{rect.perimeter}")
# 修改属性
rect.width = 10
rect.height = 6
print(f"\n修改后:")
print(f"宽度:{rect.width}")
print(f"面积:{rect.area}")
# 尝试设置无效值
try:
rect.width = -5
except ValueError as e:
print(f"错误:{e}")
运行结果:
宽度:5
高度:3
面积:15
周长:16
修改后:
宽度:10
面积:60
错误:宽度必须大于0
第三部分:继承
1. 单继承
继承允许我们创建一个新类,它继承父类的所有属性和方法。
# 示例 6:单继承
class Animal:
"""动物基类"""
def __init__(self, name, age):
self.name = name
self.age = age
def eat(self):
return f"{self.name} 在吃东西"
def sleep(self):
return f"{self.name} 在睡觉"
def make_sound(self):
return "动物发出声音"
class Dog(Animal): # Dog 继承自 Animal
"""狗类"""
def __init__(self, name, age, breed):
super().__init__(name, age) # 调用父类的初始化方法
self.breed = breed
def make_sound(self): # 重写父类方法
return f"{self.name} 在叫:汪汪!"
def fetch(self): # 子类特有的方法
return f"{self.name} 在捡球"
class Cat(Animal): # Cat 继承自 Animal
"""猫类"""
def __init__(self, name, age, color):
super().__init__(name, age)
self.color = color
def make_sound(self): # 重写父类方法
return f"{self.name} 在叫:喵喵!"
def climb(self): # 子类特有的方法
return f"{self.name} 在爬树"
# 创建对象
dog = Dog("旺财", 3, "金毛")
cat = Cat("小花", 2, "橘色")
# 使用继承的方法
print(dog.eat()) # 继承自 Animal
print(dog.sleep()) # 继承自 Animal
print(dog.make_sound()) # 重写的方法
print(dog.fetch()) # 子类特有的方法
print("\n" + "="*30)
print(cat.eat())
print(cat.make_sound())
print(cat.climb())
运行结果:
旺财 在吃东西
旺财 在睡觉
旺财 在叫:汪汪!
旺财 在捡球
==============================
小花 在吃东西
小花 在叫:喵喵!
小花 在爬树
2. 多重继承
Python 支持多重继承,一个类可以继承多个父类。
# 示例 7:多重继承
class Flyable:
"""可飞行的能力"""
def fly(self):
return "正在飞行"
def land(self):
return "正在降落"
class Swimmable:
"""可游泳的能力"""
def swim(self):
return "正在游泳"
def dive(self):
return "正在潜水"
class Bird:
"""鸟类"""
def __init__(self, name):
self.name = name
def make_sound(self):
return "鸟在叫"
class Duck(Bird, Flyable, Swimmable):
"""鸭子:既是鸟,又能飞,又能游泳"""
def __init__(self, name):
super().__init__(name)
def make_sound(self):
return f"{self.name} 在叫:嘎嘎!"
# 创建鸭子对象
duck = Duck("唐老鸭")
# 可以使用所有继承的方法
print(duck.make_sound())
print(duck.fly())
print(duck.swim())
print(duck.dive())
# 查看方法解析顺序(MRO)
print(f"\n方法解析顺序:{Duck.__mro__}")
运行结果:
唐老鸭 在叫:嘎嘎!
正在飞行
正在游泳
正在潜水
方法解析顺序:(<class '__main__.Duck'>, <class '__main__.Bird'>, <class '__main__.Flyable'>, <class '__main__.Swimmable'>, <class 'object'>)
3. 方法重写和 super()
# 示例 8:方法重写和 super() 的使用
class Vehicle:
"""交通工具基类"""
def __init__(self, brand, model):
self.brand = brand
self.model = model
self.speed = 0
def start(self):
self.speed = 10
return f"{self.brand} {self.model} 启动了"
def accelerate(self, increment=10):
self.speed += increment
return f"加速到 {self.speed} km/h"
def stop(self):
self.speed = 0
return f"{self.brand} {self.model} 停止了"
class Car(Vehicle):
"""汽车类"""
def __init__(self, brand, model, fuel_type):
super().__init__(brand, model) # 调用父类初始化
self.fuel_type = fuel_type
def start(self):
# 先调用父类的方法
result = super().start()
return f"{result},使用 {self.fuel_type} 燃料"
def accelerate(self, increment=20): # 重写,默认增量不同
return super().accelerate(increment) # 调用父类方法
class Bicycle(Vehicle):
"""自行车类"""
def __init__(self, brand, model, gear_count):
super().__init__(brand, model)
self.gear_count = gear_count
def start(self):
return f"{self.brand} {self.model} 开始骑行(人力驱动)"
def accelerate(self, increment=5): # 自行车加速较慢
return super().accelerate(increment)
# 创建对象
car = Car("特斯拉", "Model 3", "电力")
bike = Bicycle("捷安特", "山地车", 21)
print("汽车:")
print(car.start())
print(car.accelerate())
print(car.accelerate(30))
print("\n自行车:")
print(bike.start())
print(bike.accelerate())
print(bike.accelerate(10))
运行结果:
汽车:
特斯拉 Model 3 启动了,使用 电力 燃料
加速到 30 km/h
加速到 60 km/h
自行车:
捷安特 山地车 开始骑行(人力驱动)
加速到 15 km/h
加速到 25 km/h
第四部分:多态
多态允许不同类的对象对同一消息做出不同的响应。
# 示例 9:多态
class Shape:
"""图形基类"""
def area(self):
raise NotImplementedError("子类必须实现 area 方法")
def perimeter(self):
raise NotImplementedError("子类必须实现 perimeter 方法")
class Rectangle(Shape):
"""矩形"""
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
def perimeter(self):
return 2 * (self.width + self.height)
class Circle(Shape):
"""圆形"""
def __init__(self, radius):
self.radius = radius
def area(self):
return 3.14159 * self.radius ** 2
def perimeter(self):
return 2 * 3.14159 * self.radius
class Triangle(Shape):
"""三角形"""
def __init__(self, a, b, c):
self.a = a
self.b = b
self.c = c
def area(self):
# 海伦公式
s = (self.a + self.b + self.c) / 2
return (s * (s - self.a) * (s - self.b) * (s - self.c)) ** 0.5
def perimeter(self):
return self.a + self.b + self.c
# 多态的使用:不同对象调用相同的方法,产生不同的结果
def print_shape_info(shape):
"""这个函数可以处理任何 Shape 的子类"""
print(f"面积:{shape.area():.2f}")
print(f"周长:{shape.perimeter():.2f}")
print()
# 创建不同的图形对象
shapes = [
Rectangle(5, 3),
Circle(4),
Triangle(3, 4, 5)
]
# 使用多态:同一个函数处理不同类型的对象
for shape in shapes:
print_shape_info(shape)
运行结果:
面积:15.00
周长:16.00
面积:50.27
周长:25.13
面积:6.00
周长:12.00
第五部分:特殊方法(魔术方法)
Python 提供了许多特殊方法(以双下划线开头和结尾),它们定义了对象的行为。
# 示例 10:特殊方法(魔术方法)
class Book:
"""图书类"""
def __init__(self, title, author, pages):
self.title = title
self.author = author
self.pages = pages
def __str__(self):
"""字符串表示(用户友好)"""
return f"《{self.title}》- {self.author}"
def __repr__(self):
"""对象表示(开发者友好)"""
return f"Book('{self.title}', '{self.author}', {self.pages})"
def __len__(self):
"""返回书的页数"""
return self.pages
def __eq__(self, other):
"""相等比较"""
if isinstance(other, Book):
return self.title == other.title and self.author == other.author
return False
def __lt__(self, other):
"""小于比较(按页数)"""
if isinstance(other, Book):
return self.pages < other.pages
return NotImplemented
def __add__(self, other):
"""加法运算(合并两本书)"""
if isinstance(other, Book):
new_title = f"{self.title} & {other.title}"
new_author = f"{self.author}, {other.author}"
new_pages = self.pages + other.pages
return Book(new_title, new_author, new_pages)
return NotImplemented
# 创建图书对象
book1 = Book("Python编程", "张三", 300)
book2 = Book("数据结构", "李四", 250)
book3 = Book("Python编程", "张三", 300)
# 使用特殊方法
print("字符串表示:")
print(str(book1)) # 调用 __str__
print(repr(book1)) # 调用 __repr__
print(f"\n书的页数:{len(book1)}") # 调用 __len__
print(f"\nbook1 == book3: {book1 == book3}") # 调用 __eq__
print(f"book1 == book2: {book1 == book2}")
print(f"\nbook2 < book1: {book2 < book1}") # 调用 __lt__
# 加法运算
combined_book = book1 + book2
print(f"\n合并后的书:{combined_book}")
print(f"总页数:{len(combined_book)}")
运行结果:
字符串表示:
《Python编程》- 张三
Book('Python编程', '张三', 300)
书的页数:300
book1 == book3: True
book1 == book2: False
book2 < book1: True
合并后的书:《Python编程 & 数据结构》- 张三, 李四
总页数:550
更多特殊方法示例
# 示例 11:更多特殊方法
class ShoppingCart:
"""购物车类"""
def __init__(self):
self.items = {}
def add_item(self, item, quantity=1):
"""添加商品"""
if item in self.items:
self.items[item] += quantity
else:
self.items[item] = quantity
def __getitem__(self, item):
"""支持索引访问:cart['苹果']"""
return self.items.get(item, 0)
def __setitem__(self, item, value):
"""支持索引赋值:cart['苹果'] = 5"""
self.items[item] = value
def __delitem__(self, item):
"""支持删除:del cart['苹果']"""
if item in self.items:
del self.items[item]
def __contains__(self, item):
"""支持 in 操作符:'苹果' in cart"""
return item in self.items
def __iter__(self):
"""支持迭代:for item in cart"""
return iter(self.items)
def __len__(self):
"""返回商品种类数"""
return len(self.items)
def __str__(self):
"""字符串表示"""
if not self.items:
return "购物车是空的"
items_str = ", ".join([f"{item}×{qty}" for item, qty in self.items.items()])
return f"购物车:{items_str}"
# 创建购物车
cart = ShoppingCart()
# 添加商品
cart.add_item("苹果", 3)
cart.add_item("香蕉", 2)
cart.add_item("橙子", 5)
# 使用特殊方法
print(cart)
print(f"\n商品种类数:{len(cart)}")
# 索引访问
print(f"\n苹果数量:{cart['苹果']}")
# 索引赋值
cart['苹果'] = 10
print(f"修改后苹果数量:{cart['苹果']}")
# in 操作符
print(f"\n'苹果'在购物车中:{'苹果' in cart}")
print(f"'葡萄'在购物车中:{'葡萄' in cart}")
# 迭代
print("\n购物车中的商品:")
for item in cart:
print(f" {item}: {cart[item]}")
# 删除
del cart['橙子']
print(f"\n删除橙子后:{cart}")
运行结果:
购物车:苹果×3, 香蕉×2, 橙子×5
商品种类数:3
苹果数量:3
修改后苹果数量:10
'苹果'在购物车中:True
'葡萄'在购物车中:False
购物车中的商品:
苹果: 10
香蕉: 2
橙子: 5
删除橙子后:购物车:苹果×10, 香蕉×2
第六部分:类方法和静态方法
1. 类方法(@classmethod)
类方法属于类而不是实例,第一个参数是类本身(通常命名为 cls)。
# 示例 12:类方法
class Person:
"""人类"""
population = 0 # 类属性:总人口数
def __init__(self, name, age):
self.name = name
self.age = age
Person.population += 1
@classmethod
def get_population(cls):
"""获取总人口数"""
return cls.population
@classmethod
def create_baby(cls, name):
"""创建一个婴儿(年龄为0)"""
return cls(name, 0)
@classmethod
def from_birth_year(cls, name, birth_year):
"""根据出生年份创建对象"""
from datetime import datetime
age = datetime.now().year - birth_year
return cls(name, age)
def __str__(self):
return f"{self.name}, {self.age}岁"
# 使用类方法
print(f"初始人口:{Person.get_population()}")
person1 = Person("张三", 25)
person2 = Person("李四", 30)
person3 = Person("王五", 28)
print(f"创建3个人后,人口:{Person.get_population()}")
# 使用类方法创建对象
baby = Person.create_baby("小明")
print(f"\n使用类方法创建婴儿:{baby}")
# 使用类方法根据出生年份创建
person4 = Person.from_birth_year("赵六", 1995)
print(f"根据出生年份创建:{person4}")
print(f"\n最终人口:{Person.get_population()}")
运行结果:
初始人口:0
创建3个人后,人口:3
使用类方法创建婴儿:小明, 0岁
根据出生年份创建:赵六, 29岁
最终人口:5
2. 静态方法(@staticmethod)
静态方法不需要访问类或实例,它只是一个普通的函数,但逻辑上属于这个类。
# 示例 13:静态方法
class MathUtils:
"""数学工具类"""
@staticmethod
def add(a, b):
"""加法"""
return a + b
@staticmethod
def multiply(a, b):
"""乘法"""
return a * b
@staticmethod
def is_even(number):
"""判断是否为偶数"""
return number % 2 == 0
@staticmethod
def factorial(n):
"""计算阶乘"""
if n < 0:
raise ValueError("阶乘不能为负数")
if n == 0 or n == 1:
return 1
result = 1
for i in range(2, n + 1):
result *= i
return result
# 使用静态方法(可以通过类或实例调用)
print("通过类调用:")
print(f"5 + 3 = {MathUtils.add(5, 3)}")
print(f"5 × 3 = {MathUtils.multiply(5, 3)}")
print(f"6是偶数:{MathUtils.is_even(6)}")
print(f"5! = {MathUtils.factorial(5)}")
# 也可以通过实例调用
utils = MathUtils()
print(f"\n通过实例调用:")
print(f"10 + 20 = {utils.add(10, 20)}")
运行结果:
通过类调用:
5 + 3 = 8
5 × 3 = 15
6是偶数:True
5! = 120
通过实例调用:
10 + 20 = 30
第七部分:实际应用示例
1. 学生管理系统
# 示例 14:学生管理系统
class Student:
"""学生类"""
def __init__(self, student_id, name, age):
self.student_id = student_id
self.name = name
self.age = age
self.courses = {} # {课程名: 成绩}
def enroll_course(self, course_name):
"""选课"""
if course_name not in self.courses:
self.courses[course_name] = None
return f"{self.name} 成功选课:{course_name}"
return f"{self.name} 已经选了 {course_name}"
def set_grade(self, course_name, grade):
"""设置成绩"""
if course_name in self.courses:
self.courses[course_name] = grade
return f"{self.name} 的 {course_name} 成绩已设置为 {grade}"
return f"{self.name} 没有选 {course_name} 这门课"
def get_average_grade(self):
"""计算平均成绩"""
grades = [g for g in self.courses.values() if g is not None]
if grades:
return sum(grades) / len(grades)
return None
def __str__(self):
avg = self.get_average_grade()
avg_str = f"{avg:.2f}" if avg else "暂无成绩"
return f"学生[{self.student_id}] {self.name}, {self.age}岁, 平均分:{avg_str}"
class Course:
"""课程类"""
def __init__(self, course_id, name, teacher):
self.course_id = course_id
self.name = name
self.teacher = teacher
self.students = []
def add_student(self, student):
"""添加学生"""
if student not in self.students:
self.students.append(student)
student.enroll_course(self.name)
return f"{student.name} 已添加到 {self.name}"
return f"{student.name} 已经在 {self.name} 课程中"
def __str__(self):
return f"课程[{self.course_id}] {self.name}, 授课教师:{self.teacher}, 学生数:{len(self.students)}"
# 创建学生
student1 = Student("2023001", "张三", 20)
student2 = Student("2023002", "李四", 21)
student3 = Student("2023003", "王五", 19)
# 创建课程
python_course = Course("CS101", "Python编程", "张老师")
math_course = Course("MA101", "高等数学", "李老师")
# 学生选课
python_course.add_student(student1)
python_course.add_student(student2)
python_course.add_student(student3)
math_course.add_student(student1)
math_course.add_student(student2)
# 设置成绩
student1.set_grade("Python编程", 85)
student1.set_grade("高等数学", 90)
student2.set_grade("Python编程", 92)
student2.set_grade("高等数学", 88)
student3.set_grade("Python编程", 78)
# 显示信息
print("课程信息:")
print(python_course)
print(math_course)
print("\n学生信息:")
print(student1)
print(student2)
print(student3)
运行结果:
课程信息:
课程[CS101] Python编程, 授课教师:张老师, 学生数:3
课程[MA101] 高等数学, 授课教师:李老师, 学生数:2
学生信息:
学生[2023001] 张三, 20岁, 平均分:87.50
学生[2023002] 李四, 21岁, 平均分:90.00
学生[2023003] 王五, 19岁, 平均分:78.00
2. 图书管理系统
# 示例 15:图书管理系统
class Book:
"""图书类"""
total_books = 0
def __init__(self, isbn, title, author, price):
self.isbn = isbn
self.title = title
self.author = author
self.price = price
self.is_available = True
Book.total_books += 1
def borrow(self):
"""借书"""
if self.is_available:
self.is_available = False
return f"《{self.title}》已借出"
return f"《{self.title}》已被借出,无法借阅"
def return_book(self):
"""还书"""
if not self.is_available:
self.is_available = True
return f"《{self.title}》已归还"
return f"《{self.title}》未被借出"
def __str__(self):
status = "可借" if self.is_available else "已借出"
return f"《{self.title}》- {self.author}, 价格:¥{self.price}, 状态:{status}"
@classmethod
def get_total_books(cls):
return cls.total_books
class Library:
"""图书馆类"""
def __init__(self, name):
self.name = name
self.books = {}
def add_book(self, book):
"""添加图书"""
self.books[book.isbn] = book
return f"已添加图书:{book.title}"
def find_book(self, isbn):
"""查找图书"""
return self.books.get(isbn)
def search_by_title(self, keyword):
"""按书名搜索"""
results = []
for book in self.books.values():
if keyword.lower() in book.title.lower():
results.append(book)
return results
def list_available_books(self):
"""列出可借图书"""
return [book for book in self.books.values() if book.is_available]
def __str__(self):
return f"{self.name},共有 {len(self.books)} 本图书"
# 创建图书馆
library = Library("市图书馆")
# 添加图书
book1 = Book("978-7-111-12345-1", "Python编程", "张三", 59.9)
book2 = Book("978-7-111-12345-2", "数据结构", "李四", 49.9)
book3 = Book("978-7-111-12345-3", "机器学习", "王五", 79.9)
library.add_book(book1)
library.add_book(book2)
library.add_book(book3)
print(library)
print(f"\n图书馆中共有 {Book.get_total_books()} 本图书")
# 显示所有图书
print("\n所有图书:")
for book in library.books.values():
print(f" {book}")
# 借书
print(f"\n{book1.borrow()}")
print(f"{book1}")
# 搜索图书
print("\n搜索'Python':")
results = library.search_by_title("Python")
for book in results:
print(f" {book}")
# 列出可借图书
print("\n可借图书:")
available = library.list_available_books()
for book in available:
print(f" {book}")
运行结果:
市图书馆,共有 3 本图书
图书馆中共有 3 本图书
所有图书:
《Python编程》- 张三, 价格:¥59.9, 状态:可借
《数据结构》- 李四, 价格:¥49.9, 状态:可借
《机器学习》- 王五, 价格:¥79.9, 状态:可借
《Python编程》已借出
《Python编程》- 张三, 价格:¥59.9, 状态:已借出
搜索'Python':
《Python编程》- 张三, 价格:¥59.9, 状态:已借出
可借图书:
《数据结构》- 李四, 价格:¥49.9, 状态:可借
《机器学习》- 王五, 价格:¥79.9, 状态:可借
第八部分:设计模式示例
1. 单例模式
# 示例 16:单例模式
class Singleton:
"""单例模式:确保一个类只有一个实例"""
_instance = None
def __new__(cls):
"""重写 __new__ 方法"""
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance
def __init__(self):
"""初始化(只会执行一次)"""
if not hasattr(self, 'initialized'):
self.value = None
self.initialized = True
# 测试单例模式
singleton1 = Singleton()
singleton1.value = "第一个实例"
singleton2 = Singleton()
singleton2.value = "第二个实例"
print(f"singleton1.value: {singleton1.value}")
print(f"singleton2.value: {singleton2.value}")
print(f"singleton1 is singleton2: {singleton1 is singleton2}")
运行结果:
singleton1.value: 第二个实例
singleton2.value: 第二个实例
singleton1 is singleton2: True
2. 工厂模式
# 示例 17:工厂模式
class Animal:
"""动物基类"""
def speak(self):
raise NotImplementedError
class Dog(Animal):
def speak(self):
return "汪汪!"
class Cat(Animal):
def speak(self):
return "喵喵!"
class Duck(Animal):
def speak(self):
return "嘎嘎!"
class AnimalFactory:
"""动物工厂"""
@staticmethod
def create_animal(animal_type):
"""根据类型创建动物"""
animals = {
"dog": Dog,
"cat": Cat,
"duck": Duck
}
animal_class = animals.get(animal_type.lower())
if animal_class:
return animal_class()
raise ValueError(f"未知的动物类型:{animal_type}")
# 使用工厂创建对象
factory = AnimalFactory()
dog = factory.create_animal("dog")
cat = factory.create_animal("cat")
duck = factory.create_animal("duck")
print(f"狗说:{dog.speak()}")
print(f"猫说:{cat.speak()}")
print(f"鸭子说:{duck.speak()}")
运行结果:
狗说:汪汪!
猫说:喵喵!
鸭子说:嘎嘎!
第九部分:最佳实践和常见错误
1. 命名约定
# 示例 18:Python 命名约定
class MyClass:
"""类名使用驼峰命名法(PascalCase)"""
# 公开属性:普通命名
public_attr = "公开属性"
# 受保护属性:单下划线开头(约定,不是强制)
_protected_attr = "受保护属性"
# 私有属性:双下划线开头
__private_attr = "私有属性"
# 公开方法:普通命名
def public_method(self):
return "公开方法"
# 受保护方法:单下划线开头
def _protected_method(self):
return "受保护方法"
# 私有方法:双下划线开头
def __private_method(self):
return "私有方法"
# 特殊方法:双下划线开头和结尾
def __str__(self):
return "特殊方法"
# 方法名使用蛇形命名法(snake_case)
def my_function():
pass
# 常量使用全大写
MAX_SIZE = 100
DEFAULT_VALUE = 0
2. 常见错误和解决方案
# 示例 19:常见错误和解决方案
# 错误1:忘记 self 参数
class BadExample1:
def method(): # ❌ 缺少 self
return "错误"
# 正确做法:
class GoodExample1:
def method(self): # ✅ 有 self
return "正确"
# 错误2:在类外部修改可变默认参数
class BadExample2:
def __init__(self, items=[]): # ❌ 可变默认参数
self.items = items
# 正确做法:
class GoodExample2:
def __init__(self, items=None): # ✅ 使用 None
self.items = items if items is not None else []
# 错误3:直接访问私有属性
class BadExample3:
def __init__(self):
self.__value = 10
def get_value(self):
return self.__value # ✅ 通过方法访问
# 使用示例
obj = GoodExample2()
print(f"items: {obj.items}")
obj2 = GoodExample2([1, 2, 3])
print(f"items: {obj2.items}")
第十部分:练习和总结
练习1:创建一个银行账户类
# 练习1:创建银行账户类
# 要求:
# 1. 有账户号和余额属性
# 2. 有存款、取款方法
# 3. 取款时检查余额是否足够
# 4. 有获取余额的方法
class BankAccount:
# 在这里实现你的代码
pass
# 测试代码
# account = BankAccount("123456", 1000)
# account.deposit(500)
# account.withdraw(200)
# print(account.get_balance())
练习2:创建一个图形类层次结构
# 练习2:创建图形类层次结构
# 要求:
# 1. 创建一个 Shape 基类
# 2. 创建 Rectangle、Circle、Triangle 子类
# 3. 每个子类实现 area() 和 perimeter() 方法
# 4. 使用多态打印所有图形的面积和周长
# 在这里实现你的代码
总结
核心概念:
- 类(Class):定义对象的模板
- 对象(Object):类的实例
- 封装(Encapsulation):隐藏内部实现细节
- 继承(Inheritance):代码复用和扩展
- 多态(Polymorphism):同一接口,不同实现
关键特性:
__init__:构造方法self:指向当前对象super():调用父类方法@property:属性装饰器@classmethod:类方法@staticmethod:静态方法- 特殊方法:
__str__,__repr__,__len__等
最佳实践:
- 使用有意义的类名和方法名
- 遵循命名约定
- 使用文档字符串(docstring)
- 合理使用封装保护数据
- 利用继承减少代码重复
- 使用多态提高代码灵活性
附录:完整示例代码
完整的面向对象示例:游戏角色系统
# 完整的面向对象示例:游戏角色系统
class Character:
"""游戏角色基类"""
def __init__(self, name, health, attack_power):
self.name = name
self.health = health
self.max_health = health
self.attack_power = attack_power
self.level = 1
self.experience = 0
def attack(self, target):
"""攻击目标"""
damage = self.attack_power
target.take_damage(damage)
return f"{self.name} 攻击了 {target.name},造成 {damage} 点伤害"
def take_damage(self, damage):
"""受到伤害"""
self.health = max(0, self.health - damage)
if self.health == 0:
return f"{self.name} 被击败了!"
return f"{self.name} 受到 {damage} 点伤害,剩余生命值:{self.health}"
def heal(self, amount):
"""治疗"""
self.health = min(self.max_health, self.health + amount)
return f"{self.name} 恢复了 {amount} 点生命值,当前生命值:{self.health}"
def gain_experience(self, exp):
"""获得经验值"""
self.experience += exp
# 简单的升级逻辑:每100经验升1级
new_level = self.experience // 100 + 1
if new_level > self.level:
self.level = new_level
self.max_health += 10
self.health = self.max_health
self.attack_power += 5
return f"{self.name} 升级了!当前等级:{self.level}"
return f"{self.name} 获得 {exp} 点经验值"
def __str__(self):
return f"{self.name} (Lv.{self.level}) - HP: {self.health}/{self.max_health}, 攻击力: {self.attack_power}"
class Warrior(Character):
"""战士类"""
def __init__(self, name):
super().__init__(name, health=100, attack_power=15)
self.armor = 5
def take_damage(self, damage):
"""战士有护甲,减少伤害"""
actual_damage = max(1, damage - self.armor)
return super().take_damage(actual_damage)
def charge(self, target):
"""冲锋攻击(额外伤害)"""
damage = self.attack_power * 2
target.take_damage(damage)
return f"{self.name} 对 {target.name} 发动冲锋,造成 {damage} 点伤害!"
class Mage(Character):
"""法师类"""
def __init__(self, name):
super().__init__(name, health=60, attack_power=20)
self.mana = 100
self.max_mana = 100
def fireball(self, target):
"""火球术(消耗法力)"""
if self.mana >= 30:
self.mana -= 30
damage = self.attack_power * 2
target.take_damage(damage)
return f"{self.name} 对 {target.name} 释放火球术,造成 {damage} 点伤害!"
return f"{self.name} 法力不足,无法释放火球术"
def meditate(self):
"""冥想(恢复法力)"""
self.mana = min(self.max_mana, self.mana + 50)
return f"{self.name} 冥想恢复法力,当前法力:{self.mana}/{self.max_mana}"
def __str__(self):
base_str = super().__str__()
return f"{base_str}, 法力: {self.mana}/{self.max_mana}"
# 游戏演示
print("=" * 50)
print("游戏角色系统演示")
print("=" * 50)
# 创建角色
warrior = Warrior("战士")
mage = Mage("法师")
print(f"\n初始状态:")
print(warrior)
print(mage)
# 战斗
print(f"\n战斗开始:")
print(warrior.attack(mage))
print(mage)
print(mage.fireball(warrior))
print(warrior)
print(warrior.charge(mage))
print(mage)
# 治疗和恢复
print(f"\n恢复:")
print(warrior.heal(20))
print(mage.meditate())
# 获得经验
print(f"\n获得经验:")
print(warrior.gain_experience(150))
print(warrior)
print(f"\n最终状态:")
print(warrior)
print(mage)
运行结果:
==================================================
游戏角色系统演示
==================================================
初始状态:
战士 (Lv.1) - HP: 100/100, 攻击力: 15
法师 (Lv.1) - HP: 60/60, 攻击力: 20, 法力: 100/100
战斗开始:
战士 攻击了 法师,造成 15 点伤害
法师 (Lv.1) - HP: 45/60, 攻击力: 20, 法力: 100/100
法师 对 战士 释放火球术,造成 40 点伤害!
战士 (Lv.1) - HP: 95/100, 攻击力: 15
战士 对 法师 发动冲锋,造成 30 点伤害!
法师 (Lv.1) - HP: 15/60, 攻击力: 20, 法力: 70/100
恢复:
战士 恢复了 20 点生命值,当前生命值:100
法师 冥想恢复法力,当前法力:100/100
获得经验:
战士 升级了!当前等级:2
战士 (Lv.2) - HP: 110/110, 攻击力: 20
最终状态:
战士 (Lv.2) - HP: 110/110, 攻击力: 20
法师 (Lv.1) - HP: 15/60, 攻击力: 20, 法力: 100/100
总结
本教程涵盖了 Python 面向对象编程的核心概念:
- 基础概念:类、对象、属性、方法
- 封装:私有属性、属性装饰器
- 继承:单继承、多重继承、方法重写
- 多态:同一接口,不同实现
- 特殊方法:
__init__,__str__,__repr__等 - 类方法和静态方法:
@classmethod,@staticmethod - 实际应用:学生管理、图书管理等系统
- 设计模式:单例模式、工厂模式
下一步学习建议:
- 练习编写自己的类和对象
- 学习更多设计模式
- 了解 Python 的元类(metaclass)
- 学习装饰器的深入应用
- 阅读优秀的开源代码,学习面向对象设计
记住:面向对象编程的核心思想是将数据和操作数据的方法组织在一起,让代码更加模块化、可维护、可扩展。多练习、多思考,你就能掌握面向对象编程的精髓!
祝你编程愉快! 🐍✨