第一年 · 第12周
第十二章:什么是对象?
本周我们跨过编程中的一座大桥:从松散的变量和函数走向对象。对象把数据(属性)和动作(方法)打包成一个整齐的包裹。类是蓝图,告诉Python这种类型的每个对象应该长什么样。到这节课结束时,你将创建自己的对象,并理解程序员为什么要这样组织代码。
学习目标
- 用通俗的话解释类和对象的区别
- 为任何现实世界中的"东西"找出属性和方法
- 凭记忆写一个带参数和 if 语句的 Python 函数
- 用
class关键字创建自己的类,并从类创建对象
热身(10分钟)——做一张宝可梦卡片!
每人拿到一张空白卡片。在卡片上写下:
- 名字(比如:皮卡丘)
- 类型(比如:电系)
- HP(在1–100之间选一个数字)
- 一个攻击招式名称(比如:十万伏特)
- 攻击伤害值(比如:30)
找一个搭档"对战":说"我用十万伏特攻击,造成30点伤害!"你的搭档从自己的HP中减去30。
对战结束后,老师会问你:
- 每张卡片都有哪些信息?——这些就是属性。
- 每只宝可梦都能做哪些动作?——这些就是方法。
为什么需要类?先看混乱的写法
在没有类之前,程序员用单独的变量存储数据。看看这会变得多混乱:
# 混乱的写法——没有类 pikachu_name = 'Pikachu' pikachu_hp = 100 pikachu_damage = 20 charmander_name = 'Charmander' charmander_hp = 90 charmander_damage = 18 def attack(attacker_name, attacker_damage, target_hp): new_hp = target_hp - attacker_damage print(attacker_name, 'attacks for', attacker_damage, 'damage!') return new_hp charmander_hp = attack(pikachu_name, pikachu_damage, charmander_hp) print('Charmander HP:', charmander_hp)
想象一下如果有100只宝可梦。你会有300个变量!类让我们把一个对象的所有数据和动作打包成一个整齐的包裹。
你的第一个类
这里是一个最简单的宝可梦类——暂时不用 __init__,我们下节课再改进它。现在看看我们怎么把信息直接附加到对象上:
# 类就是蓝图 class Pokemon: pass # 'pass' 表示'暂时为空' # 从类创建一个对象 pikachu = Pokemon() pikachu.name = 'Pikachu' pikachu.hp = 100 pikachu.damage = 20 print(pikachu.name) # 输出:Pikachu print(pikachu.hp) # 输出:100 # 再创建第二只宝可梦 charmander = Pokemon() charmander.name = 'Charmander' charmander.hp = 90 charmander.damage = 18
注意我们是怎么用点号来访问和设置属性的:
pikachu.name—— 对象名 + 点号 + 属性名pikachu.hp—— 每个对象有自己独立的HP值
练习(25分钟)
打开 Thonny,按照下面的题目一步步完成。每道题先自己尝试写代码,再点击"显示答案"核对。
第1题:创建一个 Minecraft 类
写一个空的 Minecraft 类(跟上面的 Pokemon 一样用 pass)。然后创建一个叫 creeper 的对象,给它设置三个属性:
name设为'Creeper'hp设为20color设为'green'
最后用 print 打印出 creeper.name、creeper.hp 和 creeper.color。
显示答案
class Minecraft: pass creeper = Minecraft() creeper.name = 'Creeper' creeper.hp = 20 creeper.color = 'green' print(creeper.name) print(creeper.hp) print(creeper.color)
先定义类,再用 Minecraft() 创建对象,然后用点号设置属性。
第2题:再创建一个 Minecraft 生物对象
用同一个 Minecraft 类,创建第二个对象叫 zombie:
name设为'Zombie'hp设为25color设为'dark green'
然后打印 zombie.name 和 zombie.hp。
显示答案
zombie = Minecraft() zombie.name = 'Zombie' zombie.hp = 25 zombie.color = 'dark green' print(zombie.name) print(zombie.hp)
注意:不需要再写一次 class Minecraft。类只需要定义一次,可以反复创建多个对象。
第3题:概念题——类 vs 对象
回答以下两个问题:
- 在上面第1题和第2题中,类是什么?对象有哪些?
- 如果
creeper.hp从 20 变成了 0,zombie.hp会跟着变吗?为什么?
显示答案
问题1:Minecraft 是类(蓝图)。creeper 和 zombie 是两个不同的对象(实体)。
问题2:不会。每个对象有自己独立的属性值。creeper.hp 和 zombie.hp 是两个不同的"抽屉"——改一个不影响另一个。这就是对象的独立性。
第4题:找属性和方法
想象一个"学校储物柜"。写出:
- 至少 3个属性(它存储的信息)
- 至少 2个方法(它能做的动作)
显示答案
属性(它拥有的数据):
locker_number—— 柜子编号(比如 42)owner—— 使用者名字(比如 'Alice')is_open—— 是否打开(True 或 False)color—— 柜子颜色
方法(它能执行的动作):
open()—— 打开柜门close()—— 关上柜门change_owner(new_name)—— 更换使用者
记住:属性是名词(它有什么),方法是动词(它能做什么)。
第5题:用代码为储物柜建模
创建一个 Locker 类,然后创建一个储物柜对象并设置以下属性:
number= 42owner= 'Alice'is_open= False
写一段 if/else 代码:如果 is_open 为 True,打印 "The locker is open";否则打印 "The locker is closed"。
显示答案
class Locker: pass my_locker = Locker() my_locker.number = 42 my_locker.owner = 'Alice' my_locker.is_open = False if my_locker.is_open: print("The locker is open") else: print("The locker is closed")
这里你把前面学过的创建对象和if/else条件判断结合在一起了。对象和条件语句可以一起工作!
第6题:写一个攻击函数
写一个函数 attack(attacker, target),它做两件事:
- 打印
"[攻击者名字] attacks [目标名字]!" - 把目标的 HP 减去攻击者的 damage,打印目标的新 HP
然后调用这个函数,让 creeper 攻击 zombie。
显示答案
def attack(attacker, target): print(attacker.name + ' attacks ' + target.name + '!') target.hp = target.hp - attacker.damage print(target.name + ' HP: ' + str(target.hp)) attack(creeper, zombie)
这个函数接收两个对象作为参数,然后用点号读取和修改它们的属性。运行后,zombie 的 HP 会从 25 变成 5(25 - 20 = 5)。
第7题:连续攻击
用第6题的 attack 函数,让 creeper 再攻击一次 zombie。然后写一段 if/else 代码判断 zombie 的 HP:
- 如果 HP <= 0,打印
"[zombie名字] is defeated!" - 否则,打印
"[zombie名字] survived with [HP] HP!"
显示答案
attack(creeper, zombie) # 第二次攻击 if zombie.hp <= 0: print(zombie.name + ' is defeated!') else: print(zombie.name + ' survived with ' + str(zombie.hp) + ' HP!')
第一次攻击后 zombie 的 HP 是 5,第二次攻击后变成 5 - 20 = -15。因为 -15 <= 0,所以会打印 "Zombie is defeated!"。
第8题:挑战题——创建你自己的类
选择一个你喜欢的东西(汽车、手机、宠物、食物……什么都可以),完成以下任务:
- 创建一个类(名字自己取,但要用英文,首字母大写,比如
Car、Phone) - 创建两个不同的对象
- 每个对象至少有 3个属性(用点号设置)
- 写一个函数,接收你的对象作为参数,打印出至少两个属性
- 调用函数,传入两个对象
显示示例答案(以汽车为例)
class Car: pass car1 = Car() car1.brand = 'Toyota' car1.color = 'red' car1.speed = 0 car2 = Car() car2.brand = 'Tesla' car2.color = 'white' car2.speed = 60 def show_car(car): print('Brand:', car.brand) print('Color:', car.color) print('Speed:', car.speed) show_car(car1) show_car(car2)
你可以选任何东西!关键是:定义类、创建多个对象、用点号设置属性、写函数操作对象。
第二课时:__init__、self 和多个对象
时长:60 分钟
学习目标
- 写一个带
__init__方法的类 - 理解
self指的是什么 - 创建多个对象,每个对象有不同的属性值
饼干模具演示(10分钟)
在 Python 中:
class Pokemon: # ← 模具 pikachu = Pokemon() # ← 一块饼干 charmander = Pokemon() # ← 另一块饼干
上节课我们在创建对象之后一个一个附加属性。那样既麻烦又容易出错。__init__ 就是自动运行的"初始化配方"——每次创建新对象时都会执行。
认识 __init__ 和 self(25分钟)
class Pokemon: def __init__(self, name, hp, damage): self.name = name # 把 name 存到这个对象上 self.hp = hp # 把 hp 存到这个对象上 self.damage = damage # 把 damage 存到这个对象上 # 现在创建一只宝可梦只需一行简洁的代码: pikachu = Pokemon('Pikachu', 100, 20) charmander = Pokemon('Charmander', 90, 18) squirtle = Pokemon('Squirtle', 95, 15) print(pikachu.name) # Pikachu print(charmander.hp) # 90 print(squirtle.damage) # 15
常见错误——千万别这样写!
# 错误——忘记写 self. 在属性名前面 class Pokemon: def __init__(self, name, hp): name = name # 错!这只是在创建一个局部变量! hp = hp # __init__ 结束后它就消失了。 # 正确写法 class Pokemon: def __init__(self, name, hp): self.name = name # 存到对象上 self.hp = hp # 存到对象上
练习——组建你的队伍(20分钟)
创建3只宝可梦(或者宠物、Minecraft 生物——你选)。打印每个对象的一个属性来检查是否正确。
出口票
在纸上写出下面这个类的 __init__ 方法:
class Spaceship: # 它应该存储:name、fuel、speed def __init__(self, ???): ...
展望未来
本周你学会了用类作为蓝图创建对象,用点号设置和读取属性,还学会了用 __init__ 方法让创建对象变得像调用函数一样简洁。下周我们将学习如何给类添加方法——让对象不仅能存储数据,还能执行动作。