Python面向对象编程指南
面向对象编程(Object-Oriented Programming,OOP)是Python最核心的编程范式之一。本文将系统讲解Python中类与对象的概念、继承与多态、封装与私有属性、特殊方法以及类方法与静态方法,最后通过一个图书管理系统实战案例巩固所学知识。
一、类与对象的基本概念
类(Class)是对象的蓝图或模板,定义了一类事物共有的属性和行为。对象(Object)是类的具体实例。可以理解为:类是"汽车"的设计图,对象是根据设计图造出来的具体某辆车。
# 定义一个简单的类
class Dog:
"""这是一个简单的Dog类"""
# 类属性(所有实例共享)
species = "犬科动物"
def __init__(self, name, age):
"""构造函数,初始化实例属性"""
self.name = name # 实例属性
self.age = age
def bark(self):
"""实例方法"""
return f"{self.name}说:汪汪汪!"
def info(self):
"""返回狗狗的信息"""
return f"{self.name},{self.age}岁,{self.species}"
# 创建对象(实例化)
dog1 = Dog("旺财", 3)
dog2 = Dog("小黑", 5)
print(dog1.bark()) # 旺财说:汪汪汪!
print(dog2.info()) # 小黑,5岁,犬科动物
print(Dog.species) # 犬科动物(通过类名访问类属性)
二、self参数详解
self代表类的当前实例。在Python中定义实例方法时,第一个参数必须是self(虽然你可以用其他名字,但强烈建议使用self)。当调用方法时,Python会自动将当前实例作为self传入。
class Circle:
def __init__(self, radius):
self.radius = radius # self.radius 是实例属性
def area(self):
"""计算面积"""
return 3.14159 * self.radius ** 2
def circumference(self):
"""计算周长"""
return 2 * 3.14159 * self.radius
def compare(self, other):
"""比较两个圆的大小"""
if self.radius > other.radius:
return f"{self.radius}的圆比{other.radius}的圆大"
elif self.radius < other.radius:
return f"{self.radius}的圆比{other.radius}的圆小"
else:
return "两个圆一样大"
c1 = Circle(5)
c2 = Circle(10)
print(f"面积: {c1.area():.2f}")
print(f"周长: {c2.circumference():.2f}")
print(c1.compare(c2))
三、构造函数 __init__
__init__ 是Python中的构造方法(严格来说是初始化方法),在创建对象时自动调用。它用于初始化对象的属性。
class Student:
school = "Python大学" # 类属性
def __init__(self, name, age, grade="大一"):
self.name = name
self.age = age
self.grade = grade
self.scores = [] # 默认可变属性使用列表,每个实例独立
def add_score(self, score):
"""添加成绩"""
if 0 <= score <= 100:
self.scores.append(score)
return True
return False
def average_score(self):
"""计算平均分"""
if not self.scores:
return 0
return sum(self.scores) / len(self.scores)
def __str__(self):
return f"学生:{self.name},年龄:{self.age},年级:{self.grade}"
# 使用关键字参数
stu1 = Student("张三", 20)
stu2 = Student("李四", 21, grade="大二")
stu1.add_score(95)
stu1.add_score(88)
stu1.add_score(76)
print(stu1)
print(f"{stu1.name}的平均分:{stu1.average_score():.1f}")
四、继承与多态
继承允许子类(派生类)继承父类(基类)的属性和方法,实现代码复用。多态是指不同对象对同一方法的不同实现。
# 父类
class Animal:
def __init__(self, name, sound):
self.name = name
self.sound = sound
def speak(self):
return f"{self.name}发出声音:{self.sound}"
def move(self):
return f"{self.name}正在移动"
# 子类继承父类
class Cat(Animal):
def __init__(self, name, color):
super().__init__(name, "喵喵喵") # 调用父类构造函数
self.color = color
def climb(self):
"""子类特有的方法"""
return f"{self.name}正在爬树"
class Bird(Animal):
def __init__(self, name, wingspan):
super().__init__(name, "叽叽喳喳")
self.wingspan = wingspan
# 方法重写(覆盖父类方法)
def move(self):
return f"{self.name}正在用{self.wingspan}厘米的翅膀飞翔"
# 多态演示
def animal_action(animal):
print(animal.speak())
print(animal.move())
print("---")
animals = [
Animal("未知动物", "???"),
Cat("小花", "橘色"),
Bird("小燕子", 15)
]
for animal in animals:
animal_action(animal)
五、方法重写与super()函数
子类可以重写父类的方法来提供特定的实现。super()函数用于在子类中调用父类的方法,避免重复代码。
class Employee:
def __init__(self, name, salary):
self.name = name
self.salary = salary
def get_info(self):
return f"员工:{self.name},基本工资:{self.salary}元"
def yearly_bonus(self):
return self.salary * 1 # 默认一个月奖金
class Manager(Employee):
def __init__(self, name, salary, department, team_size):
super().__init__(name, salary)
self.department = department
self.team_size = team_size
def get_info(self):
"""重写父类方法,扩展信息"""
base_info = super().get_info()
return f"{base_info},部门:{self.department},团队人数:{self.team_size}"
def yearly_bonus(self):
"""重写奖金计算方法"""
base_bonus = super().yearly_bonus()
team_bonus = self.team_size * 500 # 每人500元团队奖金
return base_bonus + team_bonus
class Developer(Employee):
def __init__(self, name, salary, language):
super().__init__(name, salary)
self.language = language
def get_info(self):
base_info = super().get_info()
return f"{base_info},编程语言:{self.language}"
def yearly_bonus(self):
base_bonus = super().yearly_bonus()
return base_bonus * 1.5 # 开发者奖金1.5倍
# 测试
emp = Employee("张三", 8000)
mgr = Manager("李四", 15000, "技术部", 8)
dev = Developer("王五", 12000, "Python")
print(emp.get_info())
print(f" 年终奖:{emp.yearly_bonus()}元")
print(mgr.get_info())
print(f" 年终奖:{mgr.yearly_bonus()}元")
print(dev.get_info())
print(f" 年终奖:{dev.yearly_bonus()}元")
六、封装与私有属性
封装是将数据(属性)和操作数据的方法绑定在一起,并隐藏内部实现细节。Python中使用下划线约定来实现访问控制:单下划线 _ 表示"受保护",双下划线 __ 表示"私有"。
class BankAccount:
def __init__(self, owner, balance=0):
self.owner = owner # 公有属性
self._balance = balance # 受保护属性(约定不要直接访问)
self.__transaction_log = [] # 私有属性(名称修饰)
def deposit(self, amount):
"""存款"""
if amount > 0:
self._balance += amount
self.__add_log(f"存入 {amount}元")
return True
print("存款金额必须大于0")
return False
def withdraw(self, amount):
"""取款"""
if amount <= 0:
print("取款金额必须大于0")
return False
if amount > self._balance:
print("余额不足")
return False
self._balance -= amount
self.__add_log(f"取出 {amount}元")
return True
def get_balance(self):
"""获取余额(通过方法访问受保护属性)"""
return self._balance
def __add_log(self, message):
"""私有方法:记录交易日志"""
import datetime
time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.__transaction_log.append(f"[{time_str}] {message}")
def show_log(self):
"""显示交易日志"""
for log in self.__transaction_log:
print(log)
@property
def balance(self):
"""用property装饰器提供对私有属性的访问"""
return self._balance
@balance.setter
def balance(self, value):
"""限制余额不能为负数"""
if value < 0:
raise ValueError("余额不能为负数")
self._balance = value
# 使用
account = BankAccount("平平", 1000)
account.deposit(500)
account.withdraw(200)
print(f"当前余额:{account.get_balance()}元")
print("--- 交易记录 ---")
account.show_log()
# property 的用法
print(f"\n通过property访问余额:{account.balance}元")
account.balance = 2000 # 通过setter修改
print(f"修改后余额:{account.balance}元")
七、特殊方法(魔术方法)
Python通过特殊方法(以双下划线开头和结尾)让自定义类的行为像内置类型一样自然。
class Vector:
"""二维向量类"""
def __init__(self, x=0, y=0):
self.x = x
self.y = y
# 字符串表示
def __str__(self):
return f"Vector({self.x}, {self.y})"
def __repr__(self):
return f"Vector({self.x}, {self.y})"
# 向量加法
def __add__(self, other):
return Vector(self.x + other.x, self.y + other.y)
# 向量减法
def __sub__(self, other):
return Vector(self.x - other.x, self.y - other.y)
# 向量乘法(数乘)
def __mul__(self, scalar):
if isinstance(scalar, (int, float)):
return Vector(self.x * scalar, self.y * scalar)
return NotImplemented
# 反向乘法(支持 scalar * vector)
def __rmul__(self, scalar):
return self.__mul__(scalar)
# 长度
def __abs__(self):
return (self.x ** 2 + self.y ** 2) ** 0.5
# 相等判断
def __eq__(self, other):
if isinstance(other, Vector):
return self.x == other.x and self.y == other.y
return NotImplemented
# 布尔值判断(零向量为False)
def __bool__(self):
return self.x != 0 or self.y != 0
# 长度(支持len())
def __len__(self):
return 2
# 迭器支持
def __iter__(self):
return iter((self.x, self.y))
# 下标访问
def __getitem__(self, index):
if index == 0:
return self.x
elif index == 1:
return self.y
raise IndexError("向量只有两个分量")
# 小于比较
def __lt__(self, other):
return abs(self) < abs(other)
# 使用
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(f"v1 = {v1}")
print(f"v2 = {v2}")
print(f"v1 + v2 = {v1 + v2}")
print(f"v1 - v2 = {v1 - v2}")
print(f"v1 * 3 = {v1 * 3}")
print(f"|v1| = {abs(v1)}")
print(f"v1 == v2: {v1 == v2}")
print(f"bool(v1): {bool(v1)}")
print(f"v1[0] = {v1[0]}, v1[1] = {v1[1]}")
print(f"v1 < v2: {v1 < v2}")
八、类方法与静态方法
实例方法操作实例数据,类方法(@classmethod)操作类级别数据,静态方法(@staticmethod)是与类相关但不操作类或实例数据的工具函数。
import math
class Temperature:
"""温度转换工具类"""
def __init__(self, celsius):
self.celsius = celsius
@property
def fahrenheit(self):
return self.celsius * 9 / 5 + 32
@property
def kelvin(self):
return self.celsius + 273.15
def __str__(self):
return (f"{self.celsius}C = {self.fahrenheit:.1f}F "
f"= {self.kelvin:.2f}K")
@classmethod
def from_fahrenheit(cls, f):
"""类方法:从华氏度创建实例"""
celsius = (f - 32) * 5 / 9
return cls(celsius)
@classmethod
def from_kelvin(cls, k):
"""类方法:从开尔文创建实例"""
celsius = k - 273.15
return cls(celsius)
@staticmethod
def is_valid_celsius(value):
"""静态方法:验证摄氏度值是否合理"""
return -273.15 <= value <= 1_000_000
@staticmethod
def celsius_to_fahrenheit(c):
"""静态方法:简单的单位转换,不依赖实例"""
return c * 9 / 5 + 32
# 使用实例方法
t1 = Temperature(100)
print(t1) # 100C = 212.0F = 373.15K
# 使用类方法创建实例
t2 = Temperature.from_fahrenheit(98.6)
print(f"体温:{t2:.1f}C")
t3 = Temperature.from_kelvin(0)
print(f"绝对零度:{t3:.2f}C")
# 使用静态方法
print(f"100C有效吗?{Temperature.is_valid_celsius(100)}")
print(f"-300C有效吗?{Temperature.is_valid_celsius(-300)}")
print(f"0C转F:{Temperature.celsius_to_fahrenheit(0)}F")
九、实战案例:图书管理系统
综合运用以上知识,我们来实现一个功能完整的图书管理系统。
from datetime import datetime, timedelta
# ========== 基类:物品 ==========
class LibraryItem:
"""图书馆物品基类"""
def __init__(self, title, item_id):
self.title = title
self.item_id = item_id
self.is_borrowed = False
self.borrower = None
self.borrow_date = None
def borrow(self, borrower_name):
"""借出"""
if self.is_borrowed:
print(f"《{self.title}》已被 {self.borrower} 借走")
return False
self.is_borrowed = True
self.borrower = borrower_name
self.borrow_date = datetime.now()
print(f"{borrower_name} 成功借阅《{self.title}》")
return True
def return_item(self):
"""归还"""
if not self.is_borrowed:
print(f"《{self.title}》未借出")
return False
days = (datetime.now() - self.borrow_date).days
self.is_borrowed = False
print(f"《{self.title}》已归还(借阅 {days} 天)")
self.borrower = None
self.borrow_date = None
return True
def __str__(self):
status = "已借出" if self.is_borrowed else "可借阅"
return f"[{self.item_id}] 《{self.title}》 - {status}"
# ========== 子类:图书 ==========
class Book(LibraryItem):
"""图书类"""
def __init__(self, title, author, isbn, pages):
super().__init__(title, f"B-{isbn}")
self.author = author
self.isbn = isbn
self.pages = pages
self.category = "未分类"
def info(self):
return (f"《{self.title}》 - {self.author}\n"
f" ISBN: {self.isbn} | {self.pages}页 | 分类: {self.category}")
# ========== 子类:杂志 ==========
class Magazine(LibraryItem):
"""杂志类"""
def __init__(self, title, issue, publisher):
super().__init__(title, f"M-{issue}")
self.issue = issue
self.publisher = publisher
def info(self):
return f"《{self.title}》 第{self.issue}期 | {self.publisher}"
# ========== 图书馆管理类 ==========
class Library:
"""图书馆管理系统"""
def __init__(self, name):
self.name = name
self._items = {} # item_id -> LibraryItem
def add_item(self, item):
"""添加物品"""
self._items[item.item_id] = item
print(f"已添加:{item}")
def remove_item(self, item_id):
"""移除物品"""
if item_id in self._items:
item = self._items.pop(item_id)
print(f"已移除:《{item.title}》")
return True
print(f"未找到ID为 {item_id} 的物品")
return False
def find_by_title(self, keyword):
"""按标题搜索"""
results = []
for item in self._items.values():
if keyword in item.title:
results.append(item)
return results
def find_available(self):
"""查找所有可借阅物品"""
return [item for item in self._items.values()
if not item.is_borrowed]
def show_all(self):
"""显示所有物品"""
print(f"\n{'='*50}")
print(f" {self.name} - 共 {len(self._items)} 件物品")
print(f"{'='*50}")
for item in self._items.values():
print(f" {item}")
print()
def show_borrowed(self):
"""显示借出列表"""
borrowed = [i for i in self._items.values() if i.is_borrowed]
print(f"\n--- 当前借出 ({len(borrowed)} 件) ---")
for item in borrowed:
print(f" {item.item_id}: 《{item.title}》 - {item.borrower}")
if not borrowed:
print(" 暂无借出")
print()
# ========== 使用示例 ==========
if __name__ == "__main__":
lib = Library("平平的小图书馆")
# 添加图书
b1 = Book("Python编程:从入门到实践", "Eric Matthes", "9787115428028", 459)
b1.category = "编程"
b2 = Book("流畅的Python", "Luciano Ramalho", "9787115454157", 688)
b2.category = "编程"
b3 = Book("百年孤独", "加西亚·马尔克斯", "9787544253994", 360)
b3.category = "文学"
# 添加杂志
m1 = Magazine("Python Weekly", "2024-01", "Python Software Foundation")
m2 = Magazine("程序员", "2024-03", "电子工业出版社")
for item in [b1, b2, b3, m1, m2]:
lib.add_item(item)
# 显示所有
lib.show_all()
# 借书
b1.borrow("张三")
b3.borrow("李四")
# 再次借已被借走的书
b1.borrow("王五")
# 归还
b3.return_item()
# 搜索
print("\n--- 搜索'Python' ---")
for item in lib.find_by_title("Python"):
print(f" {item.info()}")
print("\n--- 可借阅列表 ---")
for item in lib.find_available():
print(f" {item}")
lib.show_borrowed()
以上就是Python面向对象编程的完整指南。从类与对象的基本概念,到继承与多态、封装与私有属性、特殊方法、类方法与静态方法,再到图书管理系统的实战案例。掌握这些知识后,你就能够用面向对象的方式组织复杂程序的代码结构,提高代码的可维护性和可复用性。
十、总结与要点回顾
- 类是对象的蓝图,对象是类的实例
- self 参数代表当前实例,在方法定义中必不可少
- __init__ 是初始化方法,在实例化时自动调用
- 继承通过 class Sub(Parent) 语法实现,super() 调用父类方法
- 单下划线 _ 表示受保护属性,双下划线 __ 会触发名称修饰
- 特殊方法让自定义类拥有内置类型的行为
- @classmethod 操作类级别数据,@staticmethod 定义工具函数
- @property 提供对私有属性的安全访问控制