1、类与对象
先明确“类”和“对象”的关系:【类】是【对象】的模板。
我们可以以【类】为模板,多次复制,生成多个【实例对象】。
比如我们可以类为模板,复制出很多【类】,生成多个【实例对象】。
什么叫实例对象呢?可以想象一下,【类】就像工厂的模具,以它为模板,造出来的成千上万的产品,才是被我们消费、购买、使用,真正融入我们生活的东西。这些产品,在Python中就叫【实例对象】。
往深了说,Python中,万事万物都可以是对象,【类】这种模板层级的本身也是【对象】,但并不是【实例对象】。
从模具变成产品,也就是从【类】变成【实例对象】的过程,就叫做【实例化】。
2、类的实例化
首先要注意实力化的基本格式,当类需要被实例化
后使用,与直接使用
的格式是不同的。
直接使用
实例化后使用
实例化后再使用的格式:
①、空着的,意思是这里不再需要@classmethod的声明;
②、中,把cls替换成了self。
③、实例化后再使用的格式,需要先赋值然后再调用。
④、我们需要用实例名 = 类()的方式(实例名其实就是任取一个变量名),为类创建一个实例,然后再使用实例名.函数()的方式调用对应的方法。
另外提一下,cls代表“类”的意思,self代表“实例”的意思,这样写是编码规范(程序员们的共识),但不是强制要求。理论上只要写个变量名占位,写什么都行,比如把self写成bbb也可以。
当类被实例化以后,就不能再以类的形式运行了。
2.1、实例属性和类属性
类和实例的关系,就像母体和复制品的关系一样。当一个类实例化为多个实例后,实例将原封不动的获得类属性,也就是实例属性和类属性完全相等。
我们可以修改类属性,这会导致所有实例属性变化(因为类是模板)。
我们也可以修改实例属性,但这不会影响到其他实例,也不会影响到类。因为每个实例都是独立的个体。
对于新增也是一样的道理,在类中新增会影响实例,但在实例中新增并不会影响类。值得注意的是,当实例和类同时修改变量时候,因为每一个实例都是独立的个体,所以下面这段代码的运行结果,是10和1
class 类:
变量 = 100 #类属性
实例1 = 类() # 实例化
实例2 = 类() # 实例化
实例1.变量 = 10
类.变量 = 1
print(实例1.变量)
print(实例2.变量)
每个实例都是独立的个体。其中实例1.变量 = 10相当于修改了实例属性,所以类.变量 = 1不能影响到它,只能影响到实例2.变量。最终实例1.变量的值是10,实例2.变量的值是1。
2.2、实例方法和类方法
“重写类方法”分成两个步骤:第一个步骤是在类的外部写一个函数,第二个步骤是把这个新函数的名字赋值给类.原始函数。
我们可以通过重写类方法,让实例方法发生变化,但我们不能重写实例方法,模板给的技能不是说换就能换的。
2.3、初始化函数
初始化函数的意思是,当你创建一个实例的时候,这个函数就会被调用。
class 类():
def __init__(self):
print('实例化成功!')
实例 = 类()
上面的代码在执行实例 = 类()的语句时,就自动调用了init(self)函数。
初始化函数的写法是固定的格式:中间是“init”,这个单词的中文意思是“初始化”,然后前后都要有【两个下划线】,然后init()的括号中,第一个参数一定要写上self,不然会报错。
同时,这个初始化函数照样可以传递参数。
小练习:通过类和实例,通过预设的数字打印三三和五五乘法表。
class 乘法表():
def __init__(self,n):
self.n = n
def 打印(self):
for i in range(1,self.n + 1):
for x in range(1,i+1):
print( '%d X %d = %d' % (i ,x ,i*x) ,end = ' ' )
print(' ')
三三乘法表 = 乘法表(3)
三三乘法表.打印()
五五乘法表 = 乘法表(5)
五五乘法表.打印()
3、类的继承
类的继承很大程度也是为了避免重复性劳动。比如说当我们要写一个新的类,如果新的类有许多代码都和旧类相同,又有一部分不同的时候,就可以用“继承”的方式避免重复写代码。
在Python里,我们统一把旧的类称为父类,新写的类称为子类。子类可以在父类的基础上改造类方法,所以我们可以说子类继承了父类。
除了单独继承外,还有多重继承。多重继承有利有弊,过度使用继承容易把事情搞复杂,就像一个人有很多爸爸必定会带来诸多麻烦。如果不是开发大型项目,不太需要用到太复杂的继承关系,所以只需有个印象就好。
4、练习,计费
练习目标:
小王开出租,小李开电动。出租车最低起组为3公里,3公里内最低费用为15元,超过3公里按2.5元每公里计费。小李的电动车与出租车计费标准相同,但每次结账打八折。请以出租车为父类,电动车为子类编写代码,程序可以根据输入的里程数分别为小王、小李计费。
提示:初始参数分别为(每公里费用、最低公里、最低费用)
class 出租车():
def __init__(self,参数1,参数2,参数3):
self.每公里费用 = 参数1
self.最低公里 = 参数2
self.最低费用 = 参数3
def 计费(self):
self.记录行程()
self.统计费用()
self.结算信息()
def 记录行程(self):
self.行程公里数 = float(input('请输入行程公里数:'))
def 统计费用(self):
if self.行程公里数<= self.最低公里:
self.最终费用 = self.最低费用
else:
self.最终费用 = self.最低费用 + (self.行程公里数 - self.最低公里) * self.每公里费用
def 结算信息(self):
print('费用一共是:' + str(self.最终费用) + '元')
class 电动车(出租车):
def 统计费用(self):
if self.行程公里数<= self.最低公里:
self.最终费用 = self.最低费用
else:
self.最终费用 = self.最低费用 + (self.行程公里数 - self.最低公里) * self.每公里费用
self.最终费用 = self.最终费用*0.8
小王的出租车 = 出租车(2.5,3,15)
小王的出租车.计费()
小李的电动车 = 电动车(2.5,3,15)
小李的电动车.计费()
通过本关的学习,知道了类
就像是一个模版,通过这个模版可以制造出许多个实例
对象,这个制造过程称之为实例化
。
在实例化的过程中,可以通过初始化函数__init__
给类传递不同的参数,这样的方式可以让我们得到属性不同的实例。
也学习了继承,有了继承之后,可以很方便的改装类,得到子类,这个过程就像在改装模版,既可以直接复制模版,又可以给模版增加一些功能,亦或是替换、强化原来模板的某些功能。
5、练习,问卷搜集器
练习目标:
通过本练习,再次实践子类的继承和定制。
练习要求:
小刚需要设计一份调查问卷系统,考虑到每次调查问卷的问题都可能不同,参与人数也不同。
请用今天学到的子类相关的知识,帮他将不同问题定制成不同子类(具体的问题见各步骤)。
class Survey():
# 收集调查问卷的答案
def __init__(self, question):
self.question = question
self.response = []
# 显示调查问卷的题目
def show_question(self):
print(self.question)
# 存储问卷搜集的答案
def store_response(self, new_response):
self.response.append(new_response)
# 请定义实名调查问卷的新类 RealNameSurvey,继承自 Survey 类。
class RealNameSurvey(Survey):
def __init__(self, question):
Survey.__init__(self, question)
# 定义收集问卷答案的变量,代码量1行
self.new_response = {}
# 存储问卷搜集的答案(覆盖父类的类方法)
def store_response(self, name, new_response):
# 由于存储答案的变量从列表变成字典,因此存储答案的代码需要改变,代码量1行
self.new_response[name] = new_response
survey = RealNameSurvey('你的籍贯地是哪?')
survey.show_question()
while True:
response = input('请回答问卷问题,按 q 键退出:')
if response == 'q':
break
name = input('请输入回答者姓名:')
# 请将答案用问卷系统存储起来,1 行代码
survey.store_response(name, response)
# 输出测试
for name, value in survey.new_response.items():
print(name + ':' + value)
在做这道题的时候,发现因为命名错误导致浪费了起码1个小时的时间!