⚠️⚠️⚠️本章后半部分难度激增,请一定认真学习⚠️⚠️⚠️
⚠️⚠️⚠️本章后半部分难度激增,请一定认真学习⚠️⚠️⚠️
⚠️⚠️⚠️本章后半部分难度激增,请一定认真学习⚠️⚠️⚠️
上篇回顾:
上篇我们帮天下第一武道会的选手登记了信息,编写了 hit()
、defend()
函数,并结合 while
循环实现了决斗过程。然而也遇到了两大问题:一是如何设计出一套模板,优化登记选手信息过程;二是如何设计一套 能体现出动作发起方与承受方 的函数。
想解决这些问题,需要我们转变思维方式,用 面向对象 方式分析问题。所谓 面向对象编程,就是将编程视作 对象 的集合,从 对象与对象间的交互 角度出发思考问题。
与此同时,我们还分析出了 选手类 具有的特征与行为:
从整体上分析出决斗过程中对象与对象间有什么样的交互后,我们就可以正式开始编写代码啦。下面让我们一起来定义选手类吧!
类与对象
在 Python 中,我们用关键字 class
来定义类。比如我们编写 class Player:
,就定义好了一个名为 Player
的类:
class Player:pass
代码第 1 行的类名 Player
后有一个冒号 :
,表示后面的语句都是类的具体内容。所有归属于类管辖的语句,都要增加一层缩进。这和我们之前学习的分支、循环、函数结构是一样的道理。
可以看到,现在 Player
类中只有一条语句 pass
。这是 Python 中的特殊语句,没有实际含义,Python 在执行到它时也什么都不会做。不过它能够保证结构的完整性。例如,我们只写了一行 while True:
,Python 会警告我们循环体为空;而如果我们在循环体位置添加一行 pass
,Python 就不会报错了:
# 循环体为空,Python 会报错
while True:# 虽然循环体内的 pass 没有实际含义
# 但它补全了 while 循环结构,因此 Python 不会报错
while True:pass
类中可以包含若干 属性 和 方法。属性 用于描述对象的特征,方法 用来定义对象的行为。比如说,虽然信息表中没有包含这些信息,但我们知道,选手们都有两只胳膊、两条腿、一双眼睛。胳膊、腿、眼睛的数量,就是 Player
类的特征,我们在代码中可以这样表达:
# 选手类
class Player:arm_num = 2 # 两只胳膊leg_num = 2 # 两条腿eye_num = 2 # 一双眼睛
啊哈,原来类的 属性 就是定义在类中的 变量。
定义好类后运行代码,却发现结果区域里什么也没有。这是怎么一回事呢?
这是因为,我们所定义的 类 只是一套模板。就像在生产零件时不能只有图纸,还要交给机器加工出一个个看得见摸得着的实物;我们有了模板后,也要创建出 实例(instance)才能实现对象与对象间的交互。
而创建类实例的过程,就叫做 类的实例化
类的实例化
说起来很玄乎,实际上,它对应的代码十分简单:
# 选手类
class Player:arm_num = 2 # 两只胳膊leg_num = 2 # 两条腿eye_num = 2 # 一双眼睛# 实例化 Player 类,生成一个新的实例对象
kakarot = Player()
代码第 8 行的含义是实例化 Player
类,并将生成的新的实例对象赋值给变量 kakarot
。此时的变量 kakarot
就是 Player
类实例化出来的实例 对象(object)。
是的,我们创建的变量也是 对象!
拓展:实例 和 对象 是两个不同的词。当我们强调 类与对象之间的关系 时,会说“
kakarot
是Player
的实例”;当我们 单独提起某一具体实例时,通常会说“对于kakarot
对象……”。
Python 奉行 万物皆对象 理念,你看到的“变量”,其实是一个个由基础的 数据类型类 实例化而来的实例对象。我们使用 type()
函数查看变量的数据类型,实际上就是在查看它所归属的 类。
同样的道理,我们也可以用 type()
函数查看变量 kakarot
的类型。
比如:
# 选手类
class Player:arm_num = 2 # 两只胳膊leg_num = 2 # 两条腿eye_num = 2 # 一双眼睛# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot
kakarot = Player()
# 打印 kakarot 变量的数据类型
print(type(kakarot))
# 输出结果为:
# <class '__main__.Player'>
这里的 __main__
就是我们之前学习过的 程序入口,即我们刚刚运行的 main.py 文件。Player
是我们在文件中定义的类,__main__
和 Player
中间的 .
运算符,表明了它们之间的从属关系,即变量 kakarot
属于我们在当前文件所定义的 Player
类型。
我们不是第一次见到 .
运算符啦。开动脑筋想一想,我们之前还在哪里遇到了它呢?
😉 没错!我们想调用列表、字符串或字典的特殊方法时,变量名与方法名之间要用 .
连接;使用某个模块中的变量或函数时,模块名和变量名/函数名之间,也要用 .
连接。
# 调用方法时,变量名和方法名之间用 . 连接
months = ['一月', '二月']
months.append('三月')# 使用模块中某个变量或函数时,也要用 . 连接
import random
number = random.randint(1, 100)
放到类中也是一样的道理。当我们想要访问 对象的属性 时,需要用 .
运算符连接对象名和属性名,就像这样:
# 选手类
class Player:arm_num = 2 # 两只胳膊leg_num = 2 # 两条腿eye_num = 2 # 一双眼睛# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot
kakarot = Player()
print('卡卡罗特有 {} 只胳膊'.format(kakarot.arm_num))
# 输出:卡卡罗特有 2 只胳膊
注意看代码第 8 行,我们通过 kakarot.arm_num
访问到了 kakarot
的 arm_num
属性。这种用 .
运算符访问数据的方式,更贴合我们的认知方式。因此用面向对象思想编写的代码,也更容易阅读。
属性定义与修改
看着我们创建好的 Player
类,天津饭(Tien Shinhan)选手提出异议:“我是三目人与地球人后裔,天生三目,怎么能用‘一双眼睛’概括我的特征呢?不行,你得给我把我的第三只眼加上!”
面对这样的 特例,我们可以为天津饭选手单独修改 eye_num
属性:
# 类的定义与实例化代码省略
# 实例化 Player 类,生成一个新的实例对象,赋值给变量 tien
tien = Player()
# 将他的眼睛数量修改为三只
tien.eye_num = 3print('天津饭选手有 {} 只眼睛'.format(tien.eye_num))
# 输出:天津饭选手有 3 只眼睛
有的同学可能会好奇:既然对象是由类实例化而来,那我们改变对象的属性后,其它由同一类实例化而来的对象属性,是否也跟着发生了变化呢?
编程练习
请按照注释提示,将天津饭的眼睛数量修改为 3 只;接着创建一个新的 Player
类对象,看看他有几只眼睛。
# 选手类
class Player:arm_num = 2 # 两只胳膊leg_num = 2 # 两条腿eye_num = 2 # 一双眼睛# 实例化 Player 类,生成一个新的实例对象,赋值给变量 tien
tien = Player()
# 将他的眼睛数量修改为三只# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot# 输出他的眼睛数量
优化后的代码为:
# 选手类
class Player:arm_num = 2 # 两只胳膊leg_num = 2 # 两条腿eye_num = 2 # 一双眼睛# 实例化 Player 类,生成一个新的实例对象,赋值给变量 tien
tien = Player()
# 将他的眼睛数量修改为三只
tien.eye_num = 3
print('天津饭的眼睛数量为{}只'.format(tien.eye_num))
# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot
kakarot = Player()
# 输出他的眼睛数量
print('卡卡罗特的眼睛数量为{}只'.format(kakarot.eye_num))
# 输出结果为:
# 天津饭的眼睛数量为3只
# 卡卡罗特的眼睛数量为2只
看来我们躲过了跟天津饭一样生出第三只眼睛的命运。不过这背后是怎么一回事呢?大家都是由 Player
类实例化而来的对象,为什么彼此之间不会干扰呢?
前面我们提到过,类是抽象的模板,对象可以看作生产出的一个个零件。零件与零件是 相互独立 的,我们加工 tien
“零件”,自然不会影响到 kakarot
“零件”,更不会对模板本身,即 Player
类本身产生影响。
了解了如何为类添加属性,我们再来看看如何为类添加 方法。
方法定义与调用
类的 方法 用来描述对象的 行为。例如,每位选手都需要登记信息,那么我们可以定义一个 sign_up()
方法,帮指定选手登记姓名、生命值和攻击力信息。
拓展:sign up 意为注册、登记;与之对应的,sign in 表示登录、签到。
# 选手类
class Player:# 帮选手登记信息def sign_up(self, name, HP, ATK): # 这里的 self 指的是需要登记信息的选手self.name = name # 为选手登记姓名self.HP = HP # 为选手登记生命值self.ATK = ATK # 为选手登记攻击力print('已成功登记信息')print('+ {}\tHP: {}\tATK: {}'.format(name, HP, ATK))
啊哈,原来所谓 方法,就是定义在类中的 函数。调用方法的方式和访问、修改对象属性类似,依然通过 .
运算符完成:
kakarot = Player()
Player.sign_up(kakarot, '卡卡罗特', 100 ,25)
# 输出:
# 已成功登记信息
# + 卡卡罗特 HP: 100 ATK: 25
上面代码第 1 行,我们实例化了 Player
类,并将新生成的实例对象赋值给了 kakarot
。接着在第 2 行,Player
类调用自己的 sign_up()
方法,传入了 kakarot
等参数,为卡卡罗特登记信息。
这是比较符合 面向过程编程 思维方式的编写形式。实际上,有了 类与对象 的加持,我们可以写成这样:
kakarot = Player()
kakarot.sign_up('卡卡罗特', 100 ,25)
# 输出:
# 已成功登记信息
# + 卡卡罗特 HP: 100 ATK: 25
注意看第 2 行代码,此时是 kakarot
实例对象在调用 Player()
类的 sign_up()
方法。它与之前我们编写的 Player.sign_up(kakarot, '卡卡罗特', 100 ,25)
是等价的:
self
参数含义
还真说对了。当 实例对象调用方法 时,Python 会 强制性 地将 实例对象本身 传递给类方法的 第一个参数。
因此,虽然我们在调用方法时写的是 kakarot.sign_up('卡卡罗特', 100 ,25)
,实际上对 Python 而言,它运行的是 Player.sign_up(kakarot, '卡卡罗特', 100 ,25)
。
这样一来,一是简化了代码,二是更能看清楚是什么对象产生了什么样的行为。就像老师在上一关末尾为你展示的代码结构一样:
kakarot = Player('卡卡罗特', 100, 25)
piccolo = Player('比克大魔王', 150, 15)kakarot.hit(piccolo)
即使我们不清楚 hit()
方法内部细节,但我们一眼就能看出 kakarot.hit(piccolo)
的含义是 卡卡罗特打了比克大魔王一拳。这其中体现了 类 的 封装 特征。
除了 封装,类还有 继承 与 多态 两大特征,这些内容我们会在下一章深入了解。
当对象调用类方法时,Python 会自动地把对象自身传递给 self
参数,因此我们只需要传入 self
后面的参数即可。A 选项多传递了 kuririn
对象本身,错误;D 选项是 kakarot
在调用方法,因此会为 kakarot
登记信息,错误。
而如果是类调用方法,则需要在参数列表中写明,究竟是什么对象在发生这一行为,因此要写成 Player.sign_up(kuririn, '克林', 85, 12)
,B 选项错误。
敲黑板划重点啦。Python 是 强制性 地将 实例对象本身 传递给类方法的 第一个参数,而不是强制性传递给名为 self
的参数。假如我们在定义 sign_up()
方法时,人为地把 self
参数放到参数列表后面位置:
# 选手类
class Player:# 人为地把 self 参数放到参数列表后面位置def sign_up(name, HP, ATK, self):self.name = name # 为选手登记姓名self.HP = HP # 为选手登记生命值self.ATK = ATK # 为选手登记攻击力kakarot = Player()
kakarot.sign_up('卡卡罗特', 100 ,25)
当 Python 执行到最后一行时,它依然会把 kakarot
传递给参数列表中第一个参数,也就是 name
参数,接着把 '卡卡罗特'
传递给 HP
参数……一切都乱套啦!
所以我们在定义类方法时,一定要把 self
参数放在参数列表第一项 哦。
明白如何编写方法后,我们来尝试将上一关编写的 hit()
函数改写成 Player
类的 hit()
方法吧。
通过之前分析我们知道,攻击 行为是由一个 Player
类对象发出的,会打在另一个 Player
对象身上。因此 hit()
方法需要携带两个参数,第一个参数自然是表示自身的 self
;第二个是他攻击的对象 target
:
# 选手类
class Player:# 帮选手登记信息def sign_up(self, name, HP, ATK):pass# 发动攻击def hit(self, target):pass
这一行为具体是怎么一回事呢?这中间有两个环节,一是攻击者放狠话,二是被攻击的对象调用自己的 防御 能力,抵御受到的伤害。我们将 hit()
方法补充完成,再把 防御 行为抽象成 defend()
方法,此时的类结构是这样的:
# 选手类
class Player:# 帮选手登记信息def sign_up(self, name, HP, ATK):pass# 发动攻击def hit(self, target):print('>> 【{}】向【{}】发动攻击,\n'.format(self.name, target.name))target.defend(self.ATK)# 防御攻击def defend(self, damage):pass
接下来,我们只要再补充完成 defend()
方法,就能完成整个 Player
类的设计了。这一步就交给你来完成吧。
编程练习
请按照注释提示,将 defend()
函数改写为 Player
类的方法,并在程序最后一行让卡卡罗特向比克大魔王发动一次攻击。
代码提示
- 类方法归属类管辖,需要添加一层缩进;
defend()
方法除self
外还应接受一个参数,表示受到了多少伤害。
注意事项
访问、修改实例对象的属性时,需要用 .
运算符。
操作提示:在代码编辑区域选中若干行,按下键盘上的
tab
键,即可快速为这些行添加一层缩进;若选中若干行后按下shift + tab
键,则能为这些行减少一层缩进。不妨自己试试吧~
在此代码中进行优化:
from random import randint# 选手类
class Player:# 帮选手登记信息def sign_up(self, name, HP, ATK):self.name = name # 为选手登记姓名self.HP = HP # 为选手登记生命值self.ATK = ATK # 为选手登记攻击力print('已成功登记信息')print('+ {}\tHP: {}\tATK: {}\n'.format(name, HP, ATK))# 发动攻击def hit(self, target):print('>> 【{}】向【{}】发动攻击,\n'.format(self.name, target.name))target.defend(self.ATK)# 请将下面 defend() 函数改写为 Player 类的方法
def defend(defender, damage):# 若生成的随机数小于等于 20,则闪避成功if randint(0, 100) <= 20:print('>> 【{}】完美躲避了攻击!\n'.format(defender['name']))# 否则扣除对应生命值else:defender['HP'] = defender['HP'] - damageprint('>> 【{}】受到 {} 点伤害...\n'.format(defender['name'], damage))# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot
kakarot = Player()
# 为卡卡罗特登记信息
kakarot.sign_up('卡卡罗特', 100 ,25)# 实例化 Player 类,生成一个新的实例对象,赋值给变量 piccolo
piccolo = Player()
# 为比克大魔王登记信息
piccolo.sign_up('比克大魔王', 150, 15)# 让卡卡罗特向比克大魔王发起攻击
优化后的代码为:
from random import randint# 选手类
class Player:# 帮选手登记信息def sign_up(self, name, HP, ATK):self.name = name # 为选手登记姓名self.HP = HP # 为选手登记生命值self.ATK = ATK # 为选手登记攻击力print('已成功登记信息')print('+ {}\tHP: {}\tATK: {}\n'.format(name, HP, ATK))# 发动攻击def hit(self, target):print('>> 【{}】向【{}】发动攻击,\n'.format(self.name, target.name))target.defend(self.ATK)# 请将下面 defend() 函数改写为 Player 类的方法def defend(defender, damage):# 若生成的随机数小于等于 20,则闪避成功if randint(0, 100) <= 20:print('>> 【{}】完美躲避了攻击!\n'.format(defender.name))# 否则扣除对应生命值else:print(defender.name)defender.HP = defender.HP - damageprint('>> 【{}】受到 {} 点伤害...\n'.format(defender.name, damage))# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot
kakarot = Player()
# 为卡卡罗特登记信息
kakarot.sign_up('卡卡罗特', 100 ,25)# 实例化 Player 类,生成一个新的实例对象,赋值给变量 piccolo
piccolo = Player()
# 为比克大魔王登记信息
piccolo.sign_up('比克大魔王', 150, 15)# 让卡卡罗特向比克大魔王发起攻击
Player.hit(kakarot, piccolo)
# 输出结果为:
# 已成功登记信息
# + 卡卡罗特 HP: 100 ATK: 25
# 已成功登记信息
# + 比克大魔王 HP: 150 ATK: 15
# >> 【卡卡罗特】向【比克大魔王】发动攻击,
# >> 【比克大魔王】完美躲避了攻击!
不知道你发现没有,虽然 sign_up()
和 hit()
、defend()
都是 Player
类的方法,但它们的使用频率和时机是不一样的:sign_up()
方法只有创建完实例对象后使用了一次,并且,如果不事先为选手登记信息,后续的攻击、防御过程都是没有意义的。🤔️ 那我们可不可以把这种 一实例化就必须要做的行为 与类实例化过程绑定在一起呢?
当然可以啦~我们用 __init__()
方法实现这一点。
__init__()
方法
__init__()
方法和程序入口 __main__
一样,都以两个下划线 __
开头、两个下划线结束。这意味着 __init__
也是 Python 中内置的一个名称,有着特殊的功能。
init 的全称是 initialize(初始化),会在我们实例化新的对象时 自动调用。
比如说我们希望在创建 Player
类对象时,自动地为这名新选手登记信息,那么可以把原来 sign_up()
方法中的内容挪到 __init__()
方法中:
# 选手类
class Player:# 每当创建新对象,都自动为他登记信息def __init__(self, name, HP, ATK):self.name = name # 为选手登记姓名self.HP = HP # 为选手登记生命值self.ATK = ATK # 为选手登记攻击力print('已成功登记信息')print('+ {}\tHP: {}\tATK: {}\n'.format(name, HP, ATK))
此时我们再创建 Player
类的对象,需要在 Player()
的圆括号中传入姓名、生命值、攻击力三样信息,就像这样:
# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot
kakarot = Player('卡卡罗特', 100, 25)
# 输出:
# 已成功登记信息
# + 卡卡罗特 HP: 100 ATK: 25
Python 执行到 kakarot = Player('卡卡罗特', 100, 25)
时,实际上完成了两个步骤:
- 实例化
Player
类,生成一个新的实例,将其赋值给kakarot
;kakarot
自动地调用__init__()
方法,为自己的name
等属性赋值。
注意,一旦我们在类中编写了 __init__()
方法,那么在创建实例时 必须要传入对应的参数。假如我们没有传入对应参数,那么 Python 会报错喔:
# 未传入参数
kakarot = Player()
# 输出:
# TypeError: __init__() missing 3 required arguments: 'name', 'HP', 'ATK'
# 类型错误:__init__() 需要 3 个参数:'name','HP' 和 'ATK'
单选题我们将 sign_up()
方法改为 __init__()
方法后,以下哪项可以为 克林 选手(kuririn
对象)登记信息呢?
克林信息:生命值 85,攻击力 12。
A:
kuririn = Player.__init__(kuririn, '克林', 85, 12)
B:
kuririn = Player('克林', 85, 12)
对于 A 选项来说,Python 会先执行 Player.__init__(kuririn, '克林', 85, 12)
,而此时我们还没有定义 kuririn
变量,自然无法将它作为参数传递给 __init__()
方法,所以 A 选项错误。
对于 B 选项来说,Python 会先执行 Player('克林', 85, 12)
。这其中发生了两个步骤,第一个步骤是实例化 Player
类,生成实例对象,将其赋值给 kuririn
;第二步是 kuririn
自动地调用 __init__()
方法,为 name
等属性赋值。所以 B 选项是正确的。
如果还不清楚的话,可以再反复读几遍,或者自己编写代码做做实验哦。
咳咳,编写了 __init__()
方法后我们再实例化 Player
类时,看起来很像在调用一个名为 Player
的函数。为避免引发歧义,凸显出类是一个整体性的概念,Python 官方建议为类取名时 首字母大写,以便和函数名区分开来。如果所要描述的类不能用单个单词表达,则每个单词的首字母都需要大写,比如 FilmSelector
。同学们在自己编写类时也要注意这一点哦。
好了,本章学习就到这里啦,让我们用一张图总结一下类与对象的语法知识吧:
课后练习:卡卡罗特VS比克大魔王
请你根据注释中提示信息,结合本关所学知识,用 面向对象编程 方法编写完成 Player
类,并让卡卡罗特和比克大魔王展开决斗吧~
卡卡罗特(kakarot)
- 姓名(name):卡卡罗特
- 生命值(HP):100
- 攻击力(ATK,attack):25
比克大魔王(piccolo)
- 姓名(name):比克大魔王
- 生命值(HP):150
- 攻击力(ATK,attack):20
决斗说明
- 决斗采取 回合制,由卡卡罗特先发动攻击;
- 防御时有 20% 几率防御成功,完全闪避攻击,免受伤害。
请在下方代码中,实现对应功能:
from random import randint# 选手类
class Player:# 每当创建新对象,都自动为他登记信息def __init__(self, name, HP, ATK):self.name = name # 为选手登记姓名self.HP = HP # 为选手登记生命值self.ATK = ATK # 为选手登记攻击力print('已成功登记信息')self.show_info()# 展示信息def show_info(self):print('+ {}\tHP: {}\tATK: {}\n'.format(self.name, self.HP, self.ATK))# 发动攻击# 防御攻击# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot# 实例化 Player 类,生成一个新的实例对象,赋值给变量 piccolo# 展开决斗
while True:# 每回合开始,由卡卡罗特先发动攻击# 判断此时决斗是否分出胜负# 若未分出胜负,则攻防交换,由比克大魔王发动攻击# 判断此时决斗是否分出胜负# 每回合结束,打印出两人当前信息
实现后的代码为:
from random import randint# 选手类
class Player:# 每当创建新对象,都自动为他登记信息def __init__(self, name, HP, ATK):self.name = name # 为选手登记姓名self.HP = HP # 为选手登记生命值self.ATK = ATK # 为选手登记攻击力print('已成功登记信息')self.show_info()# 展示信息def show_info(self):print('+ {}\tHP: {}\tATK: {}\n'.format(self.name, self.HP, self.ATK))# 发动攻击def hit(attack, defender):print('-' * 6,attack.name,'发起攻击','-' * 6)defender.dfAttack(attack.ATK)# 防御攻击def dfAttack(defender, atk):if randint(1,100) <= 20:# 防御成功print(defender.name,'防御成功')else:# 防御失败defender.HP -= atkprint(defender.name,'防御失败,气血-',atk)Player.show_info(defender)
# 实例化 Player 类,生成一个新的实例对象,赋值给变量 kakarot
kakarot = Player('卡卡罗特', 100, 25)# 实例化 Player 类,生成一个新的实例对象,赋值给变量 piccolo
piccolo = Player('比克大魔王', 150, 20)# 展开决斗
while True:# 每回合开始,由卡卡罗特先发动攻击Player.hit(kakarot, piccolo)# 判断此时决斗是否分出胜负if piccolo.HP <= 0:print(kakarot.name,'胜出')break# 若未分出胜负,则攻防交换,由比克大魔王发动攻击else:Player.hit(piccolo, kakarot)if kakarot.HP <= 0:# 判断此时决斗是否分出胜负print(piccolo.name,'胜出')break# 每回合结束,打印出两人当前信息# Player.show_info(kakarot)# Player.show_info(piccolo)print('-' * 32 + '\n')
课后练习:空调说明书
空调说明书
夏天怎么能没有空调呢!小贝舒舒服服地吹着凉风,她可太喜欢家里的空调了。
下面是小贝家卧室空调的说明书:
品牌:四季
额定电压:220V
额定制冷功率:1000W
额定制热功率:1350W
AC 是空调 (air conditioner) 的英文缩写,请你补全代码中标有 ???
的地方,为 AC
类添加一个初始化方法,让 intro
方法执行时,能够打印出上面的空调说明书。
# brand 品牌,voltage 电压,cold 制冷,hot 制热
class AC:def __init__(???):???def intro(self):print('''品牌:{}
额定电压:{}
额定制冷功率:{}
额定制热功率:{}'''.format(???))air_bedroom = AC(???)
air_bedroom.intro()
优化后可得:
# brand 品牌,voltage 电压,cold 制冷,hot 制热
class AC:def __init__(self,brand, voltage, cold, hot):self.brand = brandself.voltage = voltageself.cold = coldself.hot = hotdef intro(self):print('''品牌:{}
额定电压:{}
额定制冷功率:{}
额定制热功率:{}'''.format(self.brand, self.voltage, self.cold, self.hot))air_bedroom = AC('四季','220V','1000W','1350W')
air_bedroom.intro()# 输出结果为:
# 品牌:四季
# 额定电压:220V
# 额定制冷功率:1000W
# 额定制热功率:1350W