猫哥教你写爬虫 022--类与对象(下)

类是对象的模板

为了完成“西红柿炒蛋”的任务,可以制造一个“炒菜机器人”,给它下达指令。

机器人.做菜('西红柿炒鸡蛋')
复制代码

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

从模具变成产品,也就是从【类】变成【实例对象】的过程,就叫做【实例化】
成绩单代码
class 成绩单():
    @classmethod
    def 录入成绩单(cls):
        cls.学生姓名 = input('请输入学生姓名:')
        cls.语文_成绩 = int(input('请输入语文成绩:'))
        cls.数学_成绩 = int(input('请输入数学成绩:'))
    @classmethod
    def 打印成绩单(cls):
        print(cls.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(cls.语文_成绩))
        print('数学成绩:'+ str(cls.数学_成绩))
成绩单.录入成绩单()
成绩单.打印成绩单()
复制代码
如果我们需要录入多份成绩呢?

如果没有学习实例化对象之前. 我们可能要这样写...

class 成绩单1():
    @classmethod
    def 录入成绩单(cls):
        cls.学生姓名 = input('请输入学生姓名:')
        cls.语文_成绩 = int(input('请输入语文成绩:'))
        cls.数学_成绩 = int(input('请输入数学成绩:'))
    
    @classmethod
    def 打印成绩单(cls):
        print(cls.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(cls.语文_成绩))
        print('数学成绩:'+ str(cls.数学_成绩))
class 成绩单2():
    @classmethod
    def 录入成绩单(cls):
        cls.学生姓名 = input('请输入学生姓名:')
        cls.语文_成绩 = int(input('请输入语文成绩:'))
        cls.数学_成绩 = int(input('请输入数学成绩:'))
    @classmethod
    def 打印成绩单(cls):
        print(cls.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(cls.语文_成绩))
        print('数学成绩:'+ str(cls.数学_成绩))
class 成绩单3():
    @classmethod
    def 录入成绩单(cls):
        cls.学生姓名 = input('请输入学生姓名:')
        cls.语文_成绩 = int(input('请输入语文成绩:'))
        cls.数学_成绩 = int(input('请输入数学成绩:'))
    @classmethod
    def 打印成绩单(cls):
        print(cls.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(cls.语文_成绩))
        print('数学成绩:'+ str(cls.数学_成绩))
成绩单1.录入成绩单()
成绩单1.打印成绩单()
成绩单2.录入成绩单()
成绩单2.打印成绩单()
成绩单3.录入成绩单()
成绩单3.打印成绩单()
复制代码
有了实例化对象...
class 成绩单():
    def 录入成绩单(self):
        self.学生姓名 = input('请输入学生姓名:')
        self.语文_成绩 = int(input('请输入语文成绩:'))
        self.数学_成绩 = int(input('请输入数学成绩:'))
    def 打印成绩单(self):
        print(self.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(self.语文_成绩))
        print('数学成绩:'+ str(self.数学_成绩))
# 成绩单()类实例化为成绩单1、成绩单2、成绩单3三个【实例对象】
成绩单1 = 成绩单() # 实例化,得到实例对象“成绩单1”
成绩单2 = 成绩单() # 实例化,得到实例对象“成绩单2”
成绩单3 = 成绩单() # 实例化,得到实例对象“成绩单3”
print('现在开始录入三份成绩单:')
成绩单1.录入成绩单()
成绩单2.录入成绩单()
成绩单3.录入成绩单()
print('现在开始打印三份成绩单:')
成绩单1.打印成绩单()
成绩单2.打印成绩单()
成绩单3.打印成绩单()
复制代码

如何得到【实例】,如何使用【实例】,使用【实例】和直接使用【类】有什么区别?
当类需要被实例化后再使用时,和直接使用类的格式是不同的。
我们之前的直接使用类的代码

如果是实例化后再使用...

`

完整版的对比代码...
# 直接使用类
class 成绩单():
    @classmethod
    def 录入成绩单(cls):
        cls.学生姓名 = input('请输入学生姓名:')
        cls.语文_成绩 = int(input('请输入语文成绩:'))
        cls.数学_成绩 = int(input('请输入数学成绩:'))
    @classmethod
    def 打印成绩单(cls):
        print(cls.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(cls.语文_成绩))
        print('数学成绩:'+ str(cls.数学_成绩))
成绩单.录入成绩单()
成绩单.打印成绩单()
# 实例化之后
class 成绩单():   # ①不用再写@classmethod
    def 录入成绩单(self):  # ②cls变成self
        self.学生姓名 = input('请输入学生姓名:')  # ③cls.变成self.
        self.语文_成绩 = int(input('请输入语文成绩:'))
        self.数学_成绩 = int(input('请输入数学成绩:'))
    def 打印成绩单(self):
        print(self.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(self.语文_成绩))
        print('数学成绩:'+ str(self.数学_成绩))
成绩单1 = 成绩单() # ④创建实例对象:成绩单1
成绩单1.录入成绩单() # ⑤实例化后使用
成绩单1.打印成绩单()
复制代码
以下代码是直接使用类的格式,请改成实例化后再使用的格式
class 智能机器人():
    胸围 = 33
    腰围 = 44
    臀围 = 55
    
    @classmethod
    def 自报三围(cls):
        print('主人,我的三围是:')
        print('胸围:' + str(cls.胸围))
        print('腰围:' + str(cls.腰围))
        print('臀围:' + str(cls.臀围))
        print('哈哈哈哈哈,下面粗上面细,我长得像个圆锥。')
智能机器人.自报三围()
复制代码
实例化后再使用的代码...
class 智能机器人():
    胸围 = 33
    腰围 = 44
    臀围 = 55
    
    def 自报三围(self):
        print('主人,我的三围是:')
        print('胸围:' + str(self.胸围))
        print('腰围:' + str(self.腰围))
        print('臀围:' + str(self.臀围))
        print('哈哈哈哈哈,下面粗上面细,我长得像个圆锥。')
a = 智能机器人() # 实例化“智能机器人”类得到一个名字叫做“a”的实例
a.自报三围()
复制代码
cls代表“类”的意思,self代表“实例”的意思
如果把self改成别的单词呢 ? 比如bbb ?
class 智能机器人():
    胸围 = 33
    腰围 = 44
    臀围 = 55
    
    def 自报三围(bbb):
        print('主人,我的三围是:')
        print('胸围:' + str(bbb.胸围))
        print('腰围:' + str(bbb.腰围))
        print('臀围:' + str(bbb.臀围))
        print('哈哈哈哈哈,下面粗上面细,我长得像个圆锥。')
a = 智能机器人() # 实例化“智能机器人”类得到一个名字叫做“a”的实例
a.自报三围()
复制代码
self是所有类方法位于首位、默认的特殊参数。

实例属性和类属性有什么区别

class():
    变量 = 100
实例1 = 类() # 实例化
实例2 = 类() # 实例化
print(类.变量) # 100
print(实例1.变量) # 100
print(实例2.变量) # 100
复制代码
修改类属性,会导致所有实例属性变化(因为类是模板)

代码为证
class():
    变量 = 100
实例1 = 类() # 实例化
实例2 = 类() # 实例化
print(实例1.变量)
print(实例2.变量)
类.变量 = 'abc'   # 修改类属性
print(实例1.变量)   # 实例属性同步变化
print(实例2.变量)   # 实例属性同步变化
复制代码
修改实例属性,不会影响到其他实例,也不会影响到类。因为每个实例都是独立的个体

有代码为证
# 请直接运行并体验代码
class():
    变量 = 100
实例1 = 类() # 实例化
实例2 = 类() # 实例化
print('原先的类属性:')
print(类.变量)
print('原先的实例1属性:')
print(实例1.变量)
print('原先的实例2属性:')
print(实例2.变量)
实例1.变量 = 'abc'
print('--------修改实例1的属性后----------') 
print('现在的类属性:')
print(类.变量)
print('现在的实例1属性:')
print(实例1.变量)
print('现在的实例2属性:')
print(实例2.变量)
复制代码
新增也是一样的道理,在类中新增属性会影响到实例,但在实例中新增属性只影响这个实例自己。
类新增属性...
# 请直接运行并体验代码
class():
    变量1 = 100
实例 = 类() # 实例化
类.变量2 = 'abc' # 新增类属性
print(实例.变量1)
print(实例.变量2)
复制代码
实例新增属性...
# 请直接运行并体验代码
class():
    变量1 = 100
实例 = 类() # 实例化
实例.变量2 = 'abc' # 新增实例属性
print(类.变量2)
复制代码

请阅读以下代码,然后想一想它的运行结果将会是什么。
class 类:
    变量 = 100 #类属性
实例1 = 类() # 实例化
实例2 = 类() # 实例化
实例1.变量 = 10
类.变量 = 1
print(实例1.变量)
print(实例2.变量)
复制代码

实例方法和类方法的区别...
重写类方法,这会导致所有实例方法自动被重写

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

【不要加上括号】—— 写成类.原始函数() = 新函数()是错误的。
是赋值, 不是调用...
class():
    def 原始函数(self):
        print('我是原始函数!')
def 新函数(self):
    print('我是重写后的新函数!')
a = 类()  # 实例化
a.原始函数()
# 用新函数代替原始函数,也就是【重写类方法】
类.原始函数 = 新函数
# 现在原始函数已经被替换了
a.原始函数() # 重写类方法, 会波及到实例的方法...
复制代码
补全代码, 使其符合效果...

class 幸运():
    def 好运翻倍(self):
        print('好的,我把它存了起来,然后翻了888倍还给你:' + str(self.幸运数*888))
……
    ……
幸运.幸运数 = int(input('你的幸运数是多少?请输入一个整数。'))
……
实例 = 幸运()  # 实例化
实例.好运翻倍()
复制代码
补全之后的代码
# 请直接运行并体验代码
class 幸运():
    def 好运翻倍(self):
        print('好的,我把它存了起来,然后翻了888倍还给你:' + str(self.幸运数*888))
def 新好运翻倍(self):
    print('我是重写后的新函数!')
    print('好的,我把它存了起来,然后翻了666倍还给你:' + str(self.幸运数*666))
幸运.幸运数 = int(input('你的幸运数是多少?请输入一个整数。'))
幸运.好运翻倍 = 新好运翻倍
实例 = 幸运()  # 实例化
实例.好运翻倍()
复制代码
我们可以通过重写类方法,让实例方法发生变化,
但我们不能重写实例方法,模板给的技能不是说换就能换的。

不信 ? 来, 做个死...
class 幸运():
    def 好运翻倍(self):
        print('好的,我把它存了起来,然后翻了888倍还给你:' + str(self.幸运数*888))
def 新好运翻倍(self):
    print('我是重写后的新函数!')
    print('好的,我把它存了起来,然后翻了666倍还给你:' + str(self.幸运数*666))
幸运.幸运数 = int(input('你的幸运数是多少?请输入一个整数。'))
实例 = 幸运()  # 实例化
实例.好运翻倍 = 新好运翻倍    # 尝试重写实例方法,将会报错
实例.好运翻倍()
复制代码

什么是初始化函数
先上代码
class():
    def __init__(self):
        print('实例化成功!')
实例 = 类()
复制代码
初始化函数的意思是,当你创建一个实例的时候,这个函数就会被调用
__init__()的括号中,第一个参数一定要写上self,不然会报错

初始化函数照样可以传递参数
之前的代码...
class 成绩单():
    def 录入成绩单(self):
        self.学生姓名 = input('请输入学生姓名:')
        self.语文_成绩 = int(input('请输入语文成绩:'))
        self.数学_成绩 = int(input('请输入数学成绩:'))
    def 打印成绩单(self):
        print(self.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(self.语文_成绩))
        print('数学成绩:'+ str(self.数学_成绩))
成绩单1 = 成绩单() # 实例化
成绩单2 = 成绩单() # 实例化
成绩单3 = 成绩单() # 实例化
成绩单1.录入成绩单()
成绩单2.录入成绩单()
成绩单3.录入成绩单()
成绩单1.打印成绩单()
成绩单2.打印成绩单()
成绩单3.打印成绩单()
复制代码
我们可以直接把需要录入的信息作为参数传递给成绩单1成绩单2成绩单3这三个实例对象。
class 成绩单():
    def __init__(self,学生姓名,语文_成绩,数学_成绩):
        self.学生姓名 = 学生姓名
        self.语文_成绩 = 语文_成绩
        self.数学_成绩 = 数学_成绩
    def 打印成绩单(self):
        print(self.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(self.语文_成绩))
        print('数学成绩:'+ str(self.数学_成绩))
成绩单1 = 成绩单('张三',99,88)
成绩单2 = 成绩单('李四',64,73)
成绩单3 = 成绩单('王五',33,22)
成绩单1.打印成绩单()
成绩单2.打印成绩单()
成绩单3.打印成绩单()
复制代码
九九乘法表...

三三乘法表...

五五乘法表

补全代码后,运行效果:打印了一个三三乘法表和五五乘法表

class 乘法表():
    def __init__(……):
        ……
    def 打印(……):
        for i in range(……):
            for x in range(1,i+1):
                print( '%d X %d = %d' % (i ,x ,i*x) ,end = '  ' )
            print('  ')
三三乘法表 = 乘法表(3)
三三乘法表.打印()
五五乘法表 = 乘法表(5)
五五乘法表.打印()
复制代码
代码答案...
# 请直接运行和体验代码
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)
五五乘法表.打印()
复制代码
代码解析...

小结

什么是继承

偶像剧里富二代继承老爹遗产,从此甩开99%同龄人,走上人生巅峰...
“类的继承”也和这个有点类似,“子类”继承了“父类”的“财产”。
类的继承很大程度也是为了避免重复性劳动。
比如说当我们要写一个新的类,如果新的类有许多代码都和旧类相同,又有一部分不同的时候,
就可以用“继承”的方式避免重复写代码。
class 成绩单_():
    def __init__(self,学生姓名,语文_成绩,数学_成绩):
        self.学生姓名 = 学生姓名
        self.语文_成绩 = 语文_成绩
        self.数学_成绩 = 数学_成绩
    def 打印成绩单(self):
        print(self.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(self.语文_成绩))
        print('数学成绩:'+ str(self.数学_成绩))
    def 打印平均分(self):
        平均分 = (self.语文_成绩 + self.数学_成绩)/2
        print(self.学生姓名 + '的平均分是:' + str(平均分))
class 成绩单_():
    def __init__(self,学生姓名,语文_成绩,数学_成绩):
        self.学生姓名 = 学生姓名
        self.语文_成绩 = 语文_成绩
        self.数学_成绩 = 数学_成绩
    def 打印成绩单(self):
        print(self.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(self.语文_成绩))
        print('数学成绩:'+ str(self.数学_成绩))
    def 打印平均分(self):
        平均分 = (self.语文_成绩 + self.数学_成绩)/2
        print(self.学生姓名 + '的平均分是:' + str(平均分))
    def 打印总分(self):
        总分 = self.语文_成绩 + self.数学_成绩
        print(self.学生姓名 + '的总分是:' + str(总分))
实例_旧 = 成绩单_旧('王明明',99,88)
实例_旧.打印成绩单()
实例_旧.打印平均分()
实例_新 = 成绩单_新('王明明',99,88)
实例_新.打印成绩单()
实例_新.打印平均分()
实例_新.打印总分()
复制代码

如果运用继承来改写代码...
class 成绩单_():
    def __init__(self,学生姓名,语文_成绩,数学_成绩):
        self.学生姓名 = 学生姓名
        self.语文_成绩 = 语文_成绩
        self.数学_成绩 = 数学_成绩
    def 打印成绩单(self):
        print(self.学生姓名 + '的成绩单如下:')
        print('语文成绩:'+ str(self.语文_成绩))
        print('数学成绩:'+ str(self.数学_成绩))
    def 打印平均分(self):
        平均分 = (self.语文_成绩 + self.数学_成绩)/2
        print(self.学生姓名 + '的平均分是:' + str(平均分))
class 成绩单_(成绩单_旧):
    def 打印总分(self):
        总分 = self.语文_成绩 + self.数学_成绩
        print(self.学生姓名 + '的总分是:' + str(总分))
实例_旧 = 成绩单_旧('王明明',99,88)
实例_旧.打印成绩单()
实例_旧.打印平均分()
实例_新 = 成绩单_新('王明明',99,88)
实例_新.打印成绩单()
实例_新.打印平均分()
实例_新.打印总分()
复制代码
class 成绩单_新(成绩单_旧)就用到了类的继承,格式是class 新类(旧类)

旧的类称为父类,新写的类称为子类
子类可以在父类的基础上改造类方法,所以我们可以说子类继承了父类
class 父类():
    def __init__(self,参数):
        self.变量 = 参数
    def 打印属性(self):
        print('变量的值是:')
        print(self.变量)
class 子类(父类):
    pass  # pass语句代表“什么都不做”
子类实例 = 子类(2)
子类实例.打印属性()
复制代码

小练习, 补全代码...
class 基础机器人():
    def __init__(self,参数):
        self.姓名 = 参数
    def 自报姓名(self):
        print('我是' + self.姓名 + '!')     
    def 卖萌(self):
        print('主人,求抱抱!')
……
    ……
        ……
安迪 = 高级机器人('安迪')
安迪.自报姓名()
安迪.卖萌()
安迪.高级卖萌()
复制代码
用到的方法...
安迪 = 高级机器人('安迪')
安迪.自报姓名()
安迪.卖萌()
安迪.高级卖萌()
复制代码
运行效果
我是安迪!
主人,求抱抱!
主人,每次想到怎么欺负你的时候,就感觉自己全身biubiubiu散发着智慧的光芒!
复制代码
补全后的代码...
class 基础机器人():
    def __init__(self,参数):
        self.姓名 = 参数
    def 自报姓名(self):
        print('我是' + self.姓名 + '!')     
    def 卖萌(self):
        print('主人,求抱抱!')
class 高级机器人(基础机器人):
    def 高级卖萌(self):
        print('主人,每次想到怎么欺负你的时候,就感觉自己全身biubiubiu散发着智慧的光芒!')
安迪 = 高级机器人('安迪')
安迪.自报姓名()
安迪.卖萌()
安迪.高级卖萌()
复制代码
子类除了可以定制新的类方法,还能直接覆盖父类的方法,
只要使用相同的类方法名称就能做到这一点。
# 请阅读注释,然后运行代码
class 基础机器人():
    def __init__(self,参数):
        self.姓名 = 参数
    def 自报姓名(self):
        print('我是' + self.姓名 + '!')     
    def 卖萌(self):
        print('主人,求抱抱!')
class 高级机器人(基础机器人):
    def 卖萌(self):  # 这里使用了相同的类方法名称“卖萌”,这样可以让子类方法覆盖父类方法
        print('主人,每次想到怎么欺负你的时候,就感觉自己全身biubiubiu散发着智慧的光芒!')
鲁宾 =  基础机器人('鲁宾')
鲁宾.自报姓名()
鲁宾.卖萌()  # 调用父类方法
安迪 = 高级机器人('安迪')
安迪.自报姓名()
安迪.卖萌()  # 父类方法被子类中的同名方法覆盖
复制代码
小练习: 补全代码, 使其符合效果
class 基础机器人():
    def __init__(self,参数):
        self.姓名 = 参数
    def 自报姓名(self):
        print('我是' + self.姓名 + '!')     
    def 卖萌(self):
        print('主人,求抱抱!')
class 高级机器人(基础机器人):
    def ……
        ……
        ……
    def 卖萌(self):
        print('主人,每次想到怎么欺负你的时候,就感觉自己全身biubiubiu散发着智慧的光芒!')
安迪 = 高级机器人('安迪')
安迪.自报姓名()
安迪.高级卖萌()
复制代码

补全后的代码...
class 基础机器人():
    def __init__(self,参数):
        self.姓名 = 参数
    def 自报姓名(self):
        print('我是' + self.姓名 + '!')     
    def 卖萌(self):
        print('主人,求抱抱!')
class 高级机器人(基础机器人):
    def 自报姓名(self):
        print('我是高级机器人' + self.姓名 + '!')
    def 卖萌(self):
        print('主人,每次想到怎么欺负你的时候,就感觉自己全身biubiubiu散发着智慧的光芒!')
安迪 = 高级机器人('安迪')
安迪.自报姓名()
安迪.卖萌()
复制代码
我们能在子类中重写覆盖任意父类方法,哪怕是初始化函数__init__
小练习: 补全代码, 使其符合效果
class 基础机器人():
    def __init__(self,参数):
        self.姓名 = 参数
    def 自报姓名(self):
        print('我是' + self.姓名 + '!')     
    def 卖萌(self):
        print('主人,求抱抱!')
class 高级机器人(基础机器人):
    def __init__(……):
        ……
    
    def 自报姓名(self):
        print(……)       
    def 卖萌(self):
        print('主人,每次想到怎么欺负你的时候,就感觉自己全身biubiubiu散发着智慧的光芒!')
安迪 = 高级机器人('安迪',150)
安迪.自报姓名()
安迪.卖萌()
复制代码

补全后的代码...
class 基础机器人():
    def __init__(self,参数):
        self.姓名 = 参数
    def 自报姓名(self):
        print('我是' + self.姓名 + '!')     
    def 卖萌(self):
        print('主人,求抱抱!')
class 高级机器人(基础机器人):
    def __init__(self,参数,参数2):
        self.姓名 = 参数
        self.智商 = 参数2
    
    def 自报姓名(self):
        print('我是高级机器人' + self.姓名 + '!' + '智商高达' + str(self.智商) + '!' )       
    def 卖萌(self):
        print('主人,每次想到怎么欺负你的时候,就感觉自己全身biubiubiu散发着智慧的光芒!')
安迪 = 高级机器人('安迪',150)
安迪.自报姓名()
安迪.卖萌()
复制代码

子类从【一个父类】继承类方法,我们叫做“单继承”。还有一种更复杂的继承情况,叫“多重继承”

多重继承 就是一个子类从【多个父类】中继承类方法。
格式是class 子类(父类1,父类2,……)
class 基础机器人():
    def 卖萌(self):
        print('主人,求抱抱!')
# 注:因为多重继承要求父类是平等的关系,所以这里的“高级机器人”没有继承“基础机器人”
class 高级机器人(): 
    def 高级卖萌(self): 
        print('主人,每次想到怎么欺负你的时候,就感觉自己全身biubiubiu散发着智慧的光芒!')
class 超级机器人(基础机器人,高级机器人):
    def 超级卖萌(self): 
        print('pika, qiu!')
        print('''             へ     /|
              /\7   ∠_/
             / │  / /
             │ Z_,< /  /`ヽ
             │     ヽ  /  〉
             Y     ` /  /
             イ● 、 ●  ⊂⊃〈  /
             () へ    | \〈
              >ー、_ ィ │//
             /へ  / ノ<|\\
             ヽ_ノ  (_/ │//
              7       |/
              >―r ̄ ̄`ー―_''')
        
皮卡 = 超级机器人()
皮卡.卖萌()
皮卡.高级卖萌()
皮卡.超级卖萌()
复制代码
子类超级机器人同时继承了父类基础机器人高级机器人中的类方法
多重继承有利有弊。过度使用继承容易把事情搞复杂,就像一个人有很多爹必定会带来诸多麻烦。

课堂实操

隔壁小王请你为他编写了一个出租车计费的程序

class 出租车():
    def 计费(self):
        公里数 = float(input('请输入行程公里数:'))
        费用 = 公里数 * 2.5
        print('费用一共是:' + str(费用) + '元')
小王的出租车 = 出租车()
小王的出租车.计费()
复制代码

程序不完美的地方在于,每公里费用2.5元是一个写死的数据,无法修改。 小王希望你能完善一下这个代码,也就是写出一个初始化函数,让这个类能接收参数(也就是每公里计费价格)生成不同的实例。

这样,他就能把这个程序借个隔壁的隔壁,也就是司机小李用。

补全代码, 效果如下

class 出租车():
    ……
        ……
        ……
    def 计费(self):
        公里数 = float(input('请输入行程公里数:'))
        费用 = 公里数 * ……
        print('费用一共是:' + str(费用) + '元')
小王的出租车 = 出租车(2.5)
小王的出租车.计费()
小李的出租车 = 出租车(3)
小李的出租车.计费()
复制代码
补全后的代码...
# 请直接运行并体验代码
class 出租车():
    def __init__(self,参数):
        self.每公里费用 = 参数    
    def 计费(self):
        公里数 = float(input('请输入行程公里数:'))
        费用 = 公里数 * self.每公里费用
        print('费用一共是:' + str(费用) + '元')
小王的出租车 = 出租车(2.5)
小王的出租车.计费()
小李的出租车 = 出租车(3)
小李的出租车.计费()
复制代码

这里的计费规则不太科学。司机小王对代码提出意见 小王:“我这里都是前3公里15元,后面每公里2.5元,你帮我把代码改一下,让它按我的方式计费。”

修改后的代码...
class 出租车():
    def __init__(self,参数):
        self.每公里费用 = 参数
        
    def 计费(self):
        公里数 = int(input('请输入行程公里数:'))
        if 公里数<= 3:
            费用 = 15
        else:
            费用 = 15 + (公里数-3)*self.每公里费用
        print('费用一共是:' + str(费用) + '元')
小王的出租车 = 出租车(2.5)
小王的出租车.计费()
复制代码

小王:“你的代码还是不够方便。我有时候想改成4公里20元,有时候想改成2公里12元,你这代码不支持我传递这些参数,能不能修改一下?” 补全代码后,“出租车”类可以接受3个参数,程序的运行效果不变:

修改的代码...
class 出租车():
    def __init__(self,参数1,参数2,参数3):
        self.每公里费用 = 参数1
        self.最低公里 = 参数2
        self.最低费用 = 参数3
        
    def 计费(self):
        公里数 = float(input('请输入行程公里数:'))
        if 公里数<= self.最低公里:
            费用 = self.最低费用
        else:
            费用 = self.最低费用 + (公里数 - self.最低公里)*self.每公里费用
        print('费用一共是:' + str(费用) + '元')
小王的出租车 = 出租车(2.5,3,15)
小王的出租车.计费()
复制代码

重构代码,把计费函数拆解成计费记录行程统计费用结算信息四个函数:

class 出租车():
    def __init__(self,参数1,参数2,参数3):
        self.每公里费用 = 参数1
        self.最低公里 = 参数2
        self.最低费用 = 参数3
    
    def 计费(self):
        self.记录行程()
        self.统计费用()
        self.结算信息()
    def 记录行程(self):
        ……
    def 统计费用(self):
        ……
    def 结算信息(self):
        ……
小王的出租车 = 出租车(2.5,3,15)
小王的出租车.计费()
复制代码

程序的运行效果和刚才一模一样:

修改的代码...
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.最终费用) + '元')
小王的出租车 = 出租车(2.5,3,15)
小王的出租车.计费()
复制代码

小王对你的代码很满意。不过,开电动车的小李又跑来找你 小李:“我是开电动车的,现在政府号召环保,对电动车也补贴,所有电动车计费按8折算,你能帮我写个程序么?”

补全代码
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 ……:
        ……
小王的出租车 = 出租车(2.5,3,15)
小王的出租车.计费() 
小李的电动车 = 电动车(2.5,3,15)
小李的电动车.计费()
复制代码
效果如下...

补全的代码...(推荐使用继承)
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__给类传递不同的参数,这样的方式可以让我们得到属性不同的实例

有了继承之后,我们可以很方便的改装,得到子类
这个过程就像在改装模版,我们既可以直接复制模版,
又可以给模版增加一些功能,亦或是替换、强化原来模板的某些功能

今日作业

使用面向对象的方式, 来改写代码...
import time
import random
user1 = {
    'name': '',
    'life': 0,
    'victory':0
}
user2 = {
    'name': '',
    'life': 0,
    'victory':0
}
attack_list = [
    {
        'desc':'{} 挥剑向 {} 砍去',
        'num':20
    },
    {
        'desc':'{} 准备刚正面, 对 {} 使出一记"如来神掌"',
        'num':30
    },
    {
        'desc':'{} 撸起了袖子给 {} 一顿胖揍',
        'num':25
    },
    {
        'desc':'{} 向 {} 抛了个媚眼',
        'num':10
    },
    {
        'desc':'{} 抄起冲锋枪就是一梭子, {} 走位风骚, 轻松躲过',
        'num':0
    },
    {
        'desc':'{} 出了一个大招, {} 躲闪不及, 正中要害',
        'num':40
    }
]
user1['name'] = input('请输入玩家1的昵称: ')
user2['name'] = input('请输入玩家2的昵称: ')
while True:
    user1['victory'] = 0
    user2['victory'] = 0
    for i in range(3):
        print('  \n——————现在是第 {} 局——————'.format(i+1))
        user1['life'] = random.randint(100, 150)
        user2['life'] = random.randint(100, 150)
        print(user1['name']+'\n血量:{}'.format(user1['life']))
        print('------------------------')
        print(user2['name']+'\n血量:{}'.format(user2['life']))
        print('-----------------------')
        time.sleep(4)
        first_attack = random.randint(0,1)
        users_list = []
        if first_attack:
            user1['isfirst'] = 1
            print('漂亮!!! '+user1['name']+' 获得先发优势!')
            print('')
            users_list.append(user1)
            users_list.append(user2)
        else:
            user2['isfirst'] = 1
            print('难以置信! '+user2['name']+' 获得先发优势!')
            print('')
            users_list.append(user2)
            users_list.append(user1)
        time.sleep(2)
        while user1['life'] > 0 and user2['life'] > 0:
            tmp_rand = random.randint(0,len(attack_list)-1)
            users_list[1]['life'] = users_list[1]['life'] - attack_list[tmp_rand]['num']
            print(attack_list[tmp_rand]['desc'].format(users_list[0]['name'],users_list[1]['name'])+' 造成了{}点伤害 ==> '.format(attack_list[tmp_rand]['num'])+users_list[1]['name']+' 的剩余血量:{}'.format(users_list[1]['life']))
            time.sleep(4)
            if users_list[1]['life'] <= 0:
                print('')
                print(users_list[1]['name']+' 惨败 -_-||')
                users_list[0]['victory']+=1
                break
            tmp_rand = random.randint(0,len(attack_list)-1)
            users_list[0]['life'] = users_list[0]['life'] - attack_list[tmp_rand]['num']
            print(attack_list[tmp_rand]['desc'].format(users_list[1]['name'],users_list[0]['name'])+' 造成了{}点伤害 ==> '.format(attack_list[tmp_rand]['num'])+users_list[0]['name']+' 的剩余血量:{}'.format(users_list[0]['life']))
            time.sleep(4)
            if users_list[0]['life'] <= 0:
                print('')
                print(users_list[0]['name']+' 惨败 -_-||')
                time.sleep(3)
                users_list[1]['victory']+=1
                break
            print('-----------------------')
        if user1['victory'] == 2:
            print('')
            print('三局两胜中 '+user1['name']+' 获胜!')
            break
        if user2['victory'] == 2:
            print('')
            print('三局两胜中 '+user2['name']+' 获胜!')
            break
    print('')
    res = input('要不要再来一局? (回复"是"再来一局, 其他退出...) ') 
    if res != '是':
        break
复制代码
面向对象的方式...
未完待续...
复制代码

快速跳转:

猫哥教你写爬虫 000--开篇.md
猫哥教你写爬虫 001--print()函数和变量.md
猫哥教你写爬虫 002--作业-打印皮卡丘.md
猫哥教你写爬虫 003--数据类型转换.md
猫哥教你写爬虫 004--数据类型转换-小练习.md
猫哥教你写爬虫 005--数据类型转换-小作业.md
猫哥教你写爬虫 006--条件判断和条件嵌套.md
猫哥教你写爬虫 007--条件判断和条件嵌套-小作业.md
猫哥教你写爬虫 008--input()函数.md
猫哥教你写爬虫 009--input()函数-人工智能小爱同学.md
猫哥教你写爬虫 010--列表,字典,循环.md
猫哥教你写爬虫 011--列表,字典,循环-小作业.md
猫哥教你写爬虫 012--布尔值和四种语句.md
猫哥教你写爬虫 013--布尔值和四种语句-小作业.md
猫哥教你写爬虫 014--pk小游戏.md
猫哥教你写爬虫 015--pk小游戏(全新改版).md
猫哥教你写爬虫 016--函数.md
猫哥教你写爬虫 017--函数-小作业.md
猫哥教你写爬虫 018--debug.md
猫哥教你写爬虫 019--debug-作业.md
猫哥教你写爬虫 020--类与对象(上).md
猫哥教你写爬虫 021--类与对象(上)-作业.md
猫哥教你写爬虫 022--类与对象(下).md
猫哥教你写爬虫 023--类与对象(下)-作业.md
猫哥教你写爬虫 024--编码&&解码.md
猫哥教你写爬虫 025--编码&&解码-小作业.md
猫哥教你写爬虫 026--模块.md
猫哥教你写爬虫 027--模块介绍.md
猫哥教你写爬虫 028--模块介绍-小作业-广告牌.md
猫哥教你写爬虫 029--爬虫初探-requests.md
猫哥教你写爬虫 030--爬虫初探-requests-作业.md
猫哥教你写爬虫 031--爬虫基础-html.md
猫哥教你写爬虫 032--爬虫初体验-BeautifulSoup.md
猫哥教你写爬虫 033--爬虫初体验-BeautifulSoup-作业.md
猫哥教你写爬虫 034--爬虫-BeautifulSoup实践.md
猫哥教你写爬虫 035--爬虫-BeautifulSoup实践-作业-电影top250.md
猫哥教你写爬虫 036--爬虫-BeautifulSoup实践-作业-电影top250-作业解析.md
猫哥教你写爬虫 037--爬虫-宝宝要听歌.md
猫哥教你写爬虫 038--带参数请求.md
猫哥教你写爬虫 039--存储数据.md
猫哥教你写爬虫 040--存储数据-作业.md
猫哥教你写爬虫 041--模拟登录-cookie.md
猫哥教你写爬虫 042--session的用法.md
猫哥教你写爬虫 043--模拟浏览器.md
猫哥教你写爬虫 044--模拟浏览器-作业.md
猫哥教你写爬虫 045--协程.md
猫哥教你写爬虫 046--协程-实践-吃什么不会胖.md
猫哥教你写爬虫 047--scrapy框架.md
猫哥教你写爬虫 048--爬虫和反爬虫.md
猫哥教你写爬虫 049--完结撒花.md

转载于:https://juejin.im/post/5cfc4ad86fb9a07eb15d4896

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值