Python面向对象编程(五)¶
章节概述¶
面向对象编程(OOP)是一种重要的编程范式,它将数据和操作数据的方法组织在一起,形成"对象"。本章将介绍Python中面向对象编程的核心概念。
学习目标¶
- 理解面向对象编程的基本概念
- 掌握类和对象的定义和使用
- 理解继承和多态
- 学会使用封装保护数据
(一)类与对象¶
类的定义¶
class 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}岁"
对象的创建和使用¶
# 创建对象
dog1 = Dog("旺财", 3)
dog2 = Dog("小黑", 5)
# 访问属性
print(dog1.name) # 旺财
print(dog2.age) # 5
# 调用方法
print(dog1.bark()) # 旺财在汪汪叫!
print(dog2.info()) # 名字:小黑,年龄:5岁
# 访问类属性
print(Dog.species) # 犬科
print(dog1.species) # 犬科
实例分析¶
实例1:创建学生类
class Student:
"""学生类"""
def __init__(self, name, student_id, scores=None):
self.name = name
self.student_id = student_id
self.scores = scores or []
def add_score(self, score):
"""添加成绩"""
self.scores.append(score)
def average_score(self):
"""计算平均分"""
if not self.scores:
return 0
return sum(self.scores) / len(self.scores)
def is_passed(self, pass_score=60):
"""判断是否及格"""
return self.average_score() >= pass_score
def __str__(self):
"""字符串表示"""
return f"学生:{self.name},学号:{self.student_id},平均分:{self.average_score():.1f}"
# 使用
stu1 = Student("张三", "2024001", [85, 90, 78])
stu1.add_score(92)
print(stu1) # 学生:张三,学号:2024001,平均分:86.2
print(stu1.is_passed()) # True
(二)封装¶
访问控制¶
class BankAccount:
"""银行账户类(封装示例)"""
def __init__(self, owner, balance=0):
self.owner = owner # 公有属性
self.__balance = balance # 私有属性(双下划线)
def deposit(self, amount):
"""存款"""
if amount > 0:
self.__balance += amount
return f"存入{amount}元,余额{self.__balance}元"
return "存款金额必须大于0"
def withdraw(self, amount):
"""取款"""
if 0 < amount <= self.__balance:
self.__balance -= amount
return f"取出{amount}元,余额{self.__balance}元"
return "余额不足或金额无效"
def get_balance(self):
"""获取余额"""
return self.__balance
def __str__(self):
return f"账户:{self.owner},余额:{self.__balance}元"
# 使用
account = BankAccount("张三", 10000)
print(account.deposit(5000)) # 存入5000元,余额15000元
print(account.withdraw(3000)) # 取出3000元,余额12000元
# print(account.__balance) # 报错:AttributeError
print(account.get_balance()) # 12000
property装饰器¶
class Circle:
"""圆类(使用property)"""
def __init__(self, radius):
self._radius = radius
@property
def radius(self):
"""获取半径"""
return self._radius
@radius.setter
def radius(self, value):
"""设置半径"""
if value < 0:
raise ValueError("半径不能为负数")
self._radius = value
@property
def area(self):
"""计算面积(只读属性)"""
import math
return math.pi * self._radius ** 2
@property
def circumference(self):
"""计算周长(只读属性)"""
import math
return 2 * math.pi * self._radius
# 使用
c = Circle(5)
print(f"半径:{c.radius}") # 半径:5
print(f"面积:{c.area:.2f}") # 面积:78.54
print(f"周长:{c.circumference:.2f}") # 周长:31.42
c.radius = 10 # 可以修改
print(f"新面积:{c.area:.2f}") # 新面积:314.16
# c.area = 100 # 报错:can't set attribute
(三)继承¶
基本继承¶
class Animal:
"""动物基类"""
def __init__(self, name, age):
self.name = name
self.age = age
def speak(self):
raise NotImplementedError("子类必须实现speak方法")
def info(self):
return f"名字:{self.name},年龄:{self.age}岁"
class Dog(Animal):
"""狗狗类(继承Animal)"""
def __init__(self, name, age, breed):
super().__init__(name, age) # 调用父类方法
self.breed = breed
def speak(self):
return f"{self.name}:汪汪汪!"
def fetch(self):
return f"{self.name}去捡球了!"
class Cat(Animal):
"""猫咪类(继承Animal)"""
def speak(self):
return f"{self.name}:喵喵喵!"
def scratch(self):
return f"{self.name}在磨爪子!"
# 使用
dog = Dog("旺财", 3, "金毛")
cat = Cat("小花", 2)
print(dog.speak()) # 旺财:汪汪汪!
print(dog.info()) # 名字:旺财,年龄:3岁
print(dog.fetch()) # 旺财去捡球了!
print(cat.speak()) # 小花:喵喵喵!
print(cat.info()) # 名字:小花,年龄:2岁
多重继承¶
class Flyable:
"""可飞行的"""
def fly(self):
return "我在飞翔!"
class Swimmable:
"""可游泳的"""
def swim(self):
return "我在游泳!"
class Duck(Animal, Flyable, Swimmable):
"""鸭子类(多重继承)"""
def speak(self):
return f"{self.name}:嘎嘎嘎!"
# 使用
duck = Duck("唐老鸭", 5)
print(duck.speak()) # 唐老鸭:嘎嘎嘎!
print(duck.fly()) # 我在飞翔!
print(duck.swim()) # 我在游泳!
# 查看继承顺序(MRO)
print(Duck.__mro__)
方法重写¶
class Shape:
"""形状基类"""
def area(self):
return 0
def perimeter(self):
return 0
def __str__(self):
return f"面积:{self.area():.2f},周长:{self.perimeter():.2f}"
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)
def __str__(self):
return f"矩形({self.width}x{self.height})- {super().__str__()}"
class Circle(Shape):
"""圆形"""
def __init__(self, radius):
self.radius = radius
def area(self):
import math
return math.pi * self.radius ** 2
def perimeter(self):
import math
return 2 * math.pi * self.radius
def __str__(self):
return f"圆形(r={self.radius})- {super().__str__()}"
# 使用
shapes = [Rectangle(5, 3), Circle(4)]
for shape in shapes:
print(shape)
# 矩形(5x3)- 面积:15.00,周长:16.00
# 圆形(r=4)- 面积:50.27,周长:25.13
(四)多态¶
多态的实现¶
class Printer:
"""打印机类"""
def print_doc(self, doc):
raise NotImplementedError
class LaserPrinter(Printer):
"""激光打印机"""
def print_doc(self, doc):
return f"激光打印机打印:{doc}"
class InkjetPrinter(Printer):
"""喷墨打印机"""
def print_doc(self, doc):
return f"喷墨打印机打印:{doc}"
class _3DPrinter(Printer):
"""3D打印机"""
def print_doc(self, doc):
return f"3D打印机打印:{doc}"
# 多态:相同的方法调用,不同的行为
def print_document(printer, document):
"""统一的打印接口"""
return printer.print_doc(document)
# 使用
printers = [LaserPrinter(), InkjetPrinter(), _3DPrinter()]
doc = "Python教程"
for printer in printers:
print(print_document(printer, doc))
# 输出:
# 激光打印机打印:Python教程
# 喷墨打印机打印:Python教程
# 3D打印机打印:Python教程
鸭子类型¶
class Dog:
def speak(self):
return "汪汪!"
def walk(self):
return "四条腿走路"
class Cat:
def speak(self):
return "喵喵!"
def walk(self):
return "四条腿走路"
class Bird:
def speak(self):
return "叽叽!"
def walk(self):
return "两条腿走路"
# 鸭子类型:只要对象有speak()方法就行
def animal_speak(animal):
return animal.speak()
# 测试
for animal in [Dog(), Cat(), Bird()]:
print(animal_speak(animal))
# 输出:
# 汪汪!
# 喵喵!
# 叽叽!
(五)特殊方法(魔术方法)¶
常用特殊方法¶
class Vector:
"""向量类(演示特殊方法)"""
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
"""开发者友好的字符串表示"""
return f"Vector({self.x}, {self.y})"
def __str__(self):
"""用户友好的字符串表示"""
return f"({self.x}, {self.y})"
def __add__(self, other):
"""加法:v1 + v2"""
return Vector(self.x + other.x, self.y + other.y)
def __sub__(self, other):
"""减法:v1 - v2"""
return Vector(self.x - other.x, self.y - other.y)
def __mul__(self, scalar):
"""乘法:v * scalar"""
return Vector(self.x * scalar, self.y * scalar)
def __abs__(self):
"""绝对值:|v|(向量长度)"""
return (self.x ** 2 + self.y ** 2) ** 0.5
def __eq__(self, other):
"""相等比较:v1 == v2"""
return self.x == other.x and self.y == other.y
def __len__(self):
"""长度:返回向量维度"""
return 2
def __getitem__(self, index):
"""索引访问:v[0], v[1]"""
if index == 0:
return self.x
elif index == 1:
return self.y
raise IndexError("向量索引超出范围")
# 使用
v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(v1) # (3, 4)
print(repr(v1)) # Vector(3, 4)
print(v1 + v2) # (4, 6)
print(v1 - v2) # (2, 2)
print(v1 * 3) # (9, 12)
print(abs(v1)) # 5.0
print(v1[0]) # 3
print(v1[1]) # 4
print(v1 == v2) # False
实战练习¶
练习1:银行账户系统¶
class BankAccount:
"""银行账户"""
def __init__(self, owner, balance=0):
self.owner = owner
self.__balance = balance
self.__history = []
def deposit(self, amount):
if amount <= 0:
return "存款金额必须大于0"
self.__balance += amount
self.__history.append(f"存入:+{amount}")
return f"存入{amount}元成功,余额:{self.__balance}元"
def withdraw(self, amount):
if amount <= 0:
return "取款金额必须大于0"
if amount > self.__balance:
return "余额不足"
self.__balance -= amount
self.__history.append(f"取出:-{amount}")
return f"取出{amount}元成功,余额:{self.__balance}元"
@property
def balance(self):
return self.__balance
def get_history(self):
return self.__history.copy()
def __str__(self):
return f"账户:{self.owner},余额:{self.__balance}元"
# 测试
account = BankAccount("张三", 10000)
print(account.deposit(5000))
print(account.withdraw(3000))
print(account.balance)
print(account.get_history())
练习2:图形类层次¶
import math
class Shape:
"""形状基类"""
def area(self):
raise NotImplementedError
def __lt__(self, other):
return self.area() < other.area()
class Rectangle(Shape):
def __init__(self, w, h):
self.w, self.h = w, h
def area(self):
return self.w * self.h
class Circle(Shape):
def __init__(self, r):
self.r = r
def area(self):
return math.pi * self.r ** 2
# 测试
shapes = [Rectangle(5, 3), Circle(4), Rectangle(2, 8)]
shapes.sort(key=lambda s: s.area())
for s in shapes:
print(f"{s.__class__.__name__}: {s.area():.2f}")
章节小结¶
本章介绍了Python面向对象编程的核心概念:
- 类与对象:理解类的定义、对象的创建和使用
- 封装:使用私有属性和property保护数据
- 继承:实现代码复用和类层次结构
- 多态:相同接口,不同实现
- 特殊方法:自定义类的行为
面向对象编程是Python的重要编程范式,掌握它能写出更优雅、可维护的代码。
下一步¶
继续学习第六章:文件操作与异常处理,学习文件读写和异常处理。
重点提醒: - 类是对象的模板,对象是类的实例 - 继承实现代码复用,多态提高灵活性 - 封装保护数据,property提供访问控制 - 特殊方法让类更Pythonic