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)