面向对象编程基础
- 类(Class): 用来描述具有相同的属性和方法的对象的集合。它定义了该集合中每个对象所共有的属性和方法。对象是类的实例。
- 类变量:类变量在整个实例化的对象中是公用的。类变量定义在类中且在函数体之外。类变量通常不作为实例变量使用。
- 数据成员:类变量或者实例变量, 用于处理类及其实例对象的相关的数据。
- 方法重写:如果从父类继承的方法不能满足子类的需求,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写。
- 实例变量:定义在方法中的变量,只作用于当前实例的类。
- 继承:即一个派生类(derived class)继承基类(base class)的字段和方法。继承也允许把一个派生类的对象作为一个基类对象对待。
- 实例化:创建一个类的实例,类的具体对象
- 方法:类中定义的函数。
- 对象:通过类定义的数据结构实例。对象包括两个数据成员(类变量和实例变量)和方法。
from time import sleep
class Clock(object):
def __init__ (self,hour=0,minute=0,second=0):
self._hour = hour
self._minute = minute
self._second = second
def run (self):
self._second += 1
if self._second == 60:
self._second = 0
self._minute += 1
if self._minute == 60:
self._minute = 0
self._hour += 1
if self._hour == 24 :
self._hour = 0
def show (self):
return '%02d:%02d:%02d' % (self._hour,self._minute,self._second)
def main():
clock = Clock(23,59,58)
while True:
print(clock.show())
sleep(1)
clock.run()
if __name__ == '__main__':
main()
其中 Clcok就是类,一个模板,抽象的概念,可以理解他为C语言中的结构体变量。
Clock里面的就是模板属性,def 函数就是行为。
clock 就是对象了
除特殊模块 init 之外,模块名称都使用不带下划线的小写字母。
特殊方法 : 小写和两个前导下划线,两个后置下划线
def add(self, other):
return int.add(other)
这种风格只应用于特殊函数,比如操作符重载等。
面向对象进阶
@property 装饰器可以在类外对对象内的属性进行访问,或者操作,getter(访问器),setter(修改器)
slots魔法可以对一些属性和行为进行绑定,或者解绑
在python中用双下划线开头的方式将属性隐藏起来(设置成私有的)
继承与派生,被继承的叫做父类,基类或者超类,,继承的叫做子类了。子类从父类那里继承过来所有的属性和行为,并且可以派生出自己特有的属性和行为。这种继承更多的是一种“是”的关系,例如,人是动物,狗是动物,那么动物就可以被称作为父类,人和狗就被称为子类了。
- 抽象:抽象即抽取类似或者说比较像的部分。是一个从具体到抽象的过程。
- 继承:子类继承了父类的方法和属性
- 派生:子类在父类方法和属性的基础上产生了新的方法和属性
抽象接口
class Alipay:
'''
支付宝支付
'''
def pay(self,money):
print('支付宝支付了%s元'%money)
class Applepay:
'''
apple pay支付
'''
def pay(self,money):
print('apple pay支付了%s元'%money)
class Wechatpay:
def fuqian(self,money):
'''
实现了pay的功能,但是名字不一样
'''
print('微信支付了%s元'%money)
def pay(payment,money):
'''
支付函数,总体负责支付
对应支付的对象和要支付的金额
'''
payment.pay(money)
p = Wechatpay()
pay(p,200) #执行会报错
实践中,继承的第一种含义意义并不很大,甚至常常是有害的。因为它使得子类与基类出现强耦合。
继承的第二种含义非常重要。它又叫“接口继承”。
接口继承实质上是要求“做出一个良好的抽象,这个抽象规定了一个兼容接口,使得外部调用者无需关心具体细节,可一视同仁的处理实现了特定接口的所有对象”——这在程序设计上,叫做归一化。
归一化使得高层的外部使用者可以不加区分的处理所有接口兼容的对象集合——就好象linux的泛文件概念一样,所有东西都可以当文件处理,不必关心它是内存、磁盘、网络还是屏幕(当然,对底层设计者,当然也可以区分出“字符设备”和“块设备”,然后做出针对性的设计:细致到什么程度,视需求而定)。
奥特曼大战小怪兽1.0版
带有升级的版本
from abc import ABCMeta, abstractmethod
from random import randint, randrange
class Fighter(object, metaclass = ABCMeta):
__slots__ = ('_name','_hp','_exp')
"""绑定属性 name hp exp"""
def __init__ (self,name,hp,exp,level):
self._name = name
self._hp = hp
self._exp =exp
self._level =level
"""初始化属性"""
@property
def name(self):
return self._name
@property
def hp(self):
return self._hp
@property
def exp(self):
return self._exp
@property
def level(self):
return self._level
@level.setter
def level(self,level):
self._level = level
@exp.setter
def exp(self,exp):
self._exp = exp
@name.setter
def name(self,name):
self._name = name
@hp.setter
def hp(self, hp):
self._hp = hp if hp >= 0 else 0
@property
def alive(self):
if self._hp > 0:
return True
def attack(self):
pass
"""奥特曼的界面"""
class Ultraman(Fighter):
__slots__ = ('_name','_hp','_mp','_exp','_level')
def __init__(self, name, hp, mp, exp, level):
super().__init__(name,hp,exp,level)
self._mp = mp
def attack(self,other):
"""普通攻击"""
damage_point = randint(10,20)
other.hp -= damage_point
print('%s used a normal attack on %s causing %d normal damage point' \
%(self.name,other.name,damage_point))
def magic_attack(self,other):
"""魔法攻击"""
if self._mp >= 50 :
self._mp -= 60
magic_damage_point = randint(20,40)
other.hp -= magic_damage_point
print('%s used a magic attack on %s causing %d magic damage point' \
%(self.name,other.name,magic_damage_point))
else :
self.attack(other)
def restore_mp(self) :
"""恢复魔法值"""
incr_mp = randint(5,10)
self._mp += incr_mp
return incr_mp
def exp_value(self):
"""每回合增加经验值,打死一只怪兽涨50经验"""
self._exp += 10
return self._exp
def __str__(self):
return '~~~%s奥特曼~~~' % self._name + \
'hp is %d ' % self._hp + \
'mp is %d '% self._mp + \
'exp is %d ' %self._exp + \
'level is %d ' %self._level
"""怪兽的界面"""
class Monster(Fighter):
__slots__ = ('_name','_hp','_exp','_level')
def __init__(self, name, hp, exp, level):
super().__init__(name,hp,exp,level)
def attack(self,other):
damage_point = randint(5,10)
other.hp -= damage_point
print('%s used a normal attack on %s causing %d normal damage point' \
%(self.name,other.name,damage_point))
def __str__(self):
return '~~~%s怪兽~~~' % self._name + \
'hp is %d ' % self._hp
def is_any_alive(monsters):
for monster in monsters :
if monster.alive :
return True
else:
return False
def select_alive_monster (monsters):
monsters_len = len(monsters)
while True:
index = randrange(monsters_len)
monster = monsters[index]
if monster.alive :
return monster
"""显示信息的界面,这里面可以加入每回合固定要发生的事情
比如固定涨经验,固定恢复魔法值"""
def display_info (ultraman,monsters):
print('%s restore %d mana value and %d exp'%(ultraman.name, ultraman.restore_mp() \
,ultraman.exp_value()))
print(ultraman)
for monster in monsters:
print(monster)
print()
def level_up (ultraman):
if ultraman.exp_value() >= 100:
ultraman.exp -= 100
ultraman.level += 1
print("you are upgrade ! choose one skill : incrase mp for 0 or restore hp for 1 ")
up_options = int(input('options = '))
if up_options == 1 :
ultraman.hp += 100
else :
ultraman.mp += 100
def main():
ren = Ultraman('renyu',1000,100,10,1)
m1 = Monster('bartan',100,0,1)
m2 = Monster('sabotan',100,0,1)
ms = [m1,m2]
counter_round = 0
while is_any_alive(ms) and ren.alive:
counter_round += 1
m = select_alive_monster(ms)
print('========%02d round========' % counter_round)
"""奥特曼选择攻击方式"""
skill = randint(1,10)
if skill <= 6 : #普通攻击
ren.attack(m)
elif skill <= 10: #魔法攻击
ren.magic_attack(m)
"""怪兽的攻击"""
m.attack(ren)
"""升级涨经验"""
level_up(ren)
display_info(ren,ms)
if __name__ == '__main__':
main()
str 和 repr 的区别和联系
import datetime
s = 'hello'
d = datetime.datetime.now()
print(str(s))
print(repr(s))
print(str(d))
print(repr(d))
输出结果:
hello 'hello' 2018-11-29 22:39:18.014587 datetime.datetime(2018, 11, 29, 22, 39, 18, 14587)
可以看出repr()
更能显示出对象的类型、值等信息,对象描述清晰的。 而str()
能够让我们最快速了解到对象的内容,可读性较高。