一些关于自己学习Python的经历的内容,遇到的问题和思考等,方便以后查询和复习。
声明:本人学习是在扇贝编程通过网络学习的,相关的知识、案例来源于扇贝编程。如果使用请说明来源。
第26关:类和面向对象的编程
练习:中奖号码
模板代码是彩票抽奖机的代码,使用的是 面向过程 的思维方式写的,思考一下用 面向对象 的思维如何改写?写完记得查看答案对比一下哦~
#from random import randint
#times = 6
#lottery = []
#for i in range(0, times):
# number = randint(0, 99)
# lottery.append(number)
#print('本期彩票中奖号码为:%s' % lottery)
#面向对象
from random import randint
# 由于需要随机产生的数字,所以导入随机生成函数是必须的。
class Lottery: #定义一个类,这个我想到了,但是忘记了类的名称首字母要大写的要求了
def __init__(self, times): #定义一个初始化,参数处理self,还有一个是抽奖次数。
self.times = times #设置初始化的特征
self.lottery = [] # 设置一个空列表,因为是初始化特征,所以前面加个self
def draw_lottery(self): # 定义一个抽奖的方法/行为
for i in range(0, self.times): #用for循环,来个遍历,只是范围末端是一个参数
number = randint(0, 99)
self.lottery.append(number)
def print_lottery(self): # 定义一个打印结果的方法/行为
print('本期彩票中奖号码为:%s' % self.lottery)
lottery = Lottery(6) #实例化,同时对times赋值
lottery.draw_lottery() # 调用实例化后的抽奖方法
lottery.print_lottery() #调用打印抽奖结果的方法
说实话,我是没有弄出来,通过前面的例子,我知道面向对象的变成思路是三个部分:第一个是定义一个类,第二个是实例化,第三个是调用。其中后两个比较简单,第一个是比较难的。我看了前面那个关于学生姓名和成绩的例子,但是我还是没有思路如何做。
原因是前面学生成绩的例子是个静态的,就是资料时固定的,不变的。而这个是动态的,号码是没有的。所以如何用定义类的方式来解决呢。我没有思路,没有办法。只好看了答案。
发现:三个步骤是找到了,第一个步骤是重点,而且第一个步骤中就是抽即将的过程,所以这个步骤是对象中包含过程的,把整个抽奖过程作为一个对象。
练习:kakarotto
赛亚人会在月圆之夜因为月亮发射出来的布尔兹光,进化成巨猿。变身后是常态的 10 倍左右,并且会失去理智。
假设现在是月圆之夜,请你在类实例化时自动调用 transform() 方法变身,并添加 __str__() 方法返回 我是来自xxx的xxx,代码最终运行结果应如下:
变身巨猿
我是来自贝吉塔行星的卡卡罗特
要求:
给 Saiyan 类添加初始化方法,初始化方法接受 name 参数用于初始化 self.name,并调用 transform() 方法;
给 Saiyan 类添加 __str__() 方法,使打印 Saiyan 类的实例 kakarotto 时结果为 我是来自贝吉塔行星的卡卡罗特。
class Saiyan:
def __init__(self, name):
self.name = name
self.born_place = '贝吉塔行星'
self.character = '天生好战性格暴躁'
#这两个没有赋值,还是特征,答案是放在外面的,我也考虑了这一点,放在初始化外面更合理。放在这里前面加self,放在初始化外面,前面则不用加self
这两个应该也是赋值了,只不过似乎固定的值,而不是一个变量。
def transform(self):
print('变身巨猿')
def __str__(self):
return('我是来自%s的%s'%(self.born_place, self.name))
kakarotto = Saiyan('卡卡罗特')
kakarotto.transform() #答案是在初始化中调用这个方法的,所以最后就没有了,符合题意
print(kakarotto)
变身巨猿
我是来自贝吉塔行星的卡卡罗特
根据答案更改之后的结果:
class Saiyan:
born_place = '贝吉塔行星'
character = '天生好战性格暴躁' #不在初始化中,所以前面不能再加self
def __init__(self, name):
self.name = name
self.transform() #可以在初始化中赋值,可以调用方法
def __str__(self):
return('我是来自%s的%s'%(self.born_place, self.name))
def transform(self):
print('变身巨猿')
kakarotto = Saiyan('卡卡罗特')
#kakarotto.transform()
print(kakarotto)
也可以这样修改:
class Saiyan:
def __init__(self, name, born_place, character): 四个参数
self.name = name
self.transform()
self.born_place = born_place
self.character = character 所有参数都进行了初始化
def __str__(self):
return('我是来自%s的%s,%s'%(self.born_place, self.name, self.character))
def transform(self):
print('变身巨猿')
kakarotto = Saiyan('李建升','地球','天生爱吃肉')
#kakarotto.transform()
print(kakarotto)
变身巨猿
我是来自地球的李建升,天生爱吃肉
kakarotto = Saiyan('卡卡罗特','贝吉塔行星','天生天生好战性格暴躁')
#kakarotto.transform()
print(kakarotto)
变身巨猿
我是来自贝吉塔行星的卡卡罗特,天生天生好战性格暴躁
练习:三头六臂的哪吒
哪吒会 三头六臂 的法术,我们来给模板代码中的类补充一个初始化方法,使其打印出 我叫哪吒,我有 3 头 6 臂。
class Human:
# 在这里补充初始化方法
def __init__(self, name, heads, arms):
self.name = name
self.heads = heads
self.arms = arms
def intro(self):
print('我叫{},我有{}头{}臂'.format(self.name, self.heads, self.arms))
nezha = Human('哪吒', 3, 6)
nezha.intro()
练习:三头六臂的哪吒 另一个答案:
我们通过 intro() 方法打印出了 我叫哪吒,我有 3 头 6 臂。接下来我们去掉 intro() 方法,使用神奇方法 __str__() 来打印 我叫哪吒,我有 3 头 6 臂。
class Human:
def __init__(self, name, heads, arms):
self.name = name
self.heads = heads
self.arms = arms
def __str__(self):
return '我叫{},我有{}头{}臂'.format(self.name, self.heads, self.arms)
#def intro(self):
# print('我叫{},我有{}头{}臂'.format(self.name, self.heads, self.arms))
nezha = Human('哪吒', 3, 6)
#nezha.intro()
print(nezha)
学习笔记:
初始化方法
在 Python 的类中,有一种特殊的方法——初始化方法。它的格式是 def __init__(self):,方法名由 init(initialize 的缩写,初始化的意思)加左右两边的 双下划线 组成。
注意:初始化方法的 init 前后有 两个 下划线。
初始化方法的特殊之处是:每当进行类的实例化时,初始化方法会自动被执行。
只是创建了实例,并没有调用 __init__ 方法,它自己就自动执行了。利用这个特性,我们通常会在 初始化方法 里完成类属性初始值的设置。
除了进行固定的初始值设置,初始化方法 可以接收其他参数,进行自定义的属性初始值设置。
class Human:
def __init__(self, name, arms, legs, hair):
# self.不能丢
self.name = name
self.arms = arms
self.legs = legs
self.hair = hair
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
def intro(self):
print('我叫{},我有{}'.format(self.name, self.hair))
xiaobei = Human('小贝', 2, 2, '粉红色的头发')
print(xiaobei.name)
# 输出:小贝
xiaobei.intro()
# 输出:我叫小贝,我有粉红色的头发
给 初始化方法 额外添加了 4 个参数,因此在实例化的时候要传入对应的值。Human('小贝', 2, 2, '粉红色的头发') 这里的 '小贝' 赋值给 self.name,两个 2 分别赋值给 self.arms 和 self.legs,'粉红色的头发' 赋值给 self.hair。
当实例化完成之后,初始化方法会自动执行,这样我们就完成了自定义的属性初始值设置。然后我们可以通过 实例名.属性名 在类外访问或 self.属性名 在类的方法中访问了。
神奇方法
像 __init__() 这样的方法在 Python 的类中被称为 神奇方法(或魔术方法),它们的特征是被 双下划线 所包裹。这一节中我们再介绍一个神奇方法——__str__()。
class Human:
arms = 2
legs = 2
hair = '各种颜色的头发'
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
def intro(self):
print('人类有%d条胳膊%d条腿' % (self.arms, self.legs))
# 类的实例化
human = Human()
human.intro()
# 输出:人类有2条胳膊2条腿
class Human:
arms = 2
legs = 2
hair = '各种颜色的头发'
def __str__(self):
return '人类有%d条胳膊%d条腿' % (self.arms, self.legs)
def walk(self):
print('直立行走')
def speak(self):
print('说着各式各样的语言')
human = Human()
print(human)
# 输出:人类有2条胳膊2条腿
可以看到,有了 __str__() 方法,直接打印实例的结果为 __str__() 方法的返回值。因此,我们可以使用 __str__() 方法来描述一个类。
面向对象与面向过程
与 面向对象 相对应的是 面向过程,我们之前写代码都用的是 面向过程 的思维方式。也就是把一个问题拆分成一个个步骤,然后用函数实现各个步骤,依次调用解决问题。
而 面向对象 的思维方式是:把一个问题拆分成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为和特征(方法和属性)
可以看到,面向过程 是以动作(函数)为主体,对象(这个例子里是学生)作为参数传递给函数。而 面向对象 是以对象为主体,动作和特征分别是对象的方法和属性。用代码来描述就是,面向过程:动作(对象);面向对象:对象.动作()。
使用 面向对象 的思维方式的好处是:程序的可读性、可拓展性、可维护性高。但并不是说 面向过程 就一无是处了,二者相辅相成,并不是对立的,我们要根据实际情况选择合适的编程思维方式。