Lesson 12

  • Python Begginer, Level 2, Lesson 12, v1.0.0, 2016.12 by David.Yi
  • v1.1, 2020.5.4 edit by David Yi

本次内容要点

  • 面向对象的编程之三
    • 更加优雅的程序设计思路
    • 类方法
    • 静态方法

In [1]:
# 修改战斗的输出,战斗不能只喊喊口号,需要对对方有输出,
# 在 NPC 的 fight_common() 中我们设计返回值表示输出
# 再在主程序中增加一个 调用 soldier 的 fight_common(),来检查输出
# v1.0.6

# NPC 类
class NPC(object):
    
    # 初始化 NPC 的属性
    def __init__(self, name):
        self.name = name
        
        self.npc_type = type(self).__name__
        
        print('')
        print(self.npc_type, 'NPC created!')
        
        if self.npc_type == 'Soldier':
            self.weapon = 'gun'
            self.blood = 1000
            
        if self.npc_type == 'Wizard':
            self.weapon = 'short gun'
            self.blood = 2000
        
        
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        print('name:', self.name)
        print('weapon:', self.weapon)
        print('blood:', self.blood)
    
    # 定义方法 - 通用攻击
    def fight_common(self):
        print('Fight Common')
        output = {'blood': -100}
        return output
        
# 战士 Soldier 类
class Soldier(NPC):
    
    # 建立 soldier 的初始化
    def __init__(self, name):
        # 调用 父类 NPC 的初始化方法
        NPC.__init__(self, name)
        
        # soldier 自己的初始化
        self.soldier_level = 1
        
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        # 通过 super 来调用父类方法
        super(Soldier, self).show_properties()
        print('soldier_level', self.soldier_level)
        
# 巫师 Wizard 类
class Wizard(NPC):
    
    # 建立 Wizard 的初始化
    def __init__(self, name):
        # 调用 父类 NPC 的初始化方法
        NPC.__init__(self, name)
        
        # soldier 自己的初始化
        self.wizard_level = 1
        
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        # 通过 super 来调用父类方法
        super(Wizard, self).show_properties()
        print('wizard_level', self.wizard_level)
    
    # 定义一个巫师专用的战斗方法
    def fight_magic(self):
        print('Wizard Magic!')

s = []

for i in range(2):
    n = Soldier('AA' + str(i))
    n.show_properties()
    s.append(n)
    
for i in range(2):
    n = Wizard('CC' + str(i))
    n.show_properties()
    s.append(n)

print('\nBegin Fighting')
print(s[1].fight_common())


Soldier NPC created!
name: AA0
weapon: gun
blood: 1000
soldier_level 1

Soldier NPC created!
name: AA1
weapon: gun
blood: 1000
soldier_level 1

Wizard NPC created!
name: CC0
weapon: short gun
blood: 2000
wizard_level 1

Wizard NPC created!
name: CC1
weapon: short gun
blood: 2000
wizard_level 1

Begin Fighting
Fight Common
{'blood': -100}

In [1]:
# 进一步优化
# 在 soldier 中增加专门的战斗方式
# soldier 和 wizard 的战斗中都增加输出
# v1.0.7

# NPC 类
class NPC(object):
    
    # 初始化 NPC 的属性
    def __init__(self, name):
        self.name = name
        
        self.npc_type = type(self).__name__
        
        print('')
        print(self.npc_type, 'NPC created!')
        
        if self.npc_type == 'Soldier':
            self.weapon = ' sword'
            self.blood = 1000
            
        if self.npc_type == 'Wizard':
            self.weapon = 'staff'
            self.blood = 800
        
        
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        print('name:', self.name)
        print('weapon:', self.weapon)
        print('blood:', self.blood)
    
    # 定义方法 - 通用攻击
    def fight_common(self):
        print('Fight Common')
        output = {'blood': -100}
        return output
        
# 战士 Soldier 类
class Soldier(NPC):
    
    # 建立 soldier 的初始化
    def __init__(self, name):
        # 调用 父类 NPC 的初始化方法
        NPC.__init__(self, name)
        
        # soldier 自己的初始化
        self.soldier_level = 1
        
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        # 通过 super 来调用父类方法
        super(Soldier, self).show_properties()
        print('soldier_level', self.soldier_level)
    
    # soldier 自己的战斗方法
    def fight_shoot(self):
        print('Soldier Attack!')
        output = {'blood': -200}
        return output
        
        
# 巫师 Wizard 类
class Wizard(NPC):
    
    # 建立 Wizard 的初始化
    def __init__(self, name):
        # 调用 父类 NPC 的初始化方法
        NPC.__init__(self, name)
        
        # soldier 自己的初始化
        self.wizard_level = 1
        
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        # 通过 super 来调用父类方法
        super(Wizard, self).show_properties()
        print('wizard_level', self.wizard_level)
    
    # 定义一个巫师专用的战斗方法
    def fight_magic(self):
        print('Wizard Magic!')
        output = {'blood': -300}
        return output

# 执行代码    
    
s = []

for i in range(2):
    n = Soldier('AA' + str(i))
    n.show_properties()
    s.append(n)
    
for i in range(2):
    n = Wizard('CC' + str(i))
    n.show_properties()
    s.append(n)

print('\nBegin Fighting')
# 测试一下各类进攻方式
print(s[1].fight_common())
print(s[1].fight_shoot())
print(s[2].fight_magic())


Soldier NPC created!
name: AA0
weapon:  sword
blood: 1000
soldier_level 1

Soldier NPC created!
name: AA1
weapon:  sword
blood: 1000
soldier_level 1

Wizard NPC created!
name: CC0
weapon: staff
blood: 800
wizard_level 1

Wizard NPC created!
name: CC1
weapon: staff
blood: 800
wizard_level 1

Begin Fighting
Fight Common
{'blood': -100}
Soldier Attack!
{'blood': -200}
Wizard Magic!
{'blood': -300}

In [4]:
# 进一步优化
# 将子类中的 show_properties 去除,显示不同的 level 功能放到 NPC 类中
# 修改子类中的 solider_level 和 wizard_level 统一为 level,也放到 NPC 类中
# v1.0.8

# NPC 类
class NPC(object):
    
    # 初始化 NPC 的属性
    def __init__(self, name):
        self.name = name
        
        self.npc_type = type(self).__name__
        
        print('')
        print(self.npc_type, 'NPC created!')
        
        # 初始化值统一放在 NPC 类中
        if self.npc_type == 'Soldier':
            self.weapon = 'sword'
            self.blood = 1000
            self.level = 1 
            
        if self.npc_type == 'Wizard':
            self.weapon = 'staff'
            self.blood = 800
            self.level = 1
               
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        print('name:', self.name)
        print('weapon:', self.weapon)
        print('blood:', self.blood)
        print('level:', self.level)
    
    # 定义方法 - 通用攻击
    def fight_common(self):
        print('Fight Common')
        output = {'blood': -100}
        return output
        
# 战士 Soldier 类
class Soldier(NPC):
            
    # soldier 自己的战斗方法
    def fight_shoot(self):
        print('Soldier Attack!')
        output = {'blood': -200}
        return output
        
        
# 巫师 Wizard 类
class Wizard(NPC):
    
    # 定义一个巫师专用的战斗方法
    def fight_magic(self):
        print('Wizard Magic!')
        output = {'blood': -300}
        return output

# 执行代码
    
s = []

for i in range(2):
    n = Soldier('AA' + str(i))
    n.show_properties()
    s.append(n)
    
for i in range(2):
    n = Wizard('CC' + str(i))
    n.show_properties()
    s.append(n)

print('\nBegin Fighting')
print(s[1].fight_common())
print(s[1].fight_shoot())
print(s[2].fight_magic())


Soldier NPC created!
name: AA0
weapon: sword
blood: 1000
level: 1

Soldier NPC created!
name: AA1
weapon: sword
blood: 1000
level: 1

Wizard NPC created!
name: CC0
weapon: staff
blood: 800
level: 1

Wizard NPC created!
name: CC1
weapon: staff
blood: 800
level: 1

Begin Fighting
Fight Common
{'blood': -100}
Soldier Attack!
{'blood': -200}
Wizard Magic!
{'blood': -300}

程序是否功能越来越强大,但是也很简洁,并且很容易扩充功能?这就是面向对象编程思想的好处和强大能力!

思考一下

  • 给 NPC 增加一个 MagicPoint MP 值,应该怎么操作?
  • 考虑程序的发展,如果把武器 weapon 和伤害值不固定写死在类中比较好,应该怎么操作?

我们还可以继续来增强功能

  • 引入类方法,来简化不同子类继承后进行的操作
  • 战斗输出放在子对象中,如果我们要修改输出值的话,有点不方便,我们引入类方法

类方法和静态方法

  • 类方法是为了访问类属性更加方便
  • 类方法和静态方法可以通过类和实例来访问,效果是相同的
  • 静态方法跟普通函数没有什么区别

In [16]:
# 进一步优化
# 引入类方法,修改 NPC类的 fight_common() 来完成统一的并且能区分角色的战斗输出
# v1.0.9

# NPC 类
class NPC(object):
    
    # 初始化 NPC 的属性
    def __init__(self, name):
        self.name = name
        
        self.npc_type = type(self).__name__
        
        print('')
        print(self.npc_type, 'NPC created!')
        
        # 初始化值统一放在 NPC 类中
        if self.npc_type == 'Soldier':
            self.weapon = 'sword'
            self.blood = 1000
            self.level = 1 
            
        if self.npc_type == 'Wizard':
            self.weapon = 'staff'
            self.blood = 800
            self.level = 1
               
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        print('name:', self.name)
        print('weapon:', self.weapon)
        print('blood:', self.blood)
        print('level:', self.level)
    
    # 定义方法 - 通用攻击
    # 使用类方法,传入的参数是 class,因此通过 class的 name 来获得具体名称
    @classmethod
    def fight_common(cls):
        print(cls.__name__, 'Fight Common')
        output = {'blood': -100}
        return output
        
# 战士 Soldier 类
class Soldier(NPC):
            
    # soldier 自己的战斗方法
    def fight_shoot(self):
        print('Soldier Attack!')
        output = {'blood': -200}
        return output
        
        
# 巫师 Wizard 类
class Wizard(NPC):
    
    # 定义一个巫师专用的战斗方法
    def fight_magic(self):
        print('Wizard Magic!')
        output = {'blood': -300}
        return output

# 执行代码
    
s = []

for i in range(2):
    n = Soldier('AA' + str(i))
    n.show_properties()
    s.append(n)
    
for i in range(2):
    n = Wizard('CC' + str(i))
    n.show_properties()
    s.append(n)


print('\nBegin Fighting:')
print(s[1].fight_common())
print(s[1].fight_shoot())
print(s[2].fight_common())
print(s[2].fight_magic())


Soldier NPC created!
name: AA0
weapon: sword
blood: 1000
level: 1

Soldier NPC created!
name: AA1
weapon: sword
blood: 1000
level: 1

Wizard NPC created!
name: CC0
weapon: staff
blood: 800
level: 1

Wizard NPC created!
name: CC1
weapon: staff
blood: 800
level: 1

Begin Fighting:
Soldier Fight Common
{'blood': -100}
Soldier Attack!
{'blood': -200}
Wizard Fight Common
{'blood': -100}
Wizard Magic!
{'blood': -300}

In [60]:
# 进一步优化
# 将 NPC 对不同角色的初始化值从对象定义代码中剥离,便于调整数值
# v1.0.10

# npc 的属性字典
npc_dict = {'Soldier':{'weapon':'sword', 'blood':1000, 'level':1}, 'Wizard':{'weapon':'staff', 'blood':800, 'level':1}}

# NPC 类
class NPC(object):
    
    # 初始化 NPC 的属性
    def __init__(self, name):
        self.name = name
        
        self.npc_type = type(self).__name__
        
        print('')
        print(self.npc_type, 'NPC created!')
        
        # 初始化值统一放在 NPC 类中
        # 从 npc_dict 中读出
        # weapon_list 保存武器内容
        self.weapon = npc_dict.get(self.npc_type).get('weapon')
        self.blood = npc_dict.get(self.npc_type).get('blood')
        self.level = npc_dict.get(self.npc_type).get('level')
               
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        print('name:', self.name)
        print('weapon:', self.weapon)
        print('blood:', self.blood)
        print('level:', self.level)
    
    # 定义方法 - 通用攻击
    # 使用类方法,传入的参数是 class,因此通过 class的 name 来获得具体名称
    @classmethod
    def fight_common(cls):
        print(cls.__name__, 'Fight Common')
        output = {'blood': -100}
        return output
        
# 战士 Soldier 类
class Soldier(NPC):
            
    # soldier 自己的战斗方法
    def fight_shoot(self):
        print('Soldier Attack!')
        output = {'blood': -200}
        return output
        
        
# 巫师 Wizard 类
class Wizard(NPC):
    
    # 定义一个巫师专用的战斗方法
    def fight_magic(self):
        print('Wizard Magic!')
        output = {'blood': -300}
        return output

# 执行代码
    
s = []

for i in range(2):
    n = Soldier('AA' + str(i))
    n.show_properties()
    s.append(n)
    
for i in range(2):
    n = Wizard('CC' + str(i))
    n.show_properties()
    s.append(n)


print('\nBegin Fighting:')
print(s[1].fight_common())
print(s[1].fight_shoot())
print(s[2].fight_common())
print(s[2].fight_magic())


Soldier NPC created!
name: AA0
weapon: sword
blood: 1000
level: 1

Soldier NPC created!
name: AA1
weapon: sword
blood: 1000
level: 1

Wizard NPC created!
name: CC0
weapon: staff
blood: 800
level: 1

Wizard NPC created!
name: CC1
weapon: staff
blood: 800
level: 1

Begin Fighting:
Soldier Fight Common
{'blood': -100}
Soldier Attack!
{'blood': -200}
Wizard Fight Common
{'blood': -100}
Wizard Magic!
{'blood': -300}

In [58]:
# 进一步优化
# 将战斗输出的值修改为从外部数据读入
# 战斗的方法的名称修改
# v1.0.11

# npc 的属性字典
npc_dict = {'soldier':{'weapon':'sword', 'blood':1000, 'level':1}, 'wizard':{'weapon':'staff', 'blood':800, 'level':1}}
# fight output 字典
fight_output_dict = {'fight_common':{'name':'Fight Common','blood':-100}, 
                    'sword_fight':{'name':'Sword Fight!','blood':-200},
                    'staff_magic':{'name':'Staff Magic!','blood':-300}}

# NPC 类
class NPC(object):
    
    # 初始化 NPC 的属性
    def __init__(self, name):
        self.name = name
        
        # 将类名称转换为全部小写
        self.npc_type = (type(self).__name__).lower()
        
        print('')
        print(self.npc_type, 'NPC created!')
        
        # 初始化值统一放在 NPC 类中
        # 从 npc_dict 中读出
        # weapon_list 保存武器内容
        self.weapon = npc_dict.get(self.npc_type).get('weapon')
        self.blood = npc_dict.get(self.npc_type).get('blood')
        self.level = npc_dict.get(self.npc_type).get('level')
               
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        print('name:', self.name)
        print('weapon:', self.weapon)
        print('blood:', self.blood)
        print('level:', self.level)
    
    # 定义方法 - 通用攻击
    # fight 的内容从外部读入
    @classmethod
    def fight_common(cls):
        print(cls.__name__, fight_output_dict.get('fight_common').get('name'))
        output = fight_output_dict.get('fight_common').get('blood')
        return ('blood',output)
        
# 战士 Soldier 类
class Soldier(NPC):
            
    # soldier 自己的战斗方法
    def sword_fight(self):
        print('Fight', fight_output_dict.get('sword_fight').get('name'))
        output = fight_output_dict.get('sword_fight').get('blood')
        return ('blood',output)
        
        
# 巫师 Wizard 类
class Wizard(NPC):
    
    # 定义一个巫师专用的战斗方法
    def staff_magic(self):
        print('Wizard', fight_output_dict.get('staff_magic').get('name'))
        output = fight_output_dict.get('staff_magic').get('blood')
        return ('blood',output)

# 执行代码
    
s = []

for i in range(2):
    n = Soldier('AA' + str(i))
    n.show_properties()
    s.append(n)
    
for i in range(2):
    n = Wizard('CC' + str(i))
    n.show_properties()
    s.append(n)


print('\nBegin Fighting:')
print(s[1].fight_common())
print(s[1].sword_fight())
print(s[2].fight_common())
print(s[2].staff_magic())


soldier NPC created!
name: AA0
weapon: sword
blood: 1000
level: 1

soldier NPC created!
name: AA1
weapon: sword
blood: 1000
level: 1

wizard NPC created!
name: CC0
weapon: staff
blood: 800
level: 1

wizard NPC created!
name: CC1
weapon: staff
blood: 800
level: 1

Begin Fighting:
Soldier Fight Common
('blood', -100)
Fight Sword Fight!
('blood', -200)
Wizard Fight Common
('blood', -100)
Wizard Staff Magic!
('blood', -300)

In [61]:
# 进一步优化
# 战斗输出内容从外部数据读入了,代码就显得很重复,我们继续简化
# 通过 静态方法 fight_output() 
# v1.0.12

# npc 的属性字典
npc_dict = {'soldier':{'weapon':'sword', 'blood':1000, 'level':1}, 'wizard':{'weapon':'staff', 'blood':800, 'level':1}}
# fight output 字典
fight_output_dict = {'fight_common':{'name':'Fight Common','blood':-100}, 
                    'sword_fight':{'name':'Sword Fight!','blood':-200},
                    'staff_magic':{'name':'Staff Magic!','blood':-300}}

# NPC 类
class NPC(object):
        
    # 初始化 NPC 的属性
    def __init__(self, name):
        self.name = name
        
        # 将类名称转换为全部小写
        self.npc_type = (type(self).__name__).lower()
        
        print('')
        print(self.npc_type, 'NPC created!')
        
        # 初始化值统一放在 NPC 类中
        # 从 npc_dict 中读出
        # weapon_list 保存武器内容
        self.weapon =  npc_dict.get(self.npc_type).get('weapon')
        self.blood = npc_dict.get(self.npc_type).get('blood')
        self.level = npc_dict.get(self.npc_type).get('level')
               
    # 定义方法 - 显示 NPC 属性
    def show_properties(self):
        print('name:', self.name)
        print('weapon:', self.weapon)
        print('blood:', self.blood)
        print('level:', self.level)
    
    # 定义方法 - 通用攻击
    # fight 的内容从外部读入
    @classmethod
    def fight_common(cls):
        return (cls.__name__, 'blood' , NPC.fight_output('fight_common'))
    
    # 静态方法 - 战斗输出
    # 从外部数据读入战斗输出的值
    @staticmethod
    def fight_output(fight_type):
        name = fight_output_dict.get(fight_type).get('name')
        output = fight_output_dict.get(fight_type).get('blood')
        return (name,output)  
        
# 战士 Soldier 类
class Soldier(NPC):
            
    # soldier 自己的战斗方法
    def sword_fight(self):
        return ('Soldier', 'blood' , NPC.fight_output('sword_fight'))        
        
# 巫师 Wizard 类
class Wizard(NPC):
    
    # wizard 自己的战斗方法
    def staff_magic(self):
        return ('Wizard', 'blood' , NPC.fight_output('staff_magic')) 

# 执行代码
    
s = []

for i in range(2):
    n = Soldier('AA' + str(i))
    n.show_properties()
    s.append(n)
    
for i in range(2):
    n = Wizard('CC' + str(i))
    n.show_properties()
    s.append(n)


print('\nBegin Fighting:')
print(s[1].fight_common())
print(s[1].sword_fight())
print(s[2].fight_common())
print(s[2].staff_magic())


soldier NPC created!
name: AA0
weapon: sword
blood: 1000
level: 1

soldier NPC created!
name: AA1
weapon: sword
blood: 1000
level: 1

wizard NPC created!
name: CC0
weapon: staff
blood: 800
level: 1

wizard NPC created!
name: CC1
weapon: staff
blood: 800
level: 1

Begin Fighting:
('Soldier', 'blood', ('Fight Common', -100))
('Soldier', 'blood', ('Sword Fight!', -200))
('Wizard', 'blood', ('Fight Common', -100))
('Wizard', 'blood', ('Staff Magic!', -300))