- 防止私有变量在外部被随意访问和修改,避免写复杂的 setter 和 getter 方法
- 负责把一个方法变成属性调用
- 关键字
@property
@name.setter
class Person:
def __init__(self, name, age):
self._name = name
self._age = age
@property
def name(self):
return self._name
@name.setter
def name(self, age):
self._age = age
def main():
person = Person('Jalan', 18)
person.name = 'Jay'
参考:使用@property
- 限定自定义类型的对象只能绑定某些属性
- 只对当前类的对象生效,对子类并不起任何作用
class Person:
# Person 类只能绑定 _name 和 _age 属性
__slots__ = ('_name', '_age')
众所周知,静态方法属于类而不属于对象。在之前的编程过程中,如果调用一个方法时不想 new 一个对象出来,我就会把它定义成静态方法(粗暴),但始终不知道要定义静态方法的真正时机是什么。
骆昊老师的教程里举了个例子,算是看明白了:
我们写在类中的方法并不需要都是对象方法,例如我们定义一个“三角形”类,通过传入三条边长来构造三角形,并提供计算周长和面积的方法,但是传入的三条边长未必能构造出三角形对象,因此我们可以先写一个方法来验证三条边长是否可以构成三角形,这个方法很显然就不是对象方法,因为在调用这个方法时三角形对象尚未创建出来(因为都不知道三条边能不能构成三角形),所以这个方法是属于三角形类而并不属于三角形对象的。
定义静态方法关键字:@staticmethod
@classmethod
cls
表示类本身- 通过
cls
可以获取和类相关的信息并且可以创建出类的对象
class Clock:
def __init__(self, hour=0, minute=0, second=0):
self._hour = hour
self._minute = minute
self._second = second
@classmethod
def now(cls):
# 返回一个类对象
return cls(1, 2, 3)
- is-a:继承或泛化
- has-a:关联。例如部门和员工的关系
- use-a:依赖。例如方法中使用到某个其他对象
- 子类比父类拥有更多的功能。用子类对象替换一个父类对象,里氏替换原则
- 继承的写法:
class Teacher(Person)
,和其他编程语言不同,没有什么extends
关键字,而是直接在类后的括号里标明所要继承的父类 - 子类对父类已有方法给出新的实现版本:重写(override)。当我们调用这个经过子类重写的方法时,不同的子类对象会表现出不同的行为,这个就是多态(poly-morphism)
- 顺便复习:重载是指相同函数名的不同使用方式,Python 中没有重载
- Python 在语法层面没有像 Java 或 C# 那样提供对抽象类的支持
- 但可以通过 abc 模块的 ABCMeta 元类和 abstractmethod 包装器来达到抽象类的效果
- 如果一个类中存在抽象方法那么这个类就不能够实例化(创建对象)
from abc import ABCMeta, abstractmethod
class Pet(object, metaclass=ABCMeta):
"""宠物"""
def __init__(self, nickname):
self._nickname = nickname
@abstractmethod
def make_voice(self):
"""发出声音"""
pass
class Dog(Pet):
"""狗"""
def make_voice(self):
print('%s: 汪汪汪...' % self._nickname)
class Cat(Pet):
"""猫"""
def make_voice(self):
print('%s: 喵...喵...' % self._nickname)
def main():
pets = [Dog('旺财'), Cat('凯蒂'), Dog('大黄')]
for pet in pets:
# make_voice 表现出了多态行为
pet.make_voice()
if __name__ == '__main__':
main()
大概看了一下代码,描述一下这个案例。
首先需要定义一个攻击者类 Fighter
,奥特曼和小怪兽都是攻击者。攻击者的基本属性有姓名 name
和生命值 hp
。
- 奥特曼:
- 90% 概率使用普通攻击。普通攻击打一拳 hp-10
- 10% 概率使用魔法攻击,但魔法攻击需要蓄力,蓄力值达到 100 才可以发动。每回合可以恢复蓄力值 10 点。魔法攻击打一拳 hp-50
- 小怪兽:
- 只会普通攻击,每一回合结束奥特曼会被所有小怪兽打一拳,打一拳 hp-5
- 琦玉老师:
- 每回合除奥特曼出击外有 1% 的概率召唤琦玉老师,一拳解决一只小怪兽
"""
奥特曼打小怪兽
Version: 1.0.0
Author: Jalan
Date: 2019-05-25
"""
from abc import ABCMeta, abstractclassmethod
from random import randint, randrange
import time
class Fighter(metaclass=ABCMeta):
"""
攻击者
"""
__slots__ = ('_name', '_hp')
def __init__(self, name, hp):
"""
初始化攻击者
:param name: 攻击者姓名
:param hp: 攻击者 hp
"""
self._name = name
self._hp = hp
@property
def name(self):
return self._name
@property
def hp(self):
return self._hp
@hp.setter
def hp(self, hp):
self._hp = hp if hp > 0 else 0
def is_alive(self):
"""
判断是否存活
:return 如果存活返回 True,否则返回 False
"""
return True if self._hp > 0 else False
@abstractclassmethod
def attack(self, other):
"""
普通攻击
:param other: 攻击对象
"""
pass
class Ultraman(Fighter):
"""
奥特曼
"""
__slots__ = ('_name', '_hp', '_mp')
def __init__(self, name, hp):
"""
初始化奥特曼
:param name: 奥特曼名字
:param hp: 奥特曼 hp
:param mp: 奥特曼魔法蓄力值
"""
super().__init__(name, hp)
self._mp = 100
def attack(self, other):
"""
普通攻击一拳 -10
"""
num = randint(1, 10)
if num == 1:
self._magic_attack(other)
else:
other.hp -= 10
def _magic_attack(self, other):
"""
魔法攻击
:param other: 攻击对象
"""
if self._mp == 100:
other.hp -= 50
return True
else:
return False
def resume_mp(self):
"""
恢复 mp
"""
if self._mp < 100:
self._mp += 10
def __str__(self):
return '奥特曼 %s 生命值 %s' % (self._name, self._hp)
class OnePunchMan(Fighter):
"""
琦玉老师
"""
__slots__ = ('_name', '_hp')
def __init__(self, name):
"""
初始化一个一拳超人
"""
self._name = name
self._hp = float('inf')
def attack(self, other):
"""
一拳打死
:param other: 攻击对象
"""
other._hp = 0
def __str__(self):
return '琦玉老师出场'
class Monster(Fighter):
"""
小怪兽
"""
__slots__ = ('_name', '_hp', '_hurt')
def __init__(self, name, hp):
"""
初始化小怪兽
"""
self._name = name
self._hp = hp
def attack(self, other):
"""
普通攻击
"""
other.hp -= 5
def __str__(self):
return '小怪兽 %s 生命值 %s' % (self._name, self._hp)
def is_any_alive(monsters):
"""
是否还有小怪兽存活
:return 是返回 True,否返回 False
"""
for monster in monsters:
if monster.is_alive:
return True
return False
def select_monster(monsters):
"""
选择一只小怪兽
:return 返回小怪兽
"""
monsters_len = len(monsters)
while True:
index = randrange(monsters_len)
monster = monsters[index]
if monster.is_alive:
return monster
def main():
u = Ultraman('迪迦', 500)
m1 = Monster('小龙虾', 100)
m2 = Monster('大螃蟹', 120)
m3 = Monster('老乌龟', 200)
monsters = [m1, m2, m3]
one = OnePunchMan('琦玉老师')
while u.is_alive and is_any_alive(monsters):
target = select_monster(monsters)
# 小怪兽被打
u.attack(target)
# 小怪兽打奥特曼
for monster in monsters:
if monster.is_alive:
monster.attack(u)
# 判断是否可以召唤琦玉老师
one_punc_num = randint(1, 100)
if one_punc_num == 1 and is_any_alive(monsters):
target = select_monster(monsters)
one.attack(target)
print(one)
print(target)
print(u)
time.sleep(2)
if __name__ == "__main__":
main()