面向对象编程入门(上篇):从现实世界到代码世界 你写的代码越来越长函数越来越多维护起来像在玩“找不同”游戏。今天我们来学习一种让代码更清晰、更易维护的编程范式——面向对象编程。它不是语法而是一种思维方式。想象一下你要用代码描述一个“人”他有名字、年龄、性别他会吃饭、走路、说话他有家庭、朋友、职业如果用之前学过的知识你可能会这样写# 用多个变量和函数表示一个人 name 张三 age 25 gender 男 def eat(person_name, food): print(f{person_name}在吃{food}) def walk(person_name, destination): print(f{person_name}在走去{destination}) # 使用 eat(name, 午饭) walk(name, 公司)这有三个明显问题变量和函数是分散的没有明确关联如果要表示多个人代码会变得非常混乱修改和维护时容易出错面向对象编程Object-Oriented Programming简称OOP就是为了解决这些问题而生的。一、什么是面向对象编程现实世界的启示先看看我们生活的世界你的手机是一个对象你的电脑是一个对象你的水杯是一个对象这些对象有共同特点属性描述对象特征手机的品牌、颜色、内存行为对象能做什么手机能打电话、拍照、上网类别对象属于哪一类iPhone 15属于手机这一类面向对象编程就是把现实世界的思维方式带到编程中把数据属性和操作数据的函数行为捆绑在一起创建出一个个独立的对象对象之间通过消息调用方法进行交互一句话概括面向对象编程是用代码模拟现实世界的思维方式。二、核心概念类和对象1. 类Class对象的蓝图类是抽象的模板定义了一类对象共同的属性和行为。例子汽车设计图定义了一辆车应该有品牌、颜色、速度等属性定义了一辆车能够启动、加速、刹车等行为但它不是一辆真正的车不能开2. 对象Object类的实例对象是类的具体实现是根据类创建出来的具体个体。例子根据汽车设计图生产出来的具体车辆我的白色特斯拉Model 3朋友的黑色比亚迪汉这些都是具体存在的对象关系类 → 对象​ 就像设计图 → 实物# 用Python表达这个关系 class Car: # 类汽车设计图 pass my_car Car() # 对象我的具体汽车 your_car Car() # 对象你的具体汽车 print(type(my_car)) # 输出class __main__.Car print(my_car is your_car) # 输出False两个不同的对象随堂练习1# 创建一个Person类 # 创建两个Person对象zhangsan和lisi class Person: pass zhangsan Person() lisi Person() print(fzhangsan的类型{type(zhangsan)}) print(flisi的类型{type(lisi)}) print(f他们是同一个对象吗{zhangsan is lisi})三、定义第一个类从学生开始让我们从一个简单的学生类开始class Student: 学生类 # 初始化方法创建对象时自动调用 def __init__(self, name, age, student_id): # 属性学生的特征 self.name name # 姓名 self.age age # 年龄 self.student_id student_id # 学号 self.score 0 # 成绩默认0分 # 方法学生的行为 def study(self, subject, hours): 学习 print(f{self.name}正在学习{subject}已经学了{hours}小时) self.score hours * 0.5 # 每学习1小时成绩提高0.5分 def take_exam(self, exam_name): 参加考试 print(f{self.name}正在参加{exam_name}考试) if self.score 60: print(f考试通过最终成绩{self.score:.1f}分) return True else: print(f考试未通过需要补考。成绩{self.score:.1f}分) return False def introduce(self): 自我介绍 print(f大家好我叫{self.name}今年{self.age}岁学号是{self.student_id})关键点解析1.__init__方法对象的出生证明__init__是初始化方法在创建对象时自动调用用于设置对象的初始属性第一个参数必须是self指向对象自己其他参数是创建对象时需要提供的信息# 创建学生对象时会调用__init__方法 student1 Student(张三, 20, 2023001) # 相当于Student.__init__(student1, 张三, 20, 2023001)2.self参数对象自己self是一个特殊参数指向当前对象实例在类的方法中通过self.属性名访问对象的属性在类的方法中通过self.方法名()调用其他方法Python自动传递self我们不需要手动传递def study(self, subject, hours): # self.name 访问当前对象的name属性 print(f{self.name}正在学习{subject}...)3. 属性和方法属性对象的特征用self.属性名 值定义方法对象的行为就是类中定义的函数随堂练习2# 创建一个Book类 # 属性title书名、author作者、price价格 # 方法discount打折按百分比打折 # display显示书籍信息 class Book: def __init__(self, title, author, price): self.title title self.author author self.price price def discount(self, percent): 打折percent是折扣百分比如20表示打8折 discount_amount self.price * percent / 100 self.price - discount_amount print(f{self.title}打{percent}%折新价格{self.price:.2f}元) def display(self): print(f《{self.title}》 - {self.author} 著) print(f价格{self.price:.2f}元) # 测试 book1 Book(Python编程从入门到实践, Eric Matthes, 89.0) book1.display() book1.discount(20) # 打8折四、创建和使用对象1. 创建对象根据类生产具体个体# 创建学生对象 student1 Student(张三, 20, 2023001) student2 Student(李四, 21, 2023002) student3 Student(王五, 19, 2023003) # 每个对象都是独立的 print(fstudent1的名字{student1.name}) # 张三 print(fstudent2的名字{student2.name}) # 李四 print(fstudent3的名字{student3.name}) # 王五2. 访问属性获取对象的特征# 使用点号(.)访问属性 print(f{student1.name}的年龄是{student1.age}岁) print(f{student2.name}的学号是{student2.student_id}) # 修改属性 student1.age 21 # 张三过生日了 print(f过生日后{student1.name}的年龄是{student1.age}岁)3. 调用方法让对象执行行为# 学生自我介绍 student1.introduce() # 输出大家好我叫张三今年20岁学号是2023001 student2.introduce() # 输出大家好我叫李四今年21岁学号是2023002 # 学生学习 student1.study(Python, 4) # 张三学习Python 4小时 student1.study(数学, 2) # 张三学习数学 2小时 # 学生考试 student1.take_exam(Python期末考试)随堂练习3# 使用Book类创建两本书 # 1. 《三体》刘慈欣著原价68元 # 2. 《活着》余华著原价45元 # 对《三体》打7折对《活着》打8折 # 显示两本书的最终信息 book1 Book(三体, 刘慈欣, 68.0) book2 Book(活着, 余华, 45.0) book1.discount(30) # 打7折 book2.discount(20) # 打8折 print(\n最终图书信息) book1.display() book2.display()五、实际案例银行账户系统让我们用一个实际的例子来巩固理解。假设我们要创建一个简单的银行账户系统class BankAccount: 银行账户类 def __init__(self, account_holder, account_number, initial_balance0): 初始化账户 参数 account_holder: 账户持有人姓名 account_number: 账户号码 initial_balance: 初始余额默认为0 self.account_holder account_holder self.account_number account_number self.balance initial_balance self.transactions [] # 交易记录 def deposit(self, amount): 存款 if amount 0: print(存款金额必须大于0) return False self.balance amount self.transactions.append(f存款: {amount:.2f}元) print(f存款成功存入{amount:.2f}元当前余额{self.balance:.2f}元) return True def withdraw(self, amount): 取款 if amount 0: print(取款金额必须大于0) return False if amount self.balance: print(f余额不足当前余额{self.balance:.2f}元) return False self.balance - amount self.transactions.append(f取款: -{amount:.2f}元) print(f取款成功取出{amount:.2f}元当前余额{self.balance:.2f}元) return True def transfer(self, to_account, amount): 转账到另一个账户 if amount 0: print(转账金额必须大于0) return False if amount self.balance: print(f余额不足当前余额{self.balance:.2f}元) return False # 从当前账户扣款 self.balance - amount self.transactions.append(f转账给{to_account.account_holder}: -{amount:.2f}元) # 向目标账户存款 to_account.balance amount to_account.transactions.append(f收到{self.account_holder}的转账: {amount:.2f}元) print(f转账成功向{to_account.account_holder}转账{amount:.2f}元) return True def get_balance(self): 查询余额 return self.balance def get_transaction_history(self): 获取交易记录 if not self.transactions: print(暂无交易记录) return print(f\n {self.account_holder}的交易记录 ) for i, transaction in enumerate(self.transactions, 1): print(f{i}. {transaction}) print(f当前余额: {self.balance:.2f}元) print( * 40) def display_info(self): 显示账户信息 print(f\n账户持有人{self.account_holder}) print(f账户号码{self.account_number}) print(f当前余额{self.balance:.2f}元) print(f交易次数{len(self.transactions)}次) # 使用银行账户系统 def test_bank_system(): # 创建两个账户 account1 BankAccount(张三, 6228480012345678901, 1000) account2 BankAccount(李四, 6228480098765432109, 500) print( 初始状态 ) account1.display_info() account2.display_info() print(\n 存款测试 ) account1.deposit(500) # 张三存款500 print(\n 取款测试 ) account1.withdraw(200) # 张三取款200 print(\n 转账测试 ) account1.transfer(account2, 300) # 张三向李四转账300 print(\n 交易记录 ) account1.get_transaction_history() account2.get_transaction_history() print(\n 最终状态 ) account1.display_info() account2.display_info() # 运行测试 if __name__ __main__: test_bank_system()运行结果示例 初始状态 账户持有人张三 账户号码6228480012345678901 当前余额1000.00元 交易次数0次 账户持有人李四 账户号码6228480098765432109 当前余额500.00元 交易次数0次 存款测试 存款成功存入500.00元当前余额1500.00元 取款测试 取款成功取出200.00元当前余额1300.00元 转账测试 转账成功向李四转账300.00元 交易记录 张三的交易记录 1. 存款: 500.00元 2. 取款: -200.00元 3. 转账给李四: -300.00元 当前余额: 1000.00元 李四的交易记录 1. 收到张三的转账: 300.00元 当前余额: 800.00元 最终状态 账户持有人张三 账户号码6228480012345678901 当前余额1000.00元 交易次数3次 账户持有人李四 账户号码6228480098765432109 当前余额800.00元 交易次数1次六、类的特殊方法除了__init__Python类还有其他特殊方法它们以双下划线开头和结尾。最常用的是__str__方法用于定义对象的字符串表示class Student: def __init__(self, name, age, student_id): self.name name self.age age self.student_id student_id def __str__(self): 定义打印对象时的输出 return fStudent(name{self.name}, age{self.age}, id{self.student_id}) def __repr__(self): 定义在交互式环境中的输出通常与__str__相同 return self.__str__() # 使用 student Student(张三, 20, 2023001) print(student) # 输出Student(name张三, age20, id2023001) # 之前会输出__main__.Student object at 0x...七、面向对象编程的优势通过上面的例子你应该能感受到面向对象编程的优点了1.封装性数据和操作绑定在一起账户余额balance和存款deposit、取款withdraw操作在一起外部只需要知道存钱、取钱不需要知道内部如何实现2.模块化每个类是一个独立模块银行账户系统可以独立开发和测试可以复用到其他程序中3.可维护性代码结构清晰修改账户逻辑时只需要修改BankAccount类不会影响其他部分的代码4.可扩展性容易添加新功能要添加贷款功能只需要在类中添加新方法不影响现有功能八、常见问题与解答Q1什么时候应该使用面向对象编程A当你的程序需要表示现实世界的实体并且这些实体有状态属性​ 和行为方法​ 时。比如用户、订单、商品、车辆等。Q2类和对象有什么区别A类就像设计图对象就像根据设计图制造的产品。一个类可以创建多个对象。Q3self到底是什么Aself是指向当前对象的引用。在类的方法中通过self可以访问当前对象的属性和方法。Python会自动传递self我们不需要手动传递。Q4为什么要用__init__方法A__init__是初始化方法在创建对象时自动调用用于设置对象的初始状态。就像新生儿出生时要登记姓名、出生日期一样。九、综合练习图书馆管理系统题目创建一个简单的图书馆管理系统要求定义一个Book类包含以下属性title书名author作者isbnISBN号available是否可借布尔值Book类包含以下方法borrow()借书如果可借将available设为Falsereturn_book()还书将available设为Truedisplay_info()显示图书信息定义一个Library类包含以下属性name图书馆名称books图书列表包含多个Book对象Library类包含以下方法add_book(book)添加图书find_book(isbn)根据ISBN查找图书list_available_books()列出所有可借的图书borrow_book(isbn)借出指定ISBN的图书return_book(isbn)归还指定ISBN的图书参考代码框架class Book: def __init__(self, title, author, isbn): # 你的代码 def borrow(self): # 你的代码 def return_book(self): # 你的代码 def display_info(self): # 你的代码 class Library: def __init__(self, name): # 你的代码 def add_book(self, book): # 你的代码 def find_book(self, isbn): # 你的代码 def list_available_books(self): # 你的代码 def borrow_book(self, isbn): # 你的代码 def return_book(self, isbn): # 你的代码 # 测试代码 def test_library(): # 创建图书馆 library Library(市图书馆) # 添加图书 book1 Book(Python编程, 张三, 978-7-121-12345-6) book2 Book(数据结构, 李四, 978-7-121-12346-3) book3 Book(算法导论, 王五, 978-7-121-12347-0) library.add_book(book1) library.add_book(book2) library.add_book(book3) # 列出可借图书 print(可借图书) library.list_available_books() # 借书 print(\n借阅978-7-121-12345-6) library.borrow_book(978-7-121-12345-6) # 再次列出可借图书 print(\n借阅后可借图书) library.list_available_books() # 还书 print(\n归还978-7-121-12345-6) library.return_book(978-7-121-12345-6) # 最终状态 print(\n最终可借图书) library.list_available_books() if __name__ __main__: test_library()今日总结在面向对象编程入门上篇中你学会了核心概念类对象的蓝图或模板对象类的具体实例属性对象的特征数据方法对象的行为函数关键语法定义类class 类名:初始化方法__init__(self, ...)属性定义self.属性名 值方法定义def 方法名(self, ...):创建对象对象名 类名(参数)面向对象思维从现实世界抽象识别事物的属性和行为封装将数据和操作封装在一起模块化每个类是一个独立的模块一个生动的比喻类 → 汽车设计图对象 → 根据设计图生产的汽车属性 → 汽车的颜色、品牌、速度方法 → 汽车的启动、加速、刹车__init__→ 汽车出厂设置self→ 汽车自己下篇预告在面向对象编程入门下篇中我们将深入学习继承创建更专业的类比如电动汽车继承自汽车多态不同的对象对同一消息做出不同响应封装进阶私有属性和方法类属性和类方法通过上下两篇的学习你将能够用面向对象的思维方式设计和编写更复杂、更易维护的程序。思考题尝试用面向对象的思想描述你正在使用的设备手机、电脑。它有哪些属性有哪些行为如何用类来表示现在你已经迈出了面向对象编程的第一步。从今天起试着用对象的视角看世界你会发现编程和现实世界是如此相似