第10:面向对象编程基础

目录

面向对象编程概述

面向对象编程(Object-Oriented Programming,OOP)是一种编程范式,它将现实世界中的事物抽象为对象,通过对象之间的交互来解决问题。

面向对象的核心概念

# 1. 类(Class):对象的模板或蓝图
# 2. 对象(Object):类的实例
# 3. 属性(Attribute):对象的特征或状态
# 4. 方法(Method):对象的行为或功能
# 5. 封装(Encapsulation):隐藏对象的内部实现细节
# 6. 继承(Inheritance):子类继承父类的属性和方法
# 7. 多态(Polymorphism):同一接口的不同实现

面向对象的优势

  1. 模块化:代码组织更清晰
  2. 可重用性:通过继承和组合重用代码
  3. 可维护性:修改局部不影响整体
  4. 可扩展性:容易添加新功能

类和对象

类是创建对象的模板,对象是类的实例。

定义类

# 定义一个简单的类
class Person:
    """人类"""
    pass

# 创建对象(实例化)
person1 = Person()
person2 = Person()

print(type(person1))  # 输出:<class '__main__.Person'>
print(person1 is person2)  # 输出:False(不同的对象)

类的基本结构

class Person:
    """人类类"""
    
    # 类属性
    species = "Homo sapiens"
    
    # 初始化方法
    def __init__(self, name, age):
        # 实例属性
        self.name = name
        self.age = age
    
    # 实例方法
    def introduce(self):
        return f"我是{self.name},今年{self.age}岁"
    
    def have_birthday(self):
        self.age += 1
        return f"{self.name}现在{self.age}岁了"

# 创建对象并使用
person = Person("张三", 25)
print(person.introduce())  # 输出:我是张三,今年25岁
print(person.have_birthday())  # 输出:张三现在26岁了

属性和方法

属性是对象的特征,方法是对象的行为。

实例属性

class Car:
    """汽车类"""
    
    def __init__(self, brand, model, year):
        # 实例属性
        self.brand = brand      # 品牌
        self.model = model      # 型号
        self.year = year        # 年份
        self.mileage = 0        # 里程(公里)
        self.is_running = False # 是否运行中

# 创建汽车对象
car1 = Car("丰田", "卡罗拉", 2020)
car2 = Car("本田", "雅阁", 2021)

print(f"{car1.brand} {car1.model} {car1.year}年")  # 输出:丰田 卡罗拉 2020年
print(f"{car2.brand} {car2.model} {car2.year}年")  # 输出:本田 雅阁 2021年

实例方法

class Car:
    """汽车类"""
    
    def __init__(self, brand, model, year):
        self.brand = brand
        self.model = model
        self.year = year
        self.mileage = 0
        self.is_running = False
    
    # 启动汽车
    def start(self):
        if not self.is_running:
            self.is_running = True
            return f"{self.brand} {self.model} 已启动"
        else:
            return f"{self.brand} {self.model} 已经在运行中"
    
    # 停止汽车
    def stop(self):
        if self.is_running:
            self.is_running = False
            return f"{self.brand} {self.model} 已停止"
        else:
            return f"{self.brand} {self.model} 已经停止了"
    
    # 行驶
    def drive(self, distance):
        if self.is_running:
            self.mileage += distance
            return f"行驶了{distance}公里,总里程{self.mileage}公里"
        else:
            return "请先启动汽车"
    
    # 获取汽车信息
    def get_info(self):
        status = "运行中" if self.is_running else "已停止"
        return f"{self.brand} {self.model} ({self.year}年) - 里程:{self.mileage}公里,状态:{status}"

# 使用汽车类
my_car = Car("丰田", "卡罗拉", 2020)
print(my_car.start())        # 输出:丰田 卡罗拉 已启动
print(my_car.drive(100))     # 输出:行驶了100公里,总里程100公里
print(my_car.drive(50))      # 输出:行驶了50公里,总里程150公里
print(my_car.get_info())     # 输出:丰田 卡罗拉 (2020年) - 里程:150公里,状态:运行中
print(my_car.stop())         # 输出:丰田 卡罗拉 已停止

构造方法和析构方法

构造方法用于初始化对象,析构方法用于清理资源。

构造方法 init

class Student:
    """学生类"""
    
    def __init__(self, name, student_id, grades=None):
        """构造方法"""
        self.name = name
        self.student_id = student_id
        self.grades = grades if grades is not None else []
        print(f"创建学生对象:{self.name}")
    
    def add_grade(self, subject, grade):
        """添加成绩"""
        self.grades.append({"subject": subject, "grade": grade})
    
    def get_average(self):
        """计算平均分"""
        if not self.grades:
            return 0
        total = sum(grade["grade"] for grade in self.grades)
        return total / len(self.grades)

# 创建学生对象
student = Student("张三", "2023001")
student.add_grade("数学", 85)
student.add_grade("英语", 90)
print(f"平均分:{student.get_average()}")  # 输出:平均分:87.5

析构方法 del

class DatabaseConnection:
    """数据库连接类"""
    
    def __init__(self, host, port):
        self.host = host
        self.port = port
        print(f"连接到数据库 {host}:{port}")
    
    def query(self, sql):
        """执行查询"""
        return f"执行查询:{sql}"
    
    def __del__(self):
        """析构方法"""
        print(f"关闭数据库连接 {self.host}:{self.port}")

# 使用数据库连接
db = DatabaseConnection("localhost", 5432)
result = db.query("SELECT * FROM users")
print(result)

# 对象超出作用域时自动调用析构方法
# 注意:Python的垃圾回收机制可能会延迟析构方法的调用

封装

封装是将对象的内部实现细节隐藏起来,只暴露必要的接口。

访问控制

class BankAccount:
    """银行账户类"""
    
    def __init__(self, account_number, initial_balance=0):
        self.account_number = account_number    # 公有属性
        self._balance = initial_balance         # 受保护属性(约定)
        self.__pin = "1234"                     # 私有属性
    
    # 公有方法
    def deposit(self, amount):
        """存款"""
        if amount > 0:
            self._balance += amount
            return f"存款成功,当前余额:{self._balance}"
        return "存款金额必须大于0"
    
    def withdraw(self, amount, pin):
        """取款"""
        if pin != self.__pin:
            return "密码错误"
        if amount > self._balance:
            return "余额不足"
        self._balance -= amount
        return f"取款成功,当前余额:{self._balance}"
    
    def get_balance(self):
        """获取余额"""
        return self._balance
    
    # 私有方法
    def __validate_pin(self, pin):
        """验证密码(私有方法)"""
        return pin == self.__pin

# 使用银行账户
account = BankAccount("123456789", 1000)
print(account.deposit(500))           # 输出:存款成功,当前余额:1500
print(account.withdraw(200, "1234"))  # 输出:取款成功,当前余额:1300
print(account.get_balance())          # 输出:1300

# 尝试直接访问私有属性(会出错)
# print(account.__pin)  # AttributeError
# 但可以通过名称改写访问(不推荐)
# print(account._BankAccount__pin)  # 输出:1234

属性装饰器

class Temperature:
    """温度类"""
    
    def __init__(self, celsius=0):
        self._celsius = celsius
    
    @property
    def celsius(self):
        """获取摄氏度"""
        return self._celsius
    
    @celsius.setter
    def celsius(self, value):
        """设置摄氏度"""
        if value < -273.15:
            raise ValueError("温度不能低于绝对零度")
        self._celsius = value
    
    @property
    def fahrenheit(self):
        """获取华氏度"""
        return self._celsius * 9/5 + 32
    
    @fahrenheit.setter
    def fahrenheit(self, value):
        """设置华氏度"""
        self.celsius = (value - 32) * 5/9

# 使用温度类
temp = Temperature(25)
print(f"摄氏度:{temp.celsius}")      # 输出:摄氏度:25
print(f"华氏度:{temp.fahrenheit}")   # 输出:华氏度:77.0

temp.fahrenheit = 86
print(f"摄氏度:{temp.celsius}")      # 输出:摄氏度:30.0

# temp.celsius = -300  # 会抛出ValueError异常

继承

继承允许子类获得父类的属性和方法。

基本继承

# 父类(基类)
class Animal:
    """动物类"""
    
    def __init__(self, name, species):
        self.name = name
        self.species = species
    
    def make_sound(self):
        return "动物发出声音"
    
    def info(self):
        return f"我是{self.name},属于{self.species}"

# 子类(派生类)
class Dog(Animal):
    """狗类"""
    
    def __init__(self, name, breed):
        super().__init__(name, "犬科")  # 调用父类构造方法
        self.breed = breed
    
    # 重写父类方法
    def make_sound(self):
        return "汪汪汪!"
    
    # 添加新方法
    def wag_tail(self):
        return f"{self.name}摇尾巴"

class Cat(Animal):
    """猫类"""
    
    def __init__(self, name, color):
        super().__init__(name, "猫科")
        self.color = color
    
    # 重写父类方法
    def make_sound(self):
        return "喵喵喵!"
    
    # 添加新方法
    def purr(self):
        return f"{self.name}发出呼噜声"

# 使用继承
dog = Dog("旺财", "金毛")
cat = Cat("咪咪", "橘色")

print(dog.info())        # 输出:我是旺财,属于犬科
print(dog.make_sound())  # 输出:汪汪汪!
print(dog.wag_tail())    # 输出:旺财摇尾巴

print(cat.info())        # 输出:我是咪咪,属于猫科
print(cat.make_sound())  # 输出:喵喵喵!
print(cat.purr())        # 输出:咪咪发出呼噜声

多重继承

class Flyable:
    """可飞行"""
    
    def fly(self):
        return "正在飞行"

class Swimmable:
    """可游泳"""
    
    def swim(self):
        return "正在游泳"

class Duck(Animal, Flyable, Swimmable):
    """鸭子类"""
    
    def __init__(self, name):
        super().__init__(name, "鸭科")
    
    def make_sound(self):
        return "嘎嘎嘎!"

# 使用多重继承
duck = Duck("唐老鸭")
print(duck.info())       # 输出:我是唐老鸭,属于鸭科
print(duck.make_sound()) # 输出:嘎嘎嘎!
print(duck.fly())        # 输出:正在飞行
print(duck.swim())       # 输出:正在游泳

多态

多态允许不同类的对象对同一消息做出不同的响应。

多态示例

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

# 多态的使用
shapes = [
    Rectangle(5, 3),
    Circle(4),
    Triangle(3, 4, 5)
]

for shape in shapes:
    print(f"形状类型:{type(shape).__name__}")
    print(f"面积:{shape.area():.2f}")
    print(f"周长:{shape.perimeter():.2f}")
    print("-" * 20)

isinstance() 和 issubclass()

# 检查对象类型
rectangle = Rectangle(5, 3)
print(isinstance(rectangle, Rectangle))  # 输出:True
print(isinstance(rectangle, Shape))      # 输出:True
print(isinstance(rectangle, Circle))     # 输出:False

# 检查类继承关系
print(issubclass(Rectangle, Shape))      # 输出:True
print(issubclass(Circle, Shape))         # 输出:True
print(issubclass(Rectangle, Circle))     # 输出:False

特殊方法

特殊方法(魔术方法)允许我们自定义类的行为。

常用特殊方法

class Vector:
    """向量类"""
    
    def __init__(self, x, y):
        self.x = x
        self.y = y
    
    def __str__(self):
        """字符串表示"""
        return f"Vector({self.x}, {self.y})"
    
    def __repr__(self):
        """官方字符串表示"""
        return f"Vector(x={self.x}, y={self.y})"
    
    def __add__(self, other):
        """加法运算"""
        if isinstance(other, Vector):
            return Vector(self.x + other.x, self.y + other.y)
        return NotImplemented
    
    def __sub__(self, other):
        """减法运算"""
        if isinstance(other, Vector):
            return Vector(self.x - other.x, self.y - other.y)
        return NotImplemented
    
    def __mul__(self, scalar):
        """数乘运算"""
        if isinstance(scalar, (int, float)):
            return Vector(self.x * scalar, self.y * scalar)
        return NotImplemented
    
    def __eq__(self, other):
        """相等比较"""
        if isinstance(other, Vector):
            return self.x == other.x and self.y == other.y
        return False
    
    def __len__(self):
        """长度(返回维度数)"""
        return 2
    
    def __getitem__(self, index):
        """索引访问"""
        if index == 0:
            return self.x
        elif index == 1:
            return self.y
        else:
            raise IndexError("向量只有两个元素")
    
    def __setitem__(self, index, value):
        """索引赋值"""
        if index == 0:
            self.x = value
        elif index == 1:
            self.y = value
        else:
            raise IndexError("向量只有两个元素")

# 使用向量类
v1 = Vector(3, 4)
v2 = Vector(1, 2)

print(str(v1))           # 输出:Vector(3, 4)
print(repr(v1))          # 输出:Vector(x=3, y=4)

v3 = v1 + v2
print(v3)                # 输出:Vector(4, 6)

v4 = v1 - v2
print(v4)                # 输出:Vector(2, 2)

v5 = v1 * 3
print(v5)                # 输出:Vector(9, 12)

print(v1 == v2)          # 输出:False
print(len(v1))           # 输出:2
print(v1[0], v1[1])      # 输出:3 4

v1[0] = 5
print(v1)                # 输出:Vector(5, 4)

类属性和类方法

类属性属于类本身,类方法操作类属性。

类属性

class Employee:
    """员工类"""
    
    # 类属性
    company_name = "科技有限公司"
    employee_count = 0
    
    def __init__(self, name, position, salary):
        self.name = name
        self.position = position
        self.salary = salary
        # 每创建一个员工,员工计数加1
        Employee.employee_count += 1
    
    def get_info(self):
        return f"{self.name} - {self.position} - {self.salary}元"
    
    @classmethod
    def get_company_name(cls):
        """类方法:获取公司名称"""
        return cls.company_name
    
    @classmethod
    def get_employee_count(cls):
        """类方法:获取员工总数"""
        return cls.employee_count
    
    @classmethod
    def set_company_name(cls, name):
        """类方法:设置公司名称"""
        cls.company_name = name

# 使用类属性和类方法
emp1 = Employee("张三", "程序员", 10000)
emp2 = Employee("李四", "设计师", 8000)
emp3 = Employee("王五", "产品经理", 12000)

print(Employee.get_company_name())    # 输出:科技有限公司
print(Employee.get_employee_count())  # 输出:3
print(emp1.get_employee_count())      # 输出:3

# 修改类属性
Employee.set_company_name("新科技有限公司")
print(Employee.get_company_name())    # 输出:新科技有限公司
print(emp1.get_company_name())        # 输出:新科技有限公司

静态方法

静态方法不访问类或实例的属性,类似于普通函数。

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(MathUtils.add(5, 3))        # 输出:8
print(MathUtils.multiply(4, 6))   # 输出:24
print(MathUtils.is_even(10))      # 输出:True
print(MathUtils.factorial(5))     # 输出:120

# 静态方法可以通过类名或实例调用
utils = MathUtils()
print(utils.add(2, 3))            # 输出:5

实际应用示例

# 图书管理系统
class Book:
    """图书类"""
    
    def __init__(self, isbn, title, author, publication_year):
        self.isbn = isbn
        self.title = title
        self.author = author
        self.publication_year = publication_year
        self.is_borrowed = False
        self.borrower = None
    
    def __str__(self):
        status = "已借出" if self.is_borrowed else "在馆"
        return f"《{self.title}》 - {self.author} ({self.publication_year}) [{status}]"
    
    def borrow(self, borrower_name):
        """借书"""
        if self.is_borrowed:
            return f"《{self.title}》已被{self.borrower}借阅"
        self.is_borrowed = True
        self.borrower = borrower_name
        return f"《{self.title}》借阅成功,借阅人:{borrower_name}"
    
    def return_book(self):
        """还书"""
        if not self.is_borrowed:
            return f"《{self.title}》未被借阅"
        borrower = self.borrower
        self.is_borrowed = False
        self.borrower = None
        return f"《{self.title}》归还成功,归还人:{borrower}"

class Library:
    """图书馆类"""
    
    def __init__(self, name):
        self.name = name
        self.books = []
        self.members = []
    
    def add_book(self, book):
        """添加图书"""
        self.books.append(book)
        return f"图书《{book.title}》已添加到图书馆"
    
    def remove_book(self, isbn):
        """移除图书"""
        for i, book in enumerate(self.books):
            if book.isbn == isbn:
                removed_book = self.books.pop(i)
                return f"图书《{removed_book.title}》已从图书馆移除"
        return "未找到指定ISBN的图书"
    
    def find_book(self, keyword):
        """查找图书"""
        results = []
        for book in self.books:
            if (keyword in book.title or 
                keyword in book.author or 
                keyword == book.isbn):
                results.append(book)
        return results
    
    def list_books(self):
        """列出所有图书"""
        if not self.books:
            return "图书馆暂无图书"
        return "\n".join(str(book) for book in self.books)
    
    def borrow_book(self, isbn, borrower_name):
        """借书"""
        for book in self.books:
            if book.isbn == isbn:
                return book.borrow(borrower_name)
        return "未找到指定ISBN的图书"
    
    def return_book(self, isbn):
        """还书"""
        for book in self.books:
            if book.isbn == isbn:
                return book.return_book()
        return "未找到指定ISBN的图书"

# 使用图书管理系统
library = Library("城市图书馆")

# 添加图书
book1 = Book("978-7-111-2635-0", "Python编程:从入门到实践", "埃里克·马瑟斯", 2019)
book2 = Book("978-7-115-42802-8", "流畅的Python", "卢西亚诺·拉马略", 2017)
book3 = Book("978-7-111-52824-5", "Python核心编程", "韦斯利·春", 2016)

library.add_book(book1)
library.add_book(book2)
library.add_book(book3)

print("图书馆图书列表:")
print(library.list_books())
print()

# 借书
print(library.borrow_book("978-7-111-2635-0", "张三"))
print(library.borrow_book("978-7-115-42802-8", "李四"))
print()

print("借阅后的图书状态:")
print(library.list_books())
print()

# 还书
print(library.return_book("978-7-111-2635-0"))
print()

print("还书后的图书状态:")
print(library.list_books())
print()

# 查找图书
print("查找'Python'相关图书:")
results = library.find_book("Python")
for book in results:
    print(book)

总结

本篇教程详细介绍了面向对象编程的基础知识,包括类和对象、属性和方法、构造方法和析构方法、封装、继承、多态、特殊方法、类属性和类方法、静态方法等内容。

掌握面向对象编程是成为优秀Python程序员的重要一步,它能够帮助我们编写更加模块化、可重用和可维护的代码。


Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐