Python面向对象 | 组合
Posted summer-skr--blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python面向对象 | 组合相关的知识,希望对你有一定的参考价值。
软件重用的重要方式,除了继承之外还有另外一种方式,即:组合
一、对象之间的交互
方法可以传参,参数可以是对象。
class Person: role = ‘person‘ def __init__(self, name, sex, hp, ad): self.name = name self.sex = sex self.hp = hp self.ad = ad def attack(self,dog): dog.hp -= self.ad print(‘%s攻击了%s,%s掉了%s点血‘ % (self.name,dog.name,dog.name,self.ad)) class Dog: role = ‘person‘ def __init__(self, name, kind, hp, ad): self.name = name self.kind = kind self.hp = hp self.ad = ad def bite(self,people): #people是变量名,它是一个对象 people.hp -= self.ad print(‘%s咬了%s一口,%s掉了%s点血‘ % (self.name, people.name, people.name, self.ad)) tony = Person(‘Tony‘, ‘不详‘, 1, 5) john = Person(‘John‘, ‘女‘, 20, 50) teddy = Dog(‘teddy‘, ‘male‘, 50, 10) teddy.bite(tony) print(tony.hp) tony.attack(teddy) print(teddy.hp) ‘‘‘ 执行输出: teddy咬了Tony一口,Tony掉了10点血 -9 Tony攻击了teddy,teddy掉了5点血 45 ‘‘‘
二、面向对象的组合
组合:给一个类的对象封装一个属性,这个属性就是另一个类的对象
组合的意义:让一个类的对象和另一个类的对象产生关系,让一个类和另一个类产生关系
如何组合:
1、在类1中定义一个方法,类1对象1在执行这个方法的时候能增加一个属性,属性值就是类2的对象2;
2、类1.属性名.类2中的方法,就以类1为主体执行了类2的方法;
当一个类的对象作为另一个类的属性,说明这2个类组合在一起了。那么类就可以使用另外一个类的属性和方法了。一般说组合 ,是指2个类的组合。
class Gamerole: def __init__(self,name,ad,hp): self.name = name self.hp = hp self.ad = ad def attack(self,role): role.hp = role.hp - self.ad print(‘%s攻击%s,%s掉了%s血,还剩%s血‘ % (self.name,role.name,role.name,self.ad,role.hp)) #定义一个方法,让Gamerole的对象可以产生一个新的属性,属性名是weapon,属性值是Weapon的对象 def equip_weapon(self,w): self.weapon = w class Weapon: def __init__(self,name,ad): self.name = name self.ad = ad def fight(self,role1,role2): role2.hp = role2.hp - self.ad print(‘%s用%s攻击%s,%s掉了%s血,还剩%s‘ %(role1.name,self.name,role2.name,role2.name,self.ad,role2.hp)) p1 = Gamerole(‘盖伦‘,20,500) p2 = Gamerole(‘剑豪‘,100,200) p1.attack(p2) w1 = Weapon(‘大宝剑‘,30) w2 = Weapon(‘武士刀‘,80) w1.fight(p1,p2) #刀是主体,不合规范 盖伦用大宝剑攻击剑豪,剑豪掉了30血,还剩170血 p1.equip_weapon(w1) #执行方法,给对象p1增加一个属性weapon,属性值是Weapon的对象w1 # print(p1.weapon) #<__main__.Weapon object at 0x000001FF47997AC8> # print(w1) #<__main__.Weapon object at 0x000001FF47997AC8> 地址相同 p1.weapon.fight(p1,p2) #盖伦用大宝剑攻击剑豪,剑豪掉了30血,还剩170血
三、组合实例
1.人狗大战武器给谁装备呢?武器需要花钱买吧,那么就需要玩家充钱,现在加一个充钱功能
class Person: def __init__(self, name, sex, hp, ad): self.name = name # 对象属性 属性 self.sex = sex self.hp = hp # 血量 self.ad = ad # 攻击力 self.money = 0 # 金额 self.arms = None # 默认武器为None def attack(self, d): d.hp -= self.ad print(‘%s攻击了%s,%s掉了%s点血‘ % (self.name, d.name, d.name, self.ad)) def pay(self): # 充值 money = int(input(‘请输入您要充值的金额:‘)) self.money += money print(‘您的余额是:%s‘ % self.money) def wear(self, weapon): # 装备武器 if self.money >= weapon.price: self.arms = weapon # 组合 给人装备了武器 self.money -= weapon.price print(‘购买成功,您已经顺利装备了%s‘ % weapon.name) else: print(‘余额不足,请充值!‘) def attack_with_weapon(self, dog): # 拿武器攻击狗 if ‘arms‘ in self.__dict__ and self.arms != None: # 如果武器属性在实例属性字典里,并且属性不为空 self.arms.skill(dog) # 使用武器攻击狗 else: print(‘请先装备武器‘) class Dog: def __init__(self, name, kind, hp, ad): self.name = name # 对象属性 属性 self.kind = kind self.hp = hp self.ad = ad def bite(self, p): p.hp -= self.ad # 人掉血 print(‘%s咬了%s一口,%s掉了%s点血‘ % (self.name, p.name, p.name, self.ad)) class Weapon: # 武器 def __init__(self, name, price, level, ad): self.name = name # 武器名 self.price = price # 价格 self.level = level # 等级 self.ad = ad * self.level # 升级之后,攻击就翻倍了 self.wear = 20 # 默认的耐久度,实例化时,可以不用传 def skill(self, dog): # 技能,攻击狗 dog.hp -= self.ad # 狗掉血 print(‘%s受到了%s点的伤害,%s掉了%s点血‘ % (dog.name, self.name, dog.name, self.ad)) # 实例化武器,玩家购买武器,攻击狗 tony = Person(‘Tony‘, ‘不详‘, 1, 5) tony.pay() # 充值 tony.wear(axe) # 装备武器斧头 tony.arms.skill(teddy) # 使用斧头攻击狗 ,相当于tony.skill(reddy)
注意:不能加类静态变量meny = 0。否则玩家充钱了,别的玩家就可以使用了,int之后,不需要strip()一下,int会自动去除空格
这样写是一次性的,写一个while循环,显示菜单执行。实例化部分,改成如下:
class Person: def __init__(self, name, sex, hp, ad): self.name = name # 对象属性 属性 self.sex = sex self.hp = hp # 血量 self.ad = ad # 攻击力 self.money = 0 # 金额 self.arms = None # 默认武器为None def attack(self, d): d.hp -= self.ad print(‘%s攻击了%s,%s掉了%s点血‘ % (self.name, d.name, d.name, self.ad)) def pay(self): # 充值 money = int(input(‘请输入您要充值的金额:‘)) self.money += money print(‘您的余额是:%s‘ % self.money) def wear(self, weapon): # 装备武器 if self.money >= weapon.price: self.arms = weapon # 组合 给人装备了武器 self.money -= weapon.price print(‘购买成功,您已经顺利装备了%s‘ % weapon.name) else: print(‘余额不足,请充值!‘) def attack_with_weapon(self, dog): # 拿武器攻击狗 if ‘arms‘ in self.__dict__ and self.arms != None: # 如果武器属性在实例属性字典里,并且属性不为空 self.arms.skill(dog) # 使用武器攻击狗 else: print(‘请先装备武器‘) class Dog: def __init__(self, name, kind, hp, ad): self.name = name # 对象属性 属性 self.kind = kind self.hp = hp self.ad = ad def bite(self, p): p.hp -= self.ad # 人掉血 print(‘%s咬了%s一口,%s掉了%s点血‘ % (self.name, p.name, p.name, self.ad)) class Weapon: # 武器 def __init__(self, name, price, level, ad): self.name = name # 武器名 self.price = price # 价格 self.level = level # 等级 self.ad = ad * self.level # 升级之后,攻击就翻倍了 self.wear = 20 # 默认的耐久度,实例化时,可以不用传 def skill(self, dog): # 技能,攻击狗 dog.hp -= self.ad # 狗掉血 print(‘%s受到了%s点的伤害,%s掉了%s点血‘ % (dog.name, self.name, dog.name, self.ad)) # 实例化武器,玩家购买武器,攻击狗 tony = Person(‘Tony‘, ‘不详‘, 1, 5) teddy = Dog(‘Teddy‘, ‘teddy‘, 50, 10) axe = Weapon(‘Axe‘, 1000, 100, 1) lst = [‘攻击‘, ‘充值‘, ‘装备武器‘, ‘使用武器攻击‘,‘退出‘]
while True: for index, value in enumerate(lst, 1): print(index, value) num = int(input(‘请选择操作序号 >>>‘)) if num == 1: tony.attack(teddy) elif num == 2: tony.pay() elif num == 3: print(‘装备前余额 %s‘ % tony.money) tony.wear(axe) print(‘装备后余额 %s‘ % tony.money) elif num == 4: tony.attack_with_weapon(teddy) elif num == 5: break else: print(‘无效的序号‘)
执行输出:
skill方法,只有武器才有,人是不能直接调用的。但是,人一旦装备上了武器,就可以执行skill方法。关键点,就在于以下一段代码self.arms = weapon 组合 给人装备了武器 . 直接给人加了一个属性arms,注意,等式右边的weapon是一个武器对象, 所以就可以使用武器攻击狗self.arms.skill(dog) . self也就是实例对象,比如tony。
为什么会用组合?
独立的对象不能发挥他的作用,必须依赖一个对象,比如上面的例子,斧头不能够攻击狗,它依赖人来执行。
人还可以装备2件武器
tony = Person(‘Tony‘, ‘不详‘, 1, 5) teddy = Dog(‘Teddy‘, ‘teddy‘, 50, 10) axe = Weapon(‘Axe‘, 1000, 100, 1) knife = Weapon(‘Knife‘, 1000, 100, 1) tony.pay() # 充值 tony.wear(axe) # 装备武器斧头 tony.wear(knife) # 装备武器刀 tony.arms.skill(teddy) # 执行攻击 后一个是knife,所以alex.arms是knife
执行输出:
2.圆环
计算圆环的面积和周长
圆环的周长 :大圆周长 + 小圆周长
圆环的面积 :大圆面积 - 小圆面积
from math import pi class Circle: # 圆形 def __init__(self, r): self.r = r def cal_area(self): # 面积 return pi * self.r ** 2 def cal_perimeter(self): # 周长 return pi * self.r * 2 class Ring2: # 圆环 def __init__(self, out_r, in_r): self.out_circle = Circle(out_r) # 实例化圆作为圆环的大圆 self.in_circle = Circle(in_r) # 实例化圆,作为圆环的小圆 def area(self): # 圆环面积.用绝对值,保证结果不为负数 return abs(self.out_circle.cal_area() - self.in_circle.cal_area()) # 大圆面积 - 小圆面积 def cal_perimeter(self): return self.out_circle.cal_perimeter() + self.in_circle.cal_perimeter() # 大圆周长 + 小圆周长 r1 = Ring2(10, 5) # 实例化圆环,传入大圆和小圆的半径 print(r1.area()) print(r1.cal_perimeter()) ‘‘‘ 执行输出: 235.61944901923448 94.24777960769379 ‘‘‘
圆环包含了圆,而圆的面积和周长公式,和圆环有点类似。所以,把圆这个对象,作为圆环类对象的属性,这就是组合。
3.老师和班级
老师 属性:姓名 年龄 性别 班级 : s11
班级 属性:班级名 班级人数 科目 性质
class Class: def __init__(self, name, num, course, type): self.name = name self.num = num self.course = course self.type = type class Teacher: def __init__(self, name, sex, age, cls): self.name = name self.sex = sex self.age = age self.cls = cls # 班级 py = Class(‘Python‘, 89, ‘python‘, ‘IT‘) # 实例化一个班级 teacher = Teacher(‘Tony‘, ‘女‘, 40,py) # 实例化一个老师 print(py.course) # 查看课程 print(teacher.cls.course) # 查看课程 print(teacher.cls.__dict__) # 查看py11的所有属性 ‘‘‘ 执行输出: python python {‘name‘: ‘Python‘, ‘num‘: 89, ‘course‘: ‘python‘, ‘type‘: ‘IT‘} ‘‘‘
通过实例化,可以直接组合2个类。在这个例子中,Teacher通过cls属性,得到了py对象的所有属性以及方法。这是组合的第二种使用方式
以上是关于Python面向对象 | 组合的主要内容,如果未能解决你的问题,请参考以下文章
Python之面向对象的组合多态菱形问题子类中重用父类的两种方式
Python基础day-18[面向对象:继承,组合,接口归一化]
Python 面向对象--继承,实现,依赖,关联,聚合,组合