Python——类(class)的定义及使用

Python从设计之初就已经是一门面向对象的语言,正因为如此,在Python中创建一个类和对象是很容易的。
参考:Python入门之类(class)、python中class的定义及使用
接下来我们先来简单的了解下面向对象的一些基本特征。
类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。

面向对象技术简介

  • 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
  • **类变量:**类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
  • **数据成员:**类变量或者实例变量用于处理类及其实例对象的相关的数据。
  • **方法重写:**如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
  • **实例变量:**定义在方法中的变量,只作用于当前实例的类。
  • **继承:**即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。例如,有这样一个设计:一个Dog类型的对象派生自Animal类,素以Dog也是一个Animal。
  • **实例化:**创建一个类的实例,类的具体对象。
  • **方法:**类中定义的函数。
  • **对象:**通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。

python3 类创建

面向对象编程是一种编程方式,此编程方式的落地需要使用 “类” 和 “对象” 来实现,所以,面向对象编程其实就是对 “类” 和 “对象” 的使用。
就是一个模板,模板里可以包含多个函数,函数里实现一些功能
对象则是根据模板创建的实例,通过实例对象可以执行类中的函数

#创建类
class Foo():    #class是关键字(表示要开始创建类):Foo是新建类名称
    #创建类中函数
    def bar(self):    #self特殊参数(必填)
        pass

#根据Foo创建对象obj
obj = Foo
'''
ps:类中的函数第一个参数必须是self
类中定义的函数叫做“方法”
'''

总结:函数式的应用场景 --> 各个函数之间是独立且无共用的数据

面向对象三大特性

面向对象的三大特性是指:封装、继承和多态。

一、封装

封装,顾名思义就是将内容封装到某个地方,以后再去调用被封装在某处的内容。
所以,在使用面向对象的封装特性时,需要:

  • 将内容封装到某处
  • 从某处调用被封装的内容
#创建类
class Foo():
    def __init__(self, name, age):    #构造函数,类实例化是自动执行
        #初始化实例属性
        self.name = name
        self.age = age

#根据类Foo创建对象
#自动执行Foo类的__init__方法
obj1 = Foo('chengd', 18)    #将changd和18分别封装到obj1/self的name和age属性中(此处obj2其实就是self)

#根据类Foo创建对象
#自动执行Foo类的__init__方法
obj2 = Foo('python', 99)    #将python和99分别封装到obj2/self的name和age属性中(此处obj2其实就是self)
self是一个形式参数,
当执行obj1=Foo('wupeiqi', 18)时,self等于obj1
当执行obj2=Foo('alex', 78)时,self等于obj2

所以,内容其实被封装到了对象 obj1 和 obj2 中,每个对象中都有 name 和 age 属性,在内存里类似于下图来保存。
Python——类(class)的定义及使用_第1张图片
调用被封装的内容时,有两种情况:

  • 通过对象直接调用
  • 通过self间接调用

1、通过对象直接调用被封装的内容
上图展示了对象 obj1 和 obj2 在内存中保存的方式,根据保存格式可以如此调用被封装的内容:对象.属性名

class Foo():
    def __init__(self, name, age):
        #初始化实例属性
        self.name = name
        self.age = age

obj1 = Foo('chengd', 18)
print(obj1.name)    #直接调用obj1对象的name属性
print(obj1.age)    #直接调用obj1对象的age属性

obj2 = Foo('python', 99)
print(obj2.name)
print(obj2.age)

结果:

chengd
18
python
99

2、通过self间接调用被封装的内容
执行类中的方法时,需要通过self间接调用被封装的内容

class Foo:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def detail(self):
        print(self.name)
        print(self.age)

obj1 = Foo('chengd', 18)
obj1.detail()  # Python默认会将obj1传给self参数,即:obj1.detail(obj1),所以,此时方法内部的 self = obj1,即:self.name 是 chengd ;self.age 是 18

obj2 = Foo('python', 99)
obj2.detail()  # Python默认会将obj2传给self参数,即:obj1.detail(obj2),所以,此时方法内部的 self = obj2,即:self.name 是 python ; self.age 是 99

结果:

chengd
18
python
99

综上所述,对于面向对象的封装来说,其实就是使用构造方法将内容封装到对象中,然后通过对象直接或者self间接获取被封装的内容。

将多个函数封装成类的例子
这是多个自定义函数组成的简单游戏代码:

import time, random

# 需要的数据和变量放在开头
player_list = ['【狂血战士】', '【森林箭手】', '【光明骑士】', '【独行剑客】', '【格斗大师】', '【枪弹专家】']
enemy_list = ['【暗黑战士】', '【黑暗弩手】', '【暗夜骑士】', '【嗜血刀客】', '【首席刺客】', '【陷阱之王】']
players = random.sample(player_list, 3)
enemies = random.sample(enemy_list, 3)
player_info = {}
enemy_info = {}


# 随机生成角色的属性
def born_role():
    life = random.randint(100, 180)
    attack = random.randint(30, 50)
    return life, attack


# 生成和展示角色信息
def show_role():
    for i in range(3):
        player_info[players[i]] = born_role()
        enemy_info[enemies[i]] = born_role()

    # 展示我方的3个角色
    print('----------------- 角色信息 -----------------')
    print('你的人物:')
    for i in range(3):
        print('%s  血量:%s  攻击:%s'
              % (players[i], player_info[players[i]][0], player_info[players[i]][1]))
    print('--------------------------------------------')
    print('电脑敌人:')

    # 展示敌方的3个角色
    for i in range(3):
        print('%s  血量:%s  攻击:%s'
              % (enemies[i], enemy_info[enemies[i]][0], enemy_info[enemies[i]][1]))
    print('--------------------------------------------')
    input('请按回车键继续。\n')  # 为了让玩家更有控制感,可以插入类似的代码来切分游戏进程。
    return

# 角色排序,选择出场顺序。
def order_role():
    global players
    order_dict = {}
    for i in range(3):
        order = int(input('你想将 %s 放在第几个上场?(输入数字1~3)' % players[i]))
        order_dict[order] = players[i]

    players = []
    for i in range(1, 4):
        players.append(order_dict[i])

    print('\n我方角色的出场顺序是:%s、%s、%s' % (players[0], players[1], players[2]))
    print('敌方角色的出场顺序是:%s、%s、%s' % (enemies[0], enemies[1], enemies[2]))
    return

# 角色PK
def pk_role():
    round = 1
    score = 0
    for i in range(3):  # 一共要打三局
        player_name = players[i]
        enemy_name = enemies[i]
        player_life = player_info[players[i]][0]
        player_attack = player_info[players[i]][1]
        enemy_life = enemy_info[enemies[i]][0]
        enemy_attack = enemy_info[enemies[i]][1]

        # 每一局开战前展示战斗信息
        print('\n----------------- 【第%s局】 -----------------' % round)
        print('玩家角色:%s vs 敌方角色:%s ' % (player_name, enemy_name))
        print('%s 血量:%s  攻击:%s' % (player_name, player_life, player_attack))
        print('%s 血量:%s  攻击:%s' % (enemy_name, enemy_life, enemy_attack))
        print('--------------------------------------------')
        input('请按回车键继续。\n')

        # 开始判断血量是否都大于零,然后互扣血量。
        while player_life > 0 and enemy_life > 0:
            enemy_life = enemy_life - player_attack
            player_life = player_life - enemy_attack
            print('%s发起了攻击,%s剩余血量%s' % (player_name, enemy_name, enemy_life))
            print('%s发起了攻击,%s剩余血量%s' % (enemy_name, player_name, player_life))
            print('--------------------------------------------')
            time.sleep(1)
        else:  # 每局的战果展示,以及分数score和局数的变化。
            # 调用show_result()函数,打印返回元组中的result。
            print(show_result(player_life, enemy_life)[1])
            # 调用show_result()函数,完成计分变动。
            score += int(show_result(player_life, enemy_life)[0])
            round += 1
    input('\n点击回车,查看比赛的最终结果\n')

    if score > 0:
        print('【最终结果:你赢了!】\n')
    elif score < 0:
        print('【最终结果:你输了!】\n')
    else:
        print('【最终结果:平局!】\n')
    return 

# 返回单局战果和计分法所加分数。
def show_result(player_life, enemy_life):  # 注意:该函数要设定参数,才能判断单局战果。
    if player_life > 0 and enemy_life <= 0:
        result = '\n敌人死翘翘了,你赢了!'
        return 1, result  # 返回元组(1,'\n敌人死翘翘了,你赢了!'),类似角色属性的传递。
    elif player_life <= 0 and enemy_life > 0:
        result = '\n悲催,敌人把你干掉了!'
        return -1, result
    else:
        result = '\n哎呀,你和敌人同归于尽了!'
        return 0, result


# (主函数)展开战斗流程
def main():
    show_role()  # 生成和展示角色信息
    order_role()  # 角色排序,选择出场顺序
    pk_role()  # 完成角色PK,并展示PK结果


# 启动程序(即调用主函数)
main()

运行结果:

----------------- 角色信息 -----------------
你的人物:
【枪弹专家】  血量:163  攻击:50
【光明骑士】  血量:119  攻击:37
【森林箭手】  血量:139  攻击:39
--------------------------------------------
电脑敌人:
【嗜血刀客】  血量:110  攻击:38
【暗夜骑士】  血量:115  攻击:50
【黑暗弩手】  血量:151  攻击:40
--------------------------------------------
请按回车键继续。

你想将 【枪弹专家】 放在第几个上场?(输入数字1~3)3
你想将 【光明骑士】 放在第几个上场?(输入数字1~3)1
你想将 【森林箭手】 放在第几个上场?(输入数字1~3)2

我方角色的出场顺序是:【光明骑士】、【森林箭手】、【枪弹专家】
敌方角色的出场顺序是:【嗜血刀客】、【暗夜骑士】、【黑暗弩手】

----------------- 【第1局】 -----------------
玩家角色:【光明骑士】 vs 敌方角色:【嗜血刀客】 
【光明骑士】 血量:119  攻击:37
【嗜血刀客】 血量:110  攻击:38
--------------------------------------------
请按回车键继续。

【光明骑士】发起了攻击,【嗜血刀客】剩余血量73
【嗜血刀客】发起了攻击,【光明骑士】剩余血量81
--------------------------------------------
【光明骑士】发起了攻击,【嗜血刀客】剩余血量36
【嗜血刀客】发起了攻击,【光明骑士】剩余血量43
--------------------------------------------
【光明骑士】发起了攻击,【嗜血刀客】剩余血量-1
【嗜血刀客】发起了攻击,【光明骑士】剩余血量5
--------------------------------------------

敌人死翘翘了,你赢了!

----------------- 【第2局】 -----------------
玩家角色:【森林箭手】 vs 敌方角色:【暗夜骑士】 
【森林箭手】 血量:139  攻击:39
【暗夜骑士】 血量:115  攻击:50
--------------------------------------------
请按回车键继续。

【森林箭手】发起了攻击,【暗夜骑士】剩余血量76
【暗夜骑士】发起了攻击,【森林箭手】剩余血量89
--------------------------------------------
【森林箭手】发起了攻击,【暗夜骑士】剩余血量37
【暗夜骑士】发起了攻击,【森林箭手】剩余血量39
--------------------------------------------
【森林箭手】发起了攻击,【暗夜骑士】剩余血量-2
【暗夜骑士】发起了攻击,【森林箭手】剩余血量-11
--------------------------------------------

哎呀,你和敌人同归于尽了!

----------------- 【第3局】 -----------------
玩家角色:【枪弹专家】 vs 敌方角色:【黑暗弩手】 
【枪弹专家】 血量:163  攻击:50
【黑暗弩手】 血量:151  攻击:40
--------------------------------------------
请按回车键继续。

【枪弹专家】发起了攻击,【黑暗弩手】剩余血量101
【黑暗弩手】发起了攻击,【枪弹专家】剩余血量123
--------------------------------------------
【枪弹专家】发起了攻击,【黑暗弩手】剩余血量51
【黑暗弩手】发起了攻击,【枪弹专家】剩余血量83
--------------------------------------------
【枪弹专家】发起了攻击,【黑暗弩手】剩余血量1
【黑暗弩手】发起了攻击,【枪弹专家】剩余血量43
--------------------------------------------
【枪弹专家】发起了攻击,【黑暗弩手】剩余血量-49
【黑暗弩手】发起了攻击,【枪弹专家】剩余血量3
--------------------------------------------

敌人死翘翘了,你赢了!

点击回车,查看比赛的最终结果

【最终结果:你赢了!】

把上面的代码封装成类,只需做这么几件事:
Python——类(class)的定义及使用_第2张图片
上面的代码,我们使用了很多全局变量,这是因为有多个函数都需要使用这些变量。而当这些函数被封装成一个类之后,我们就不必再使用全局变量,直接把它们放在类里面,作为类属性来被不同的类方法调用。

import time,random

# 将变量放在类里面,作为类属性
class Game():
    player_list =  ['【狂血战士】','【森林箭手】','【光明骑士】','【独行剑客】','【格斗大师】','【枪弹专家】']
    enemy_list = ['【暗黑战士】','【黑暗弩手】','【暗夜骑士】','【嗜血刀客】','【首席刺客】','【陷阱之王】']
    player_info = {}
    enemy_info = {}

    # 初始化函数
    def __init__(self):
        # 随机抽取3个角色名形成玩家角色列表和敌人角色列表
        self.players = random.sample(self.player_list,3)
        self.enemies = random.sample(self.enemy_list,3)
        # 然后执行游戏流程的相关函数
        self.show_role()
        self.order_role()
        self.pk_role()

    # 随机生成角色的属性
    def born_role(self):
        life = random.randint(100, 180)
        attack = random.randint(30, 50)
        return life, attack

    # 生成和展示角色信息
    def show_role(self):
        for i in range(3):
            self.player_info[self.players[i]] = self.born_role()
            self.enemy_info[self.enemies[i]] = self.born_role()

        # 展示我方的3个角色
        print('----------------- 角色信息 -----------------')
        print('你的人物:')
        for i in range(3):
            print('%s  血量:%s  攻击:%s'
                  % (self.players[i], self.player_info[self.players[i]][0], self.player_info[self.players[i]][1]))
        print('--------------------------------------------')
        print('电脑敌人:')

        # 展示敌方的3个角色
        for i in range(3):
            print('%s  血量:%s  攻击:%s'
                  % (self.enemies[i], self.enemy_info[self.enemies[i]][0], self.enemy_info[self.enemies[i]][1]))
        print('--------------------------------------------')
        input('请按回车键继续。\n')  # 为了让玩家更有控制感,可以插入类似的代码来切分游戏进程。
        return

    # 角色排序,选择出场顺序。
    def order_role(self):  # 在类方法中加入self作为参数
        order_dict = {}
        for i in range(3):
            order = int(input('你想将 %s 放在第几个上场?(输入数字1~3)' % self.players[i]))
            order_dict[order] = self.players[i]

        self.players = []  # 变量前加上self.其余几处同理
        for i in range(1, 4):
            self.players.append(order_dict[i])

        print('\n我方角色的出场顺序是:%s、%s、%s' % (self.players[0], self.players[1], self.players[2]))
        print('敌方角色的出场顺序是:%s、%s、%s' % (self.enemies[0], self.enemies[1], self.enemies[2]))
        return

    # 角色PK
    def pk_role(self):
        round = 1
        score = 0
        for i in range(3):  # 一共要打三局
            player_name = self.players[i]
            enemy_name = self.enemies[i]
            player_life = self.player_info[self.players[i]][0]
            player_attack = self.player_info[self.players[i]][1]
            enemy_life = self.enemy_info[self.enemies[i]][0]
            enemy_attack = self.enemy_info[self.enemies[i]][1]

            # 每一局开战前展示战斗信息
            print('\n----------------- 【第%s局】 -----------------' % round)
            print('玩家角色:%s vs 敌方角色:%s ' % (player_name, enemy_name))
            print('%s 血量:%s  攻击:%s' % (player_name, player_life, player_attack))
            print('%s 血量:%s  攻击:%s' % (enemy_name, enemy_life, enemy_attack))
            print('--------------------------------------------')
            input('请按回车键继续。\n')

            # 开始判断血量是否都大于零,然后互扣血量。
            while player_life > 0 and enemy_life > 0:
                enemy_life = enemy_life - player_attack
                player_life = player_life - enemy_attack
                print('%s发起了攻击,%s剩余血量%s' % (player_name, enemy_name, enemy_life))
                print('%s发起了攻击,%s剩余血量%s' % (enemy_name, player_name, player_life))
                print('--------------------------------------------')
                time.sleep(1)
            else:  # 每局的战果展示,以及分数score和局数的变化。
                # 调用show_result()函数,打印返回元组中的result。
                print(self.show_result(player_life, enemy_life)[1])
                # 调用show_result()函数,完成计分变动。
                score += int(self.show_result(player_life, enemy_life)[0])
                round += 1
        input('\n点击回车,查看比赛的最终结果\n')

        if score > 0:
            print('【最终结果:你赢了!】\n')
        elif score < 0:
            print('【最终结果:你输了!】\n')
        else:
            print('【最终结果:平局!】\n')
        return

    # 返回单局战果和计分法所加分数。
    def show_result(self, player_life, enemy_life):  # 注意:该函数要设定参数,才能判断单局战果。
        if player_life > 0 and enemy_life <= 0:
            result = '\n敌人死翘翘了,你赢了!'
            return 1, result  # 返回元组(1,'\n敌人死翘翘了,你赢了!'),类似角色属性的传递。
        elif player_life <= 0 and enemy_life > 0:
            result = '\n悲催,敌人把你干掉了!'
            return -1, result
        else:
            result = '\n哎呀,你和敌人同归于尽了!'
            return 0, result

gp = Game()  # 运行游戏

结果:

----------------- 角色信息 -----------------
你的人物:
【森林箭手】  血量:130  攻击:32
【格斗大师】  血量:164  攻击:48
【光明骑士】  血量:142  攻击:42
--------------------------------------------
电脑敌人:
【陷阱之王】  血量:135  攻击:32
【暗夜骑士】  血量:165  攻击:50
【暗黑战士】  血量:141  攻击:44
--------------------------------------------
请按回车键继续。

你想将 【森林箭手】 放在第几个上场?(输入数字1~3)1
你想将 【格斗大师】 放在第几个上场?(输入数字1~3)3
你想将 【光明骑士】 放在第几个上场?(输入数字1~3)2

我方角色的出场顺序是:【森林箭手】、【光明骑士】、【格斗大师】
敌方角色的出场顺序是:【陷阱之王】、【暗夜骑士】、【暗黑战士】

----------------- 【第1局】 -----------------
玩家角色:【森林箭手】 vs 敌方角色:【陷阱之王】 
【森林箭手】 血量:130  攻击:32
【陷阱之王】 血量:135  攻击:32
--------------------------------------------
请按回车键继续。

【森林箭手】发起了攻击,【陷阱之王】剩余血量103
【陷阱之王】发起了攻击,【森林箭手】剩余血量98
--------------------------------------------
【森林箭手】发起了攻击,【陷阱之王】剩余血量71
【陷阱之王】发起了攻击,【森林箭手】剩余血量66
--------------------------------------------
【森林箭手】发起了攻击,【陷阱之王】剩余血量39
【陷阱之王】发起了攻击,【森林箭手】剩余血量34
--------------------------------------------
【森林箭手】发起了攻击,【陷阱之王】剩余血量7
【陷阱之王】发起了攻击,【森林箭手】剩余血量2
--------------------------------------------
【森林箭手】发起了攻击,【陷阱之王】剩余血量-25
【陷阱之王】发起了攻击,【森林箭手】剩余血量-30
--------------------------------------------

哎呀,你和敌人同归于尽了!

----------------- 【第2局】 -----------------
玩家角色:【光明骑士】 vs 敌方角色:【暗夜骑士】 
【光明骑士】 血量:142  攻击:42
【暗夜骑士】 血量:165  攻击:50
--------------------------------------------
请按回车键继续。

【光明骑士】发起了攻击,【暗夜骑士】剩余血量123
【暗夜骑士】发起了攻击,【光明骑士】剩余血量92
--------------------------------------------
【光明骑士】发起了攻击,【暗夜骑士】剩余血量81
【暗夜骑士】发起了攻击,【光明骑士】剩余血量42
--------------------------------------------
【光明骑士】发起了攻击,【暗夜骑士】剩余血量39
【暗夜骑士】发起了攻击,【光明骑士】剩余血量-8
--------------------------------------------

悲催,敌人把你干掉了!

----------------- 【第3局】 -----------------
玩家角色:【格斗大师】 vs 敌方角色:【暗黑战士】 
【格斗大师】 血量:164  攻击:48
【暗黑战士】 血量:141  攻击:44
--------------------------------------------
请按回车键继续。

【格斗大师】发起了攻击,【暗黑战士】剩余血量93
【暗黑战士】发起了攻击,【格斗大师】剩余血量120
--------------------------------------------
【格斗大师】发起了攻击,【暗黑战士】剩余血量45
【暗黑战士】发起了攻击,【格斗大师】剩余血量76
--------------------------------------------
【格斗大师】发起了攻击,【暗黑战士】剩余血量-3
【暗黑战士】发起了攻击,【格斗大师】剩余血量32
--------------------------------------------

敌人死翘翘了,你赢了!

点击回车,查看比赛的最终结果

【最终结果:平局!】

二、继承

继承,面向对象中的继承和现实生活中的继承相同,即:子可以继承父的内容。
“类的实例化”的格式:
Python——类(class)的定义及使用_第3张图片
这是“初始化函数”的格式:

class():
    def __init__(self):
        print('实例化成功!')

实例 =()

像这样,我们先写出一个类Role(),里面有三个类属性:名称、血量、攻击力。然后用实例化的方法,就可以得到角色的实例,并使用实例.属性的方式提取出每个实例的属性值。不过我们没有对实例的name属性做区别,现在它们都是“普通角色”。

# 创建一个类,可实例化成一个固定的游戏角色
import random

class Role():
    def __init__(self):
        self.name = '【普通角色】'
        self.life = random.randint(100,150)
        self.attack = random.randint(30,50)

a = Role()
print('实例a的角色名称是:'+ a.name)
print('实例a的血量是:'+ str(a.life))
print('实例a的攻击力是:' + str(a.attack))

b = Role()
print('实例b的角色名称是:'+ b.name)
print('实例b的血量是:'+ str(b.life))
print('实例b的攻击力是:' + str(b.attack))

c = Role()
print('实例c的角色名称是:'+ c.name)
print('实例c的血量是:'+ str(c.life))
print('实例c的攻击力是:' + str(c.attack))

结果:

实例a的角色名称是:【普通角色】
实例a的血量是:120
实例a的攻击力是:36
实例b的角色名称是:【普通角色】
实例b的血量是:101
实例b的攻击力是:47
实例c的角色名称是:【普通角色】
实例c的血量是:106
实例c的攻击力是:32

写出三个角色的类,其中属性差异如下:

class Role(): 
# 父类 “【普通角色】”
# 随机生成血量和攻击

class Knight(Role): 
# 子类 “【圣光骑士】” (英文是Knight)
# 血量是随机数的5倍大小,攻击力是随机数的3倍大小

class Assassin(Role):
# 子类 “【暗影刺客】” (英文是Assassin)
# 血量是随机数的3倍大小,攻击力是随机数的5倍大小

class Bowman(Role):
# 子类 “【精灵弩手】” (英文是Bowman)
# 血量是随机数的4倍大小,攻击力是随机数的4倍大小

根据上面的属性差异,写出三个子类,并把每个角色的类属性也打印出来
在这里,每个子类都重写了一遍初始化函数,把角色名、血量、攻击力做出了区分。例如self.name = ‘【圣光骑士】’,是区分了子类的名称,而self.life = random.randint(100,150)*5代表5倍血量。
这样做,我们就既保证了血量和攻击力是随机数,又保证了在不同类型的角色中,血量和攻击力是有差异的。

import random

class Role():
    def __init__(self):
        self.name = '【普通角色】'
        self.life = random.randint(100,150)
        self.attack = random.randint(30,50)

class Knight(Role):
    def __init__(self):
        self.name = '【圣光骑士】'
        self.life = random.randint(100,150)*5
        self.attack = random.randint(30,50)*3

class Assassin(Role):
    def __init__(self):
        self.name = '【暗影刺客】'
        self.life = random.randint(100, 150) * 3
        self.attack = random.randint(30, 50) * 5

class Bowman(Role):
    def __init__(self):
        self.name = '【精灵弩手】'
        self.life = random.randint(100, 150) * 4
        self.attack = random.randint(30, 50) * 4

a = Role()
print(a.name + '的血量是' + str(a.life) + ';攻击力是' + str(a.attack))

b = Knight()
print(b.name + '的血量是' + str(b.life) + ';攻击力是' + str(b.attack))

c = Assassin()
print(c.name + '的血量是' + str(c.life) + ';攻击力是' + str(c.attack))

d = Bowman()
print(d.name + '的血量是' + str(d.life) + ';攻击力是' + str(d.attack))

结果:

【普通角色】的血量是112;攻击力是45
【圣光骑士】的血量是630;攻击力是135
【暗影刺客】的血量是366;攻击力是155
【精灵弩手】的血量是440;攻击力是156

改进:

import random

class Role():
    def __init__(self, name='【角色】'):  # 把角色名作为默认参数
        self.name = name
        self.life = random.randint(100,150)
        self.attack = random.randint(30,50)

# 创建三个子类,可实例化为3个不同类型的角色
class Knight(Role):
    def __init__(self, name='【圣光骑士】'):   # 把子类角色名作为默认参数
        Role.__init__(self,name)  # 利用了父类的初始化函数
        self.life = self.life*5  # 骑士有5份血量
        self.attack = self.attack*3    # 骑士有3份攻击力

class Assassin(Role):
    def __init__(self, name='【暗影刺客】'):
        Role.__init__(self, name)  # 利用了父类的初始化函数
        self.life = random.randint(100, 150) * 3
        self.attack = random.randint(30, 50) * 5

class Bowman(Role):
    def __init__(self, name='【精灵弩手】'):
        Role.__init__(self, name)  # 利用了父类的初始化函数
        self.life = random.randint(100, 150) * 4
        self.attack = random.randint(30, 50) * 4

a = Role()
b = Knight()
c = Assassin()
d = Bowman()

#我们创建了一个列表把4个实例保存起来,然后用for循环遍历即可。
list1 = [a,b,c,d]
for i in list1:
    print(i.name + '的血量是' + str(i.life) + ';攻击力是' + str(i.attack))

结果:

【角色】的血量是136;攻击力是39
【圣光骑士】的血量是590;攻击力是126
【暗影刺客】的血量是417;攻击力是180
【精灵弩手】的血量是600;攻击力是144

队伍中的角色可以随机生成(也就是队伍中的角色可以重复,比如随机生成三个【暗影刺客】都是合理的)。

import random
import time

# 创建一个类,可实例化成具体的游戏角色
class Role():
    def __init__(self, name='【角色】'):  # 把角色名作为默认参数
        self.name = name
        self.life = random.randint(100, 150)
        self.attack = random.randint(30, 50)

# 创建三个子类,可实例化为3个不同类型的角色
class Knight(Role):
    def __init__(self, name='【圣光骑士】'):  # 把子类角色名作为默认参数
        Role.__init__(self, name)  # 利用了父类的初始化函数
        self.life = self.life * 5  # 骑士有5份血量
        self.attack = self.attack * 3  # 骑士有3份攻击力

class Assassin(Role):
    def __init__(self, name='【暗影刺客】'):
        Role.__init__(self, name)
        self.life = self.life * 3
        self.attack = self.attack * 5

class Bowman(Role):
    def __init__(self, name='【精灵弩手】'):
        Role.__init__(self, name)
        self.life = self.life * 4
        self.attack = self.attack * 4

# 创建一个类,可生成3V3并展示:可分为:欢迎语→随机生成→展示角色
class Game:
    def __init__(self):
        # 初始化各种变量
        self.players = []
        self.enemies = []
        self.score = 0
        # 执行各种游戏函数
        self.game_start()
        self.born_role()
        self.show_role()

    # 欢迎语
    def game_start(self):
        print('------------ 欢迎来到“PK小游戏” ------------')
        print('将自动生成【玩家角色】和【电脑人物】')
        input('请按回车键继续。')
        return

    # 随机生成6个角色
    def born_role(self):
        for i in range(3):
            self.players.append(random.choice([Knight(), Assassin(), Bowman()]))
            self.enemies.append(random.choice([Knight(), Assassin(), Bowman()]))
        return

    # 展示角色
    def show_role(self):
        print('----------------- 角色信息 -----------------')
        print('你的队伍:')
        for i in range(3):
            print('『我方』%s 血量:%s  攻击:%s' %(self.players[i].name, self.players[i].life, self.players[i].attack))
        print('--------------------------------------------')

        print('敌人队伍:')
        for i in range(3):
            print('『敌方』%s 血量:%s  攻击:%s' %(self.enemies[i].name, self.enemies[i].life, self.enemies[i].attack))
        print('--------------------------------------------')
        return

gp = Game()  # 运行游戏

结果:

------------ 欢迎来到“PK小游戏” ------------
将自动生成【玩家角色】和【电脑人物】
请按回车键继续。
----------------- 角色信息 -----------------
你的队伍:
『我方』【精灵弩手】 血量:508  攻击:192
『我方』【精灵弩手】 血量:428  攻击:168
『我方』【圣光骑士】 血量:675  攻击:138
--------------------------------------------
敌人队伍:
『敌方』【暗影刺客】 血量:426  攻击:200
『敌方』【圣光骑士】 血量:725  攻击:117
『敌方』【暗影刺客】 血量:312  攻击:200
--------------------------------------------

这里的代码绝大部分都复用了第一部分封装成Game类的代码,然后在这个基础上又做了两处改变。
第一处改变是把函数拆开,函数拆开后,游戏逻辑会更加清晰:
Python——类(class)的定义及使用_第4张图片
第二处改变是改写了born_role()函数,这也是刚才重点实操练习过的:

# 随机生成6个角色
def born_role(self):
    for i in range(3):
        self.players.append(random.choice([Knight(),Assassin(),Bowman()]))
        self.enemies.append(random.choice([Knight(),Assassin(),Bowman()]))

所以,对于面向对象的继承来说,其实就是将多个类共有的方法提取到父类中,子类仅需继承父类而不必一一实现每个方法。
注:除了子类和父类的称谓,你可能看到过 派生类 和 基类 ,他们与子类和父类只是叫法不同而已。
Python——类(class)的定义及使用_第5张图片
那么问题又来了,多继承呢?

  • 是否可以继承多个类
  • 如果继承的多个类每个类中都定了相同的函数,那么那一个会被使用呢?

1、Python的类可以继承多个类,Java和C#中则只能继承一个类
2、Python的类如果继承了多个类,那么其寻找方法的方式有两种,分别是:深度优先和广度优先

下图中B、C类继承D类,A类继承B、C类。
Python——类(class)的定义及使用_第6张图片

  • 当类是经典类时,多继承情况下,会按照深度优先方式查找
  • 当类是新式类时,多继承情况下,会按照广度优先方式查找

经典类和新式类,从字面上可以看出一个老一个新,新的必然包含了跟多的功能,也是之后推荐的写法,从写法上区分的话,如果当前类或者父类继承了object类,那么该类便是新式类,否则便是经典类。
在这里插入图片描述

  • 经典类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去D类中找,如果D类中么有,则继续去C类中找,如果还是未找到,则报错
  • 新式类:首先去A类中查找,如果A类中没有,则继续去B类中找,如果B类中么有,则继续去C类中找,如果C类中么有,则继续去D类中找,如果还是未找到,则报错

注意:在上述查找过程中,一旦找到,则寻找过程立即中断,便不会再继续找了

三、多态

Pyhon不支持Java和C#这一类强类型语言中多态的写法,但是原生多态,其Python崇尚“鸭子类型”。

class F1:
    pass

class S1(F1):
    def show(self):
        print('S1.show')

class S2(F1):
    def show(self):
        print('S2.show')

# 由于在Java或C#中定义函数参数时,必须指定参数的类型
# 为了让Func函数既可以执行S1对象的show方法,又可以执行S2对象的show方法,所以,定义了一个S1和S2类的父类
# 而实际传入的参数是:S1对象和S2对象

def Func(F1, obj):
    """Func函数需要接收一个F1类型或者F1子类的类型"""
    print(obj.show())

s1_obj = S1()
Func(F1, s1_obj)  # 在Func函数中传入S1类的对象 s1_obj,执行 S1 的show方法,结果:S1.show

s2_obj = S2()
Func(F1, s2_obj)  # 在Func函数中传入Ss类的对象 ss_obj,执行 Ss 的show方法,结果:S2.show

# Python伪代码实现Java或C的多态

结果:

S1.show
None
S2.show
None
class F1:
    pass

class S1(F1):
    def show(self):
        print('S1.show')

class S2(F1):
    def show(self):
        print('S2.show')

def Func(obj):
    print(obj.show())

s1_obj = S1()
Func(s1_obj)

s2_obj = S2()
Func(s2_obj)

# Python “鸭子类型”

结果;

S1.show
None
S2.show
None

总结

以上就是本节对于面向对象初级知识的介绍,总结如下:

  • 面向对象是一种编程方式,此编程方式的实现是基于对 对象 的使用
  • 类 是一个模板,模板中包装了多个“函数”供使用
  • 对象,根据模板创建的实例(即:对象),实例用于调用被包装在类中的函数
  • 面向对象三大特性:封装、继承和多态

类——项目例子

1、猫和老鼠

class Animal():  # 创建一个父类“动物”
    def __init__(self, name='动物'):
        self.name = name
        self.attack = 100  # 动物的攻击力是100

class Cat(Animal):  # 创建一个子类“猫”
    def __init__(self, name='猫'):
        Animal.__init__(self, name)  # 完全继承动物的初始化函数,也就是攻击力还是100

    def fight_buff(self, opponent):  # fight_buff的意思是“战斗强化”,opponent的意思是“对手”
        if opponent.name == '老鼠':
            self.attack = int(self.attack * 1.5)

class Rat(Animal):  # 创建一个子类“老鼠”
    def __init__(self, name='老鼠'):
        Animal.__init__(self, name)  # 完全继承动物的初始化函数,也就是攻击力还是100

class Monkey(Animal):  # 创建一个子类“猴子”
    def __init__(self, name='猴子'):
        Animal.__init__(self, name)  # 完全继承动物的初始化函数,也就是攻击力还是100

Tom = Cat()  # 实例化一只叫做Tom的猫
Jerry = Rat()  # 实例化一只叫做Jerry的老鼠
Bobo = Monkey()  # 实例化一只叫做Bobo的猴子

print('猫的攻击力是:')
print(Tom.attack)

Tom.fight_buff(Jerry)
print('遇到老鼠,猫的攻击力是:')
print(Tom.attack)

Tom.fight_buff(Bobo)
print('遇到猴子,猫的攻击力是:')
print(Tom.attack)

结果:

猫的攻击力是:
100
遇到老鼠,猫的攻击力是:
150
遇到猴子,猫的攻击力是:
150

上面代码的关键是新增了一个类方法fight_buff(),这个函数需要接受一个参数opponent,也就是战斗对手的实例对象。
然后在函数中用opponent.name可以把对手的名称给提取出来,并用条件判断,如果对手的名称是’老鼠’,那就给自己的攻击力重新赋值为1.5倍(也就是增加了50%攻击力)

2、游戏角色互相PK
Python——类(class)的定义及使用_第7张图片
游戏可以在开始前调用角色子类对应的fight_buff()实例方法,从而获得攻击力加成,实现属性克制功能!

import random
import time

# 创建一个类,可实例化成具体的游戏角色
class Role:
    def __init__(self, name='【角色】'):  # 把角色名作为默认参数
        self.name = name
        self.life = random.randint(100, 150)
        self.attack = random.randint(30, 50)

# 创建3个子类,可实例化为3个不同的职业
class Knight(Role):
    def __init__(self, name='【圣光骑士】'):  # 把子类角色名作为默认参数
        Role.__init__(self, name)  # 利用了父类的初始化函数
        self.life = self.life * 5  # 骑士有5份血量
        self.attack = self.attack * 3  # 骑士有3份攻击力

    # 职业克制关系
    def fight_buff(self, opponent, str1, str2):
        if opponent.name == '【暗影刺客】':
            self.attack = int(self.attack * 1.5)
            print('『%s』【圣光骑士】对 『%s』【暗影刺客】说:“让无尽光芒制裁你的堕落!”' % (str1, str2))

class Assassin(Role):
    def __init__(self, name='【暗影刺客】'):
        Role.__init__(self, name)
        self.life = self.life * 3
        self.attack = self.attack * 5

    # 职业克制关系
    def fight_buff(self, opponent, str1, str2):
        if opponent.name == '【精灵弩手】':
            self.attack = int(self.attack * 1.5)
            print('『%s』【暗影刺客】对 『%s』【精灵弩手】说:“主动找死,就别怪我心狠手辣。”' % (str1, str2))

class Bowman(Role):
    def __init__(self, name='【精灵弩手】'):
        Role.__init__(self, name)
        self.life = self.life * 4
        self.attack = self.attack * 4

    # 职业克制关系
    def fight_buff(self, opponent, str1, str2):
        if opponent.name == '【圣光骑士】':
            self.attack = int(self.attack * 1.5)
            print('『%s』【精灵弩手】对 『%s』【圣光骑士】说:“骑着倔驴又如何?你都碰不到我衣服。”' % (str1, str2))

# 创建一个类,可生成3V3并展示:可分为:欢迎语→随机生成→展示角色
class Game():
    def __init__(self):
        self.players = []  # 存玩家顺序
        self.enemies = []  # 存敌人顺序
        self.score = 0  # 比赛积分
        self.i = 0  # 记轮次
        # 依次执行以下函数
        self.game_start()  # 欢迎语
        self.born_role()  # 随机生成6个角色
        self.show_role()  # 展示角色
        self.order_role()  # 排序并展示
        self.pk_role()  # 让双方 Pk 并展示结果
        self.show_result()  # 展示最终结局

    # 欢迎语
    def game_start(self):
        print('------------ 欢迎来到“炼狱角斗场” ------------')
        print('在昔日的黄昏山脉,奥卢帝国的北境边界上,有传说中的“炼狱角斗场”。')
        print('鲜血与战斗是角斗士的归宿,金钱与荣耀是角斗士的信仰!')
        print('今日,只要你【你的队伍】能取得胜利,你将获得一笔够花500年的财富。')
        time.sleep(2)
        print('将随机生成【你的队伍】和【敌人队伍】!')
        input('\n狭路相逢勇者胜,请按任意键继续。\n')

    # 随机生成6个角色
    def born_role(self):
        for i in range(3):
            self.players.append(random.choice([Knight(), Assassin(), Bowman()]))
            self.enemies.append(random.choice([Knight(), Assassin(), Bowman()]))

    # 展示角色
    def show_role(self):
        print('----------------- 角色信息 -----------------')
        print('你的队伍:')
        for i in range(3):
            print('『我方』%s 血量:%s  攻击:%s' %
                  (self.players[i].name, self.players[i].life, self.players[i].attack))
        print('--------------------------------------------')

        print('敌人队伍:')
        for i in range(3):
            print('『敌方』%s 血量:%s  攻击:%s' %
                  (self.enemies[i].name, self.enemies[i].life, self.enemies[i].attack))
        print('--------------------------------------------')
        input('请按回车键继续。\n')

    # 排序并展示
    def order_role(self):
        order_dict = {}
        for i in range(3):
            order = int(input('你想将 %s 放在第几个上场?(输入数字1~3)' % self.players[i].name))
            order_dict[order] = self.players[i]
        self.players = []
        for i in range(1, 4):
            self.players.append(order_dict[i])
        print('\n你的队伍出场顺序是:%s、%s、%s'
              % (self.players[0].name, self.players[1].name, self.players[2].name))
        print('敌人队伍出场顺序是:%s、%s、%s'
              % (self.enemies[0].name, self.enemies[1].name, self.enemies[2].name))

    # 让双方 Pk 并展示结果
    def pk_role(self):
        for i in range(3):
            print('\n----------------- 【第%s轮】 -----------------' % (i + 1))
            # 每一局开战前加buff
            self.players[i].fight_buff(self.enemies[i], '我方', '敌方')
            self.enemies[i].fight_buff(self.players[i], '敌方', '我方')
            input('\n战斗双方准备完毕,请按回车键继续。')
            print('--------------------------------------------')

            while self.players[i].life > 0 and self.enemies[i].life > 0:
                self.enemies[i].life -= self.players[i].attack
                self.players[i].life -= self.enemies[i].attack
                print('我方%s 发起了攻击,敌方%s 剩余血量 %s' %
                      (self.players[i].name, self.enemies[i].name, self.enemies[i].life))
                print('敌方%s 发起了攻击,我方%s 剩余血量 %s' %
                      (self.enemies[i].name, self.players[i].name, self.players[i].life))
                print('--------------------------------------------')
                time.sleep(1)
            if self.players[i].life <= 0 and self.enemies[i].life > 0:
                print('\n很遗憾,我方%s 挂掉了!' % (self.players[i].name))
                self.score -= 1
            elif self.players[i].life > 0 and self.enemies[i].life <= 0:
                print('\n恭喜,我方%s 活下来了。' % (self.players[i].name))
                self.score += 1
            else:
                print('\n我的天,他们俩都死了啊!')

    # 展示最终结局
    def show_result(self):
        input('\n请按回车查看最终结果。\n')
        if self.score > 0:
            print('【最终结果】\n你赢了,最终的财宝都归你了!')
        elif self.score == 0:
            print('【最终结果】\n你没有胜利,但也没有失败,在夜色中灰溜溜离开了奥卢帝国。')
        else:
            print('【最终结果】\n你输了。炼狱角斗场又多了几具枯骨。')

game = Game()

结果:

------------ 欢迎来到“炼狱角斗场” ------------
在昔日的黄昏山脉,奥卢帝国的北境边界上,有传说中的“炼狱角斗场”。
鲜血与战斗是角斗士的归宿,金钱与荣耀是角斗士的信仰!
今日,只要你【你的队伍】能取得胜利,你将获得一笔够花500年的财富。
将随机生成【你的队伍】和【敌人队伍】!

狭路相逢勇者胜,请按任意键继续。

----------------- 角色信息 -----------------
你的队伍:
『我方』【圣光骑士】 血量:620  攻击:129
『我方』【暗影刺客】 血量:399  攻击:160
『我方』【圣光骑士】 血量:515  攻击:120
--------------------------------------------
敌人队伍:
『敌方』【暗影刺客】 血量:369  攻击:155
『敌方』【精灵弩手】 血量:520  攻击:180
『敌方』【暗影刺客】 血量:411  攻击:205
--------------------------------------------
请按回车键继续。

你想将 【圣光骑士】 放在第几个上场?(输入数字1~3)1
你想将 【暗影刺客】 放在第几个上场?(输入数字1~3)3
你想将 【圣光骑士】 放在第几个上场?(输入数字1~3)2

你的队伍出场顺序是:【圣光骑士】、【圣光骑士】、【暗影刺客】
敌人队伍出场顺序是:【暗影刺客】、【精灵弩手】、【暗影刺客】

----------------- 【第1轮】 -----------------
『我方』【圣光骑士】对 『敌方』【暗影刺客】说:“让无尽光芒制裁你的堕落!”

战斗双方准备完毕,请按回车键继续。
--------------------------------------------
我方【圣光骑士】 发起了攻击,敌方【暗影刺客】 剩余血量 176
敌方【暗影刺客】 发起了攻击,我方【圣光骑士】 剩余血量 465
--------------------------------------------
我方【圣光骑士】 发起了攻击,敌方【暗影刺客】 剩余血量 -17
敌方【暗影刺客】 发起了攻击,我方【圣光骑士】 剩余血量 310
--------------------------------------------

恭喜,我方【圣光骑士】 活下来了。

----------------- 【第2轮】 -----------------
『敌方』【精灵弩手】对 『我方』【圣光骑士】说:“骑着倔驴又如何?你都碰不到我衣服。”

战斗双方准备完毕,请按回车键继续。
--------------------------------------------
我方【圣光骑士】 发起了攻击,敌方【精灵弩手】 剩余血量 400
敌方【精灵弩手】 发起了攻击,我方【圣光骑士】 剩余血量 245
--------------------------------------------
我方【圣光骑士】 发起了攻击,敌方【精灵弩手】 剩余血量 280
敌方【精灵弩手】 发起了攻击,我方【圣光骑士】 剩余血量 -25
--------------------------------------------

很遗憾,我方【圣光骑士】 挂掉了!

----------------- 【第3轮】 -----------------

战斗双方准备完毕,请按回车键继续。
--------------------------------------------
我方【暗影刺客】 发起了攻击,敌方【暗影刺客】 剩余血量 251
敌方【暗影刺客】 发起了攻击,我方【暗影刺客】 剩余血量 194
--------------------------------------------
我方【暗影刺客】 发起了攻击,敌方【暗影刺客】 剩余血量 91
敌方【暗影刺客】 发起了攻击,我方【暗影刺客】 剩余血量 -11
--------------------------------------------

很遗憾,我方【暗影刺客】 挂掉了!

请按回车查看最终结果。

【最终结果】
你输了。炼狱角斗场又多了几具枯骨。

你可能感兴趣的:(Python程序设计小技巧,python)