当前位置: 首页 > news >正文

Python编程基础(八) | 类

引言:很久没有写 Python 了,有一点生疏。这是学习《Python 编程:从入门到实践(第3版)》的课后练习记录,主要目的是快速回顾基础知识。

练习1:餐馆

创建一个名为Restaurant的类,为其__init__()方法设置两个属性:restaurant_namecuisine_type。创建一个名为describe_restaurant()的方法和一个名为open_restaurant()的方法,其中前者打印前述两项信息,而后者打印一条消息,指出餐馆正在营业。

根据这个类创建一个名为restaurant的实例,分别打印其两个属性,再调用前述两个方法。

class Restaurant:def __init__(self, restaurant_name, cuisine_type):"""初始化餐馆名和菜品类型属性。"""self.restaurant_name = restaurant_nameself.cuisine_type = cuisine_typedef describe_restaurant(self):"""打印餐馆的描述信息。"""print(f"Restaurant name: {self.restaurant_name}")print(f"Cuisine type: {self.cuisine_type}")def open_restaurant(self):"""打印餐馆正在营业的消息。"""print(f"{self.restaurant_name} is open.")# 创建一个类的实例
restaurant = Restaurant("乡村基", "中餐")# 调用实例的方法
restaurant.describe_restaurant()
restaurant.open_restaurant()
Restaurant name: 乡村基
Cuisine type: 中餐
乡村基 is open.

知识点回顾:

  • 类的定义:使用 class 关键字定义一个类,类名通常采用驼峰命名法(Restaurant)。
  • 构造方法 __init__():这是一个特殊的方法,在创建类的新实例时会自动调用。它的第一个参数必须是 self
  • self 参数:它是一个指向实例本身的引用,让实例能够访问类中的属性和方法。
  • 属性 (Attribute):通过 self.属性名 = 值 的方式在 __init__() 方法中定义,用于存储与实例相关的数据。
  • 方法 (Method):在类中定义的函数。每个方法都必须包含 self 这个参数。
  • 实例化:通过 类名(实参) 的方式(如 Restaurant("乡村基", "中餐"))创建一个类的实例(或称对象)。
  • 访问属性和方法:使用点号 (.) 来访问实例的属性(如 restaurant.restaurant_name)或调用其方法(如 restaurant.describe_restaurant())。

练习2:三家餐馆

根据为练习1编写的类创建三个实例,并对每个实例调用describe_restaurant()方法。

# (此处省略了 Restaurant 类的重复定义)
class Restaurant:def __init__(self, restaurant_name, cuisine_type):self.restaurant_name = restaurant_nameself.cuisine_type = cuisine_typedef describe_restaurant(self):print(f"\nRestaurant name: {self.restaurant_name}")print(f"Cuisine type: {self.cuisine_type}")restaurant1 = Restaurant("乡村基", "中餐")
restaurant1.describe_restaurant()restaurant2 = Restaurant("喜茶", "奶茶")
restaurant2.describe_restaurant()restaurant3 = Restaurant("绵阳米粉", "中餐")
restaurant3.describe_restaurant()
Restaurant name: 乡村基
Cuisine type: 中餐Restaurant name: 喜茶
Cuisine type: 奶茶Restaurant name: 绵阳米粉
Cuisine type: 中餐

知识点回顾:

  • 创建多个实例:一个类就像一个蓝图,可以根据它创建任意数量的独立实例。
  • 实例的独立性restaurant1, restaurant2, 和 restaurant3 是三个完全独立的对象。它们各自拥有自己的 restaurant_namecuisine_type 属性,互不影响。

练习3:用户

创建一个名为User的类,其中包含属性first_namelast_name,还有用户简介中通常会有的其他几个属性。在类User中定义一个名为describe_user()的方法,用于打印用户信息摘要。再定义一个名为greet_user()的方法,用于向用户发出个性化的问候。

创建多个表示不同用户的实例,并对每个实例调用上述两个方法。

class User:def __init__(self, first_name, last_name, age, city):"""初始化用户属性。"""self.first_name = first_nameself.last_name = last_nameself.age = ageself.city = citydef describe_user(self):"""打印用户信息的摘要。"""print(f"\nUser Profile:")print(f"- First name: {self.first_name}")print(f"- Last name: {self.last_name}")print(f"- Age: {self.age}")print(f"- City: {self.city}")def greet_user(self):"""向用户发出个性化的问候。"""full_name = f"{self.first_name} {self.last_name}"print(f"Hello, {full_name}!")user1 = User("Alice", "Smith", 30, "New York")
user1.describe_user()
user1.greet_user()user2 = User("Bob", "Johnson", 25, "Los Angeles")
user2.describe_user()
user2.greet_user()
User Profile:
- First name: Alice
- Last name: Smith
- Age: 30
- City: New York
Hello, Alice Smith!User Profile:
- First name: Bob
- Last name: Johnson
- Age: 25
- City: Los Angeles
Hello, Bob Johnson!

知识点回顾:

  • 类的封装:将相关的数据(属性)和操作这些数据的代码(方法)捆绑在一个对象中,是对现实世界实体(如“用户”)的抽象。这使得代码结构更清晰,更易于管理。

练习4:就餐人数

在为练习1编写的程序中,添加一个名为number_served的属性,并将其默认值设置为0。

  • 添加一个名为set_number_served()的方法,用来设置就餐人数。
  • 添加一个名为increment_number_served()的方法,用来让就餐人数递增。
class Restaurant:def __init__(self, restaurant_name, cuisine_type):self.restaurant_name = restaurant_nameself.cuisine_type = cuisine_typeself.number_served = 0  # 设置默认值def describe_restaurant(self):print(f"Restaurant name: {self.restaurant_name}")print(f"Cuisine type: {self.cuisine_type}")def open_restaurant(self):print(f"{self.restaurant_name} is open.")def set_number_served(self, number):"""设置就餐人数。"""self.number_served = numberdef increment_number_served(self, increment):"""将就餐人数按指定的数量增加。"""self.number_served += incrementrestaurant = Restaurant("乡村基", "中餐")
print(f"初始就餐人数: {restaurant.number_served}")# 修改属性值
restaurant.number_served = 5
print(f"直接修改后的就餐人数: {restaurant.number_served}")# 通过方法设置
restaurant.set_number_served(20)
print(f"通过 set_number_served() 设置后的就餐人数: {restaurant.number_served}")# 通过方法递增
restaurant.increment_number_served(50)
print(f"通过 increment_number_served() 增加后的就餐人数: {restaurant.number_served}")
初始就餐人数: 0
直接修改后的就餐人数: 5
通过 set_number_served() 设置后的就餐人数: 20
通过 increment_number_served() 增加后的就餐人数: 70

知识点回顾:

  • 属性的默认值:可以直接在 __init__ 方法中为属性赋一个初始值,这样在创建实例时就无需为它提供实参。
  • 修改属性值
    1. 直接修改:通过实例直接访问并赋新值(如 restaurant.number_served = 5)。简单直接,但不够安全。
    2. 通过方法修改:编写专门的方法(如 set_number_served())来更新属性值。这是更推荐的方式,因为它允许在方法内部添加检查逻辑(如检查新值是否有效),从而更好地控制属性。
  • 递增属性值:编写方法(如 increment_number_served())来对属性进行增量修改,而不是完全替换。这使得对属性的操作更加具体和清晰。

练习5:尝试登录次数

User类中,添加一个login_attempts属性。编写一个increment_login_attempts()方法,将该值加1。再编写一个reset_login_attempts()方法,将其重置为0。

class User:def __init__(self, first_name, last_name):self.first_name = first_nameself.last_name = last_nameself.login_attempts = 0def greet_user(self):print(f"Hello, {self.first_name} {self.last_name}")def increment_login_attempts(self):"""将登录尝试次数增加 1。"""self.login_attempts += 1def reset_login_attempts(self):"""将登录尝试次数重置为 0。"""self.login_attempts = 0user1 = User("Alice", "Smith")
print(f"初始登录次数: {user1.login_attempts}")user1.increment_login_attempts()
user1.increment_login_attempts()
user1.increment_login_attempts()
print(f"递增后登录次数: {user1.login_attempts}")user1.reset_login_attempts()
print(f"重置后登录次数: {user1.login_attempts}")
初始登录次数: 0
递增后登录次数: 3
重置后登录次数: 0

知识点回顾:

  • 管理对象状态:通过为类编写专门的方法(如 increment_login_attemptsreset_login_attempts),可以更好地管理和控制实例(对象)的内部状态(属性 login_attempts),使对象的行为更加明确和可预测。

练习6:冰激凌小店

编写一个名为IceCreamStand的类,让它继承Restaurant类。添加一个名为flavors的属性,用于存储一个口味列表。编写一个显示这些口味的方法。

class Restaurant:def __init__(self, restaurant_name, cuisine_type):self.restaurant_name = restaurant_nameself.cuisine_type = cuisine_typedef describe_restaurant(self):print(f"Restaurant name: {self.restaurant_name.title()}")print(f"Cuisine type: {self.cuisine_type}")class IceCreamStand(Restaurant):"""冰激凌小店是一种特殊的餐馆。"""def __init__(self, restaurant_name, cuisine_type='ice cream'):"""初始化父类的属性,并添加冰激凌口味属性。"""super().__init__(restaurant_name, cuisine_type)self.flavors = ["chocolate", "vanilla", "strawberry"]def display_flavors(self):"""打印所有可用的口味。"""print("Available flavors:")for flavor in self.flavors:print(f"- {flavor.title()}")ice_cream_shop = IceCreamStand("DQ")
ice_cream_shop.describe_restaurant()
ice_cream_shop.display_flavors()
Restaurant name: Dq
Cuisine type: ice cream
Available flavors:
- Chocolate
- Vanilla
- Strawberry

知识点回顾:

  • 继承 (Inheritance):一个类(子类)可以继承另一个类(父类)的属性和方法。
  • 父类与子类Restaurant 是父类,IceCreamStand 是子类。子类自动获得父类的所有非私有属性和方法。
  • super() 函数super().__init__(...) 用于调用父类的 __init__ 方法,确保子类实例也能正确初始化从父类继承的属性。
  • 代码复用:继承是实现代码复用的强大方式。子类可以直接使用父类的方法(如 describe_restaurant()),无需重写。
  • 添加子类特有功能:子类可以在继承父类的基础上,定义自己独有的属性(flavors)和方法(display_flavors())。

练习7:管理员

编写一个名为Admin的类,让它继承User类。添加一个名为privileges的属性,用来存储一个权限字符串列表。编写一个show_privileges()方法,显示管理员的权限。

class User:def __init__(self, first_name, last_name):self.first_name = first_nameself.last_name = last_namedef greet_user(self):full_name = f"{self.first_name} {self.last_name}"print(f"Hello, {full_name.title()}!")class Admin(User):def __init__(self, first_name, last_name):"""初始化父类属性,并添加管理员权限属性。"""super().__init__(first_name, last_name)self.privileges = ['can add post', 'can delete post', 'can ban user']def show_privileges(self):"""显示管理员拥有的权限。"""print(f"Admin {self.first_name.title()} has the following privileges:")for privilege in self.privileges:print(f"- {privilege}")admin = Admin(first_name='John', last_name='Doe')
admin.greet_user()
admin.show_privileges()
Hello, John Doe!
Admin John has the following privileges:
- can add post
- can delete post
- can ban user

知识点回顾:

  • 继承的应用:这个练习再次展示了继承。Admin “是一种” User,它拥有 User 的所有特性(名和姓),同时还具备自己独特的特性(权限列表)。

练习8:权限

编写一个名为Privileges的类,它只有一个属性privileges。将方法show_privileges()移到这个类中。在Admin类中,将一个Privileges实例用作其属性。

class User:# (同上一个练习,此处省略)def __init__(self, first_name, last_name):self.first_name = first_nameself.last_name = last_namedef greet_user(self):full_name = f"{self.first_name} {self.last_name}"print(f"Hello, {full_name.title()}!")class Privileges:"""一个专门用于表示和显示管理员权限的类。"""def __init__(self):self.privileges = ['can add post', 'can delete post', 'can ban user']def show_privileges(self):"""显示权限列表。"""print('The admin has the following privileges:')for privilege in self.privileges:print(f"- {privilege}")class Admin(User):def __init__(self, first_name, last_name):super().__init__(first_name, last_name)self.privileges = Privileges() # 将 Privileges 实例作为属性admin = Admin(first_name='John', last_name='Doe')
admin.greet_user()
admin.privileges.show_privileges() # 注意调用方式的变化
Hello, John Doe!
The admin has the following privileges:
- can add post
- can delete post
- can ban user

知识点回顾:

  • 组合 (Composition):将一个类的实例作为另一个类的属性。这体现了 “has-a”(有一个)关系,例如 Admin “有一个” Privileges 对象。
  • 继承 vs. 组合:继承是 “is-a” 关系(Admin is a User),而组合是 “has-a” 关系。当一个类需要另一个类的功能,但逻辑上不属于其子类时,组合是更好的选择。
  • 代码解耦:通过将权限管理逻辑封装到独立的 Privileges 类中,Admin 类的职责更单一,代码结构更清晰,也更易于维护和扩展。

练习9:电池升级

Battery类添加一个upgrade_battery()方法。这个方法检查电池容量,如果不是65,就设置为65。创建一辆电动汽车,调用get_range(),然后升级电池,并再次调用get_range()

class Car:"""一次模拟汽车的简单尝试"""# (Car 类的代码此处省略)def __init__(self, make, model, year):self.make = makeself.model = modelself.year = yearself.odometer_reading = 0# ...class Battery:"""一次模拟电动汽车电瓶的简单尝试"""def __init__(self, battery_size=40):self.battery_size = battery_sizedef describe_battery(self):print(f"This car has a {self.battery_size}-kWh battery.")def get_range(self):"""根据电池容量打印续航里程。"""if self.battery_size == 40:range = 150elif self.battery_size == 65:range = 225else:range = "unknown"print(f"This car can go about {range} miles on a full charge.")def upgrade_battery(self):"""检查电瓶容量,并尝试升级到65kWh。"""if self.battery_size < 65:print("Upgrading the battery...")self.battery_size = 65class ElectricCar(Car):"""电动汽车的独特之处"""def __init__(self, make, model, year):super().__init__(make, model, year)self.battery = Battery()my_leaf = ElectricCar(make='nissan', model='leaf', year=2024)
my_leaf.battery.get_range()
my_leaf.battery.upgrade_battery()
my_leaf.battery.get_range()
This car can go about 150 miles on a full charge.
Upgrading the battery...
This car can go about 225 miles on a full charge.

知识点回顾:

  • 组合的实际应用ElectricCar 类本身不处理电池逻辑,而是包含一个 Battery 实例,并将所有与电池相关的操作(如 get_range, upgrade_battery)委托给这个 Battery 对象。这使得 ElectricCar 类的代码更简洁。
  • 在类的方法中添加逻辑upgrade_battery() 方法内部包含了 if 条件判断,这使得对象的方法可以根据自身状态(self.battery_size)执行不同的操作。

练习10 & 11 & 12:模块化

将类存储在单独的文件(模块)中,然后在主程序文件中导入并使用它们。

  • 练习10: 将 Restaurant 类放入 restaurant.py
  • 练习11: 将 User, Privileges, Admin 类放入 user_admin.py
  • 练习12: 将 User 放入 user.pyPrivilegesAdmin 放入 admin.py

文件 1: restaurant.py

class Restaurant:# ... Restaurant 类的完整定义 ...

主文件: main.py

from restaurant import Restaurantmy_restaurant = Restaurant('The Pizza Place', 'Pizza')
my_restaurant.describe_restaurant()

文件 1: user.py

class User:# ... User 类的完整定义 ...

文件 2: admin.py

from user import Userclass Privileges:# ... Privileges 类的完整定义 ...class Admin(User):# ... Admin 类的完整定义 ...

主文件: main.py

from admin import Adminthe_admin = Admin('super', 'user')
the_admin.privileges.show_privileges()

知识点回顾:

  • 模块 (Module):每个 .py 文件就是一个模块。将类和函数存储在模块中可以使项目结构更有条理。
  • import 语句
    • from module_name import ClassName:从一个模块中导入一个或多个特定的类。
    • import module_name:导入整个模块,使用时需要 module_name.ClassName
  • 代码组织:将相关的类放在同一个模块中,不相关的类分开放置。当一个模块依赖另一个模块中的类时(如 admin.py 依赖 user.py),可以在模块内部进行导入。这极大地提高了代码的可维护性和重用性。

练习13:骰子

创建一个Die类,有一个属性sides默认为6。编写一个roll_die()方法,打印一个1到sides之间的随机数。创建不同面数的骰子并掷多次。

from random import randintclass Die:def __init__(self, sides=6):"""初始化骰子的面数。"""self.sides = sidesdef roll_die(self):"""模拟掷骰子,并打印结果。"""result = randint(1, self.sides)print(f'Rolling a {self.sides}-sided die... Result: {result}')# 创建一个6面的骰子并掷10次
d6 = Die()
print("--- Rolling a 6-sided die 10 times ---")
for _ in range(10):d6.roll_die()# 创建一个10面的骰子并掷10次
d10 = Die(sides=10)
print("\n--- Rolling a 10-sided die 10 times ---")
for _ in range(10):d10.roll_die()
--- Rolling a 6-sided die 10 times ---
Rolling a 6-sided die... Result: 3
Rolling a 6-sided die... Result: 5
... (and so on)--- Rolling a 10-sided die 10 times ---
Rolling a 10-sided die... Result: 8
Rolling a 10-sided die... Result: 2
... (and so on)

知识点回顾:

  • 使用标准库:通过 from random import randint 导入并使用 Python 标准库中 random 模块的功能。
  • 类与循环结合:在 for 循环中调用对象的方法,可以方便地重复执行某个动作。
  • 灵活的实例:通过在创建实例时传递不同的参数(Die() vs Die(sides=10)),可以用同一个类创建出行为略有不同的对象。

练习14 & 15:彩票

  1. 从一个包含数字和字母的列表中随机抽取4个,组成中奖号码。
  2. 编写一个循环,模拟不断抽奖,直到抽中预设的中奖号码为止,并计算次数。
from random import choicedef generate_ticket(pool):"""从奖池中随机抽取4个字符组成一张彩票。"""ticket = ""for _ in range(4):ticket += str(choice(pool))return ticket# 奖池
lottery_pool = ['0', '1','2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e']# 设定中奖号码
winning_ticket = generate_ticket(lottery_pool)
print(f'The winning ticket is: {winning_ticket}')# 开始循环抽奖,直到中奖
my_ticket = ""
attempts = 0
while my_ticket != winning_ticket:my_ticket = generate_ticket(lottery_pool)attempts += 1# 为了避免输出过多,可以每隔一定次数打印一次if attempts % 10000 == 0:print(f"Attempt #{attempts}: Drew ticket {my_ticket}...")print(f"\nCongratulations! You won after {attempts} attempts!")
print(f"Your winning ticket was: {my_ticket}")
The winning ticket is: 38c8
Attempt #10000: Drew ticket 7d77...
Attempt #20000: Drew ticket 4b29...
Attempt #30000: Drew ticket a986...Congratulations! You won after 30387 attempts!
Your winning ticket was: 38c8

知识点回顾:

  • random.choice():从一个非空序列(如列表)中随机返回一个元素。
  • while 循环:当需要重复执行代码直到某个条件不再满足时(这里是 my_ticket != winning_ticket),while 循环非常适用。
  • 计数器变量:在循环中使用一个变量(attempts)来追踪循环执行的次数是一种常见的编程模式。
  • 程序模拟:通过编程来模拟现实世界中的随机事件(如彩票),是检验概率和算法的有效方法。

文章转载自:

http://hu9kHlJw.thhrf.cn
http://OxGqfnH8.thhrf.cn
http://qEL1iRAH.thhrf.cn
http://AaLor6R3.thhrf.cn
http://5GDAJSh7.thhrf.cn
http://sxtOAauu.thhrf.cn
http://2QujkjWs.thhrf.cn
http://t7Ffp43f.thhrf.cn
http://J1mNrs4J.thhrf.cn
http://1Ex1FUC8.thhrf.cn
http://GPjgKNcA.thhrf.cn
http://6N98NPfz.thhrf.cn
http://XdpTc00o.thhrf.cn
http://S3UHgqo0.thhrf.cn
http://HJQEcm2F.thhrf.cn
http://OmKmSrYr.thhrf.cn
http://QZCGIUvp.thhrf.cn
http://JRRty3Ga.thhrf.cn
http://CtKBUdR3.thhrf.cn
http://ZMi1BiyW.thhrf.cn
http://SqJkCXCq.thhrf.cn
http://LnNzlEBe.thhrf.cn
http://1uvRDxjB.thhrf.cn
http://IyYb4yPN.thhrf.cn
http://kKciRLdY.thhrf.cn
http://tcjSSWxD.thhrf.cn
http://TiCeCg86.thhrf.cn
http://0QfMuPAN.thhrf.cn
http://y0ZoVUXM.thhrf.cn
http://gWh10KFD.thhrf.cn
http://www.dtcms.com/a/374138.html

相关文章:

  • Ubuntu1804安装SonarQube
  • commons-lang3
  • 分布式专题——4 大厂生产级Redis高并发分布式锁实战
  • Infortrend普安科技IEC私有云平台VM解决方案
  • 实战对比:百炼知识库与钉钉知识库的全方位对比
  • GitLab升级后仓库镜像信任证书导入问题
  • 2. 计算机系统基础知识
  • 软考中级习题与解答——第三章_操作系统(2)
  • 第七届全球校园人工智能算法精英大赛-算法巅峰赛产业命题赛--算法题科普
  • 【CentOS7】使用yum安装出错,报HTTPS Error 404 - Not Found
  • 今天继续学习shell脚本
  • 解决哈希冲突
  • C++算法专题学习:栈相关的算法
  • CentOS部署ELK Stack完整指南
  • 多模态大模型Keye-VL-1.5发布!视频理解能力更强!
  • JAK/STAT信号通路全解析:核心分子、激活与负调控
  • 人工智能知识图谱应用平台国家标准发布实施
  • Chiplet封装革命:路登多芯片同步固晶治具支持异构集成
  • 语法分析:编译器中的“语法警察”
  • python数据分析工具特点分析
  • 高并发场景下的“命令执行”注入绕道记
  • Java创建对象的5种方式
  • Redis+Envoy实现智能流量治理:动态读写分离方案
  • ros2中qos的调优配置
  • 【GPT入门】第65课 vllm指定其他卡运行的方法,解决单卡CUDA不足的问题
  • 网络地址转换(NAT)详解
  • 综合体项目 3D 数字孪生可视化运维管理平台解决方案
  • 平衡车 -- MPU6050
  • 【PyTorch】图像二分类
  • 自动驾驶中的传感器技术39——Radar(0)