【二十二】Python全栈之路--多态_小人射击

1. 多态

# ### 多态: 不同的子类对象调用相同的父类方法,得到不同的执行结果
"""继承 重写 """

class Soldier():
	def attack(self):
		pass
		
	def back(self):
		pass
		
# 陆军
class Army(Soldier):
	def attack(self):
		print("[陆军]开坦克装甲部队,开大炮轰炸敌方根据地,拼刺刀,手撕鬼子")
		
	def back(self):
		print("[陆军]为了一条性命,夜行八百,日行一千,回家")
	
# 海军
class Navy(Soldier):
	def attack(self):
		print("[海军]开航空母舰,扔鱼叉,撒网捆住敌人,收网")
	
	def back(self):
		print("[海军]直接跳水,下海喂鱼,原地爆炸")

# 空军
class AirForce(Soldier):
	def attack(self):
		print("[空军]空对地投放原子弹,空对空发射巡航导弹")
	
	def back(self):
		print("[空军]直接跳机,落地成盒")
	
# 创建士兵
obj1 = Army()
obj2 = Navy()
obj3 = AirForce()

# 
lst = [obj1,obj2,obj3]
# lst = [Army(),Navy(),AirForce()]

strvar = """
将军请下令:
1.全体出击
2.全体撤退
3.海军上,其他兵种撤退
"""

num = input(strvar)
for i in lst:
	# print(i)
	if num == "1":
		i.attack()
	elif num == "2":
		i.back()
	elif num == "3":
		if isinstance(i,Navy):
			i.attack()
		else:
			i.back()
	else:
		print("风太大,小弟听不见")
		break

2. __new__魔术方法

# ### __new__ 魔术方法
'''
	触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
	功能:控制对象的创建过程
	参数:至少一个cls接受当前的类,其他根据情况决定
	返回值:通常返回对象或None
'''

# (1) 基本使用
class MyClass2():
	a = 100
obj2 = MyClass2()
# print(obj2)

class MyClass1():
	def __new__(cls):
		# print(cls)		
		# 1.返回本类对象
		"""类.成员方法(类)"""
		# return object.__new__(cls)
		# 2.返回其他类的对象
		# return obj2
		# 3.不返回对象,None
		return None		
	
obj = MyClass1()
# print(obj.a)
print(obj)

# (2) __new__ 触发时机要快于 __init__
"""
__new__  创建对象
__init__ 初始化对象
"""
class MyClass():

	def __new__(cls):
		print(1)
		return object.__new__(cls)

	def __init__(self):
		print(2)
	
obj = MyClass()	

# (3) __new__的参数要和__init__参数一一对应

class Boat():
	def __new__(cls,name):
		return object.__new__(cls)
	
	def __init__(self,name):
		self.name  = name

obj = Boat("万里阳光号")
print(obj.name)

# 使用收集参数进行改造
class Boat():
	# *args,**kwargs 可以收集多余的所有参数
	def __new__(cls,*args,**kwargs):
		return object.__new__(cls)
	
	def __init__(self,name,type):
		self.name  = name
		self.type = type

obj = Boat("万里阳光号","破木头做的")
print(obj.name , obj.type)


# (4) __new__和__init__之间的注意点
"""
如果__new__ 没有返回对象或者返回的是其他类的对象,不会调用构造方法.
只有在返回自己本类对象的时候,才会调用构造方法.
"""
class Children():
	def __new__(cls,*args,**kwargs):
		return obj2
		# pass
		
	def __init__(self,name,skin):
		print("构造方法被触发 ... ")
		# self.name = name
		# self.skin = skin
		
obj = Children("灭霸","紫薯")

# print(obj.name) error
# print(obj.skin) error

小提示:

通过这个object这个父类来帮助子类创建对象(中央集权)
如果想自己控制对象的创建,就要用到__new__,可以控制返回不同的对象(可以返回其他类的对象)
cls就是类

3. 单态模式

# ### 单态模式 : 同一个类,无论实例化多少次,都有且只有一个对象
"""
每创建一个对象,就会在内存中多占用一份空间
为了节省空间,提升执行效率,使用单态模式
场景:只是单纯调用类中的成员,而不会额外为当前对象添加成员;
"""

class Singleton():
	__obj = None
	def __new__(cls):
		if cls.__obj is None:
			cls.__obj = object.__new__(cls)
		return cls.__obj

"""
第一次,在实例化对象时触发__new__魔术方法 
if cls.__obj is None 条件成立  cls.__obj = object.__new__(cls) 创建一个对象给私有成员属性__obj
return cls.__obj  用obj1接收到了对象

第二次,在实例化对象时触发__new__魔术方法 if cls.__obj is None不满足,因为已经在__obj属性中存放了一个对象
return cls.__obj

第三次,在实例化对象时触发__new__魔术方法 if cls.__obj is None不满足,因为已经在__obj属性中存放了一个对象
return cls.__obj
"""
obj1 = Singleton()
obj2 = Singleton()
obj3 = Singleton()
print(obj1,obj2,obj3)

# 
class Singleton():
	__obj = None
	def __new__(cls,*args,**kwargs):
		if cls.__obj is None:
			cls.__obj = object.__new__(cls)
		return cls.__obj
		
	def __init__(self,name):
		self.name = name

obj1 = Singleton("康玉康")
obj2 = Singleton("张保张")
print(obj1,obj2)
print(obj1.name)
print(obj2.name)
"""
康玉康 康玉康
康玉康 张保张
张保张 张保张

第一次实例化对象时,
触发__new__ if cls.__obj is None: 创建一个新的对象进行返回
然后触发__init__ self.name = 康玉康

第二次实例化对象时
触发__new__ if cls.__obj is None: 条件不满足,返回的是第一次实例化的对象,是同一个
然后触发__init__ self.name = 张保张
"""
	
name = "康裕康"
name = "张保障"
print(name)
	

在这里插入图片描述
在这里插入图片描述

4. del_str_repr

4.1 del

# ### __del__ 魔术方法(析构方法)
'''
	触发时机:当对象被内存回收的时候自动触发[1.页面执行完毕回收所有变量 2.所有对象被del的时候]
    功能:对象使用完毕后资源回收
	参数:一个self接受对象
	返回值:无
'''

# (1) 基本语法

class Lion():
	def __init__(self,name):
		self.name = name
		
	def __del__(self):
		print("析构方法被触发 ... ")

# 触发方式一: 页面执行完毕回收所有变量
obj1 = Lion("辛巴")

# 触发方式二: 所有对象被del的时候
obj2 = obj1
obj3 = obj1
print(obj2 , obj1 ,obj3)
print("<====start===>")
del obj1
del obj2
del obj3
print("<====end===>")

# (2) 模拟文件操作
import os
class ReadFile():
	# 根据文件是否存在,创建对象
	def __new__(cls,filename):
		if os.path.exists(filename):
			return object.__new__(cls)
		else:
			print("抱歉,没有这个文件")
	
	# 打开文件
	def __init__(self,filename):
		self.fp = open(filename,mode="r",encoding="utf-8")
		
	# 关闭文件
	def __del__(self):
		self.fp.close()
		
	# 读取文件
	def readcontent(self):
		return self.fp.read()
		

obj = ReadFile("0.py")
print(obj.readcontent())

在这里插入图片描述

4.2 str

# ### __str__ 魔术方法
'''
	触发时机: 使用print(对象)或者str(对象)的时候触发
	功能:     查看对象
	参数:     一个self接受当前对象
	返回值:   必须返回字符串类型
'''

class Cat():
	gift = "抓老鼠"
	def __init__(self,name):
		self.name = name
		
	def cat_gift(self):
		return "小猫叫{},小猫会{}".format(self.name,self.gift)
	
	def __str__(self):
		return self.cat_gift()	

	__repr__ = __str__
	
tom = Cat("汤姆")
# 触发时机1 :  print(对象)
# print(tom)
# 触发时机2 :  str(对象)
res = str(tom)
print(res)

print("<==================>")
res = repr(tom)
print(res , type(res))
print("<==================>")

# ### __repr__ 魔术方法
'''
	触发时机: 使用repr(对象)的时候触发
	功能:     查看对象,与魔术方法__str__相似
	参数:     一个self接受当前对象
	返回值:   必须返回字符串类型
'''
class Mouse():
	gift = "偷油吃"
	def __init__(self,name):
		self.name = name
	
	def mouse_gift(self):
		return "老鼠叫{},老鼠会{}".format(self.name,self.gift)
	
	def __repr__(self):
		return self.mouse_gift()
	
	# 系统底层默认把__repr__方法赋值给__str__方法,所以通过print或者str强转可以触发;
	# __str__ = __repr__
	
jerry = Mouse("杰瑞")
# res = repr(jerry)
# print(res)

# 可以触发
# print(jerry)
res = str(jerry)
print(res)

5. 小人射击

5.1 连贯操作

# ### 连贯操作
"""不停地通过.调用下一个对象的操作叫连贯操作"""
class A():
	aaa = 100
	
	
class B():
	def __init__(self,obj):
		self.pty = obj

obj1 = A()
obj2 = B(obj1)

# 如何通过obj2对象 调用aaa 这个属性
# obj2.pty =>  <__main__.A object at 0x7f256716c2b0>
print(obj2.pty.aaa)



#
class Ceshi1():
	pty1 = 10
	def func1(self):
		print("我是func1方法")
	
class Ceshi2():
	
	def __init__(self,obj):
		self.pty2 = obj
	
	def func2(self):
		print("我是func2方法")
	
class Ceshi3():

	def __init__(self,obj):
		self.pty3 = obj
		
	def func3(self):
		print("我是func3方法")

class Ceshi4():

	def __init__(self,obj):
		self.pty4 = obj
		
	def func4(self):
		print("我是func4方法")

obj1 = Ceshi1()
obj2 = Ceshi2(obj1)
obj3 = Ceshi3(obj2)
obj4 = Ceshi4(obj3)

# 如果通过调用obj4这个对象获取  Ceshi1的pty1  的属性和 Ceshi2的func2方法
print(obj4.pty4.pty3.pty2.pty1)
obj4.pty4.pty3.func2()

在这里插入图片描述

5.2 小人射击

package目录(与main.py同级)

bulletbox.py

# ### 弹匣类

class BulletBox():
	def __init__(self,bulletcount):
		# bulletcount是子弹的数量
		self.bulletcount = bulletcount

gun.py

# ### 枪类
class Gun():
	def __init__(self,bulletbox):
		self.bulletbox = bulletbox
		
	# 射击方法
	def shoot(self,firecount):
		# 剩余数量 = 总数量 - 射出的数量
		# self.bulletbox.bulletcount = self.bulletbox.bulletcount - firecount
		
		if self.bulletbox.bulletcount < firecount:
			print("抱歉,你需要上子弹,换个枪")
			
		else:
			self.bulletbox.bulletcount -= firecount
			print(   "蹦ong!!" *  firecount   ,  "剩余的子弹数量是{}".format(self.bulletbox.bulletcount)    )
				
# ak47 = Gun()
# ak47         突突突突突突  
# 加特林      哒哒哒
# 1887霰弹枪  "蹦ong!!"

person.py

# ### 人类
class Person():
	def __init__(self,gun):
		self.gun = gun
		
	def fill(self,num):
		# 找弹匣对象中的bulletcount属性填充子弹
		self.gun.bulletbox.bulletcount += num
		"""
		self.gun => 枪对象
		self.gun.bulletbox => 弹匣对象
		self.gun.bulletbox.bulletcount => 弹匣对象里面的子弹数量属性		
		"""
		
	def fire(self,fcount):
		self.gun.shoot(fcount)

main.py

# ### 小人射击
"""面向对象的核心思想: 把对象当做程序的最小单元,让对象去操作一切   """
"""
需求分析: 
	弹匣类:  bulletbox
		属性: bulletcount
		方法: 无

	枪类:    gun
		属性: 弹匣对象
		方法: 射击 shoot

	人类:    person
		属性: 枪对象
		方法: 1.射击,  2.换子弹
"""
# 导入弹匣类 , 枪类  , 人类
from package.bulletbox import BulletBox
from package.gun import Gun
from package.person import Person

# 创建一个弹匣
danxia = BulletBox(10)
print(danxia)

# 创建一个枪
xdq1887 = Gun(danxia)

# 创建一个人
kangyukang = Person(xdq1887)

if __name__ == "__main__":
	# 开枪发射
	kangyukang.fire(5)
	# 上子弹
	kangyukang.fill(3)
	# 开枪发射
	kangyukang.fire(7)
	kangyukang.fire(10)
	

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值