Python-十、深入了解类

1、类与对象

先明确“类”和“对象”的关系:【类】是【对象】的模板。

image

我们可以以【类】为模板,多次复制,生成多个【实例对象】。

比如我们可以类为模板,复制出很多【类】,生成多个【实例对象】。

什么叫实例对象呢?可以想象一下,【类】就像工厂的模具,以它为模板,造出来的成千上万的产品,才是被我们消费、购买、使用,真正融入我们生活的东西。这些产品,在Python中就叫【实例对象】。

往深了说,Python中,万事万物都可以是对象,【类】这种模板层级的本身也是【对象】,但并不是【实例对象】。

从模具变成产品,也就是从【类】变成【实例对象】的过程,就叫做【实例化】。

2、类的实例化

首先要注意实力化的基本格式,当类需要被实例化后使用,与直接使用的格式是不同的。

直接使用

image

实例化后使用

image

实例化后再使用的格式:

①、空着的,意思是这里不再需要@classmethod的声明;

②、中,把cls替换成了self。

③、实例化后再使用的格式,需要先赋值然后再调用。

④、我们需要用实例名 = 类()的方式(实例名其实就是任取一个变量名),为类创建一个实例,然后再使用实例名.函数()的方式调用对应的方法。

另外提一下,cls代表“类”的意思,self代表“实例”的意思,这样写是编码规范(程序员们的共识),但不是强制要求。理论上只要写个变量名占位,写什么都行,比如把self写成bbb也可以。

当类被实例化以后,就不能再以类的形式运行了。

2.1、实例属性和类属性

类和实例的关系,就像母体和复制品的关系一样。当一个类实例化为多个实例后,实例将原封不动的获得类属性,也就是实例属性和类属性完全相等。

image

我们可以修改类属性,这会导致所有实例属性变化(因为类是模板)。

image

我们也可以修改实例属性,但这不会影响到其他实例,也不会影响到类。因为每个实例都是独立的个体。

image

对于新增也是一样的道理,在类中新增会影响实例,但在实例中新增并不会影响类。值得注意的是,当实例和类同时修改变量时候,因为每一个实例都是独立的个体,所以下面这段代码的运行结果,是10和1


class 类:

    变量 = 100 #类属性

实例1 = 类() # 实例化

实例2 = 类() # 实例化

实例1.变量 = 10

类.变量 = 1

print(实例1.变量)

print(实例2.变量)

每个实例都是独立的个体。其中实例1.变量 = 10相当于修改了实例属性,所以类.变量 = 1不能影响到它,只能影响到实例2.变量。最终实例1.变量的值是10,实例2.变量的值是1。

2.2、实例方法和类方法

“重写类方法”分成两个步骤:第一个步骤是在类的外部写一个函数,第二个步骤是把这个新函数的名字赋值给类.原始函数。

image

我们可以通过重写类方法,让实例方法发生变化,但我们不能重写实例方法,模板给的技能不是说换就能换的。

image

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)

五五乘法表.打印()

image

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个小时的时间!

你可能感兴趣的:(Python-十、深入了解类)