跳转至

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面向对象编程的核心概念:

  1. 类与对象:理解类的定义、对象的创建和使用
  2. 封装:使用私有属性和property保护数据
  3. 继承:实现代码复用和类层次结构
  4. 多态:相同接口,不同实现
  5. 特殊方法:自定义类的行为

面向对象编程是Python的重要编程范式,掌握它能写出更优雅、可维护的代码。

下一步

继续学习第六章:文件操作与异常处理,学习文件读写和异常处理。


重点提醒: - 类是对象的模板,对象是类的实例 - 继承实现代码复用,多态提高灵活性 - 封装保护数据,property提供访问控制 - 特殊方法让类更Pythonic