目录
多态
什么是多态?
不同的子类对象,调用相同的父类方法,产生不同的执行结果
多态的关键字:继承和改写
下面的例子完美展示了python的多态:
# 定义Soldier类,让空军陆军海军继承这个类 class Soldier(): def attack(self): pass def back(self): pass # 陆军 class Army(Soldier): def attack(self): print("[陆军]搏击,ufc,无限制格斗,太极,八卦,占星,制作八卦符") def back(self): print("[陆军]白天晨跑10公里,也行800百公里") # 海军 class Navy(Soldier): def attack(self): print("[海军]潜泳水下30个小时,手捧鱼雷,亲自送到敌人的老挝,炸掉敌人的碉堡") def back(self): print("[海军]每小时在海底夜行800公里,游的比鲨鱼还快") # 空军 class AirForce(Soldier): def attack(self): print("[空军]空中夺导弹,手撕飞机,在空中打飞机,精准弹幕") def back(self): print("[空军]高中跳伞,落地成盒") # 实例化陆军对象 army_obj = Army() # 实例化海军对象 navy_obj = Navy() # 实例化空军对象 af_obj = AirForce() lst = [army_obj,navy_obj,af_obj] # 对象列表 strvar = """ 1.所有兵种开始攻击训练 2.所有兵种开始撤退训练 3.空军练习攻击,其他兵种练习撤退 """ print(strvar) num = input("将军请下令,选择训练的种类") for i in lst: if num == "1": i.attack() elif num == "2": i.back() elif num == "3": if isinstance(i,AirForce): i.attack() else: i.back() else: print("将军~ 风太大 我听不见~") break
__new__魔术方法
关于魔术方法__new__
1.触发时机:实例化类生成对象的时候触发(触发时机在__init__之前)
2.功能:控制对象的创建过程
3.参数:至少一个cls接受当前的类,其他根据情况决定
4.返回值:通常返回对象或None
基本语法
# (1)基本语法 class MyClass2(): pty = 100 obj2= MyClass2() class MyClass(): def __new__(cls): print(cls) # 类.方法(自定义类) => 借助父类object创建MyClass这个类的对象 obj = object.__new__(cls) # (1) 借助父类object创建自己类的一个对象 return obj # (2) 返回其他类的对象 return obj2 # (3) 不返回任何对象 return None obj = MyClass() print(obj)
__new__ 触发时机快于构造方法
__new__ 用来创建对象
__init__ 用来初始化对象
先创建对象,才能在初始化对象,所以__new__快于__init__
class Boat(): def __new__(cls): print(2) return object.__new__(cls) def __init__(self): print(1) obj = Boat() # 因为__new__比__init__先执行,所以会先打印2后打印1.
__new__ 和 __init__ 参数一一对应
单个参数的情况
class Boat(): def __new__(cls,name): return object.__new__(cls) def __init__(self,name): self.name = name obj = Boat("友谊的小船说裂开就裂开") print(obj.name)
多个参数的情况
# 当__init__参数很多的时候,在__new__方法使用*args和**kwargs收集所有的参数!! class Boat(): def __new__(cls,*args,**kwargs): return object.__new__(cls) def __init__(self,name,color,shangpai): self.name = name self.color = color self.shangpai = shangpai obj = Boat("泰坦尼克号","屎绿色","京A66688") print(obj.name) print(obj.color) print(obj.shangpai)
关于__new__的注意点
如果返回的对象不是自己本类中的对象,不会触发本类的构造方法
"""如果返回的对象不是自己本类中的对象,不会触发本类的构造方法""" class MyClass(): pty = 200 obj = MyClass() class Boat(): def __new__(cls,*args,**kwargs): return object.__new__(cls) # 返回的是自己类的对象,会触发__init__方法 # return obj # 返回的不是自己的对象,所以不会触发下面的__init__方法 # return None # 没有返回对象,不可能触发__init__方法 def __init__(self): print("构造方法被触发") obj = Boat() print(obj)
单态模式
什么是单态模式?
一个类,无论实例化多少个对象,都有且只有一个对象
单态模式的应用场景
优点:节省内存空间,提升执行效率
针对于不要额外对该对象添加成员的场景(比如:mysql增删改查)
基本语法
class SingleTon(): __obj = None def __new__(cls): if cls.__obj is None: # 把创建出来的对象赋值给私有成员__obj cls.__obj = object.__new__(cls) return cls.__obj obj1 = SingleTon() obj2 = SingleTon() obj3 = SingleTon() print(obj1,obj2,obj3) """ 第一次实例化对象时候, 创建一个对象赋值给cls.__obj,返回 cls.__obj 第二次实例化对象时候, 判定cls.__obj is None: 不成立, 直接返回上一次创建好的那一个对象 第三次实例化对象时候, 判定cls.__obj is None: 不成立, 直接返回上一次创建好的那一个对象 """
单态模式+构造方法
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("A") obj2 = SingleTon("B") print(obj1.name) print(obj2.name) # 打印出来的是两个B,原因如下 ''' obj1 = SingleTon(宋云杰) self.name = "A" obj2 = SingleTon(戈隆) self.name = "B" self 代表的是本对象 第一次实例化对象时候,创建一个对象,赋值name为A 第二次实例化对象时候,因为 cls.__obj is None不满足,返回上一个创建好的对象 为上一个对象的name这个属性赋值 为B obj1 和 obj2 所指代的对象是同一个对象 obj1.name => B obj2.name => B 其实有些相当于是B把A覆盖了,因为B和A指向同一个对象 '''
连贯操作
连贯操作,通过在类中的__init__方法中传入obj对象,进而实现对象.对象.对象.属性的这种连贯操作
通过.不停的调用下一个对象的操作就是连贯操作
1.小试牛刀
class MyClass1(): pth1 = 10 class MyClass2(): def __init__(self,obj): self.obj = obj obj = MyClass1() obj2 = MyClass2(obj) # 对象.对象.属性 # obj2.obj = obj # obj.pth1 = 10 print(obj2.obj.pth1) # 10
2.升级版
class MyClass1(): pty1 = 101 def func1(self): print("我是func1函数") class MyClass2(): def __init__(self,obj): self.pty2 = obj def func2(self): print("我是func2函数") class MyClass3(): pty3 = 103 def __init__(self,obj): self.pty3 = obj def func2(self): print("我是func3函数") obj1 = MyClass1() obj2 = MyClass2(obj1) obj3 = MyClass3(obj2) # 使用obj3调用func1方法? # 对象.pty3 => obj2 | obj2.pty2 => obj1 | obj1.func1() obj3.pty3.pty2.func1() print(obj3.pty3.pty2.pty1) obj3.pty3.func2()
连贯操作小项目->小人射击
小人射击的项目需求
小人射击项目的文件结构
文件夹下:
package包中:
小人射击项目的代码实现
main.py(主函数)
# ### 小人射击 """面向对象的核心思想: 把对象当做程序中的一个最小单元,让对象操作一切""" """ 弹夹: 属性: 子弹数量 bulletcount 方法: 无 枪 : 属性: 弹夹 方法: 射击 shoot 人 : 属性: 枪 方法: (1) 射击 (2) 换子弹 """ from package.bulletbox import BulletBox from package.gun import Gun from package.person import Person # 先创建弹夹 danjia = BulletBox(20) # 在创建一杆枪 ak47 = Gun(danjia) # 在创造一个人 songyunjie = Person(ak47,"宋云杰") # 小人射击 if __name__ == "__main__": # 射击 songyunjie.fire(15) # 填充 songyunjie.fillcount(10) # 在射击 songyunjie.fire(150)
bulletbox.py(弹夹)
# ### 弹夹类 class BulletBox(): def __init__(self,bulletcount): self.bulletcount = bulletcount
gun.py(枪)
# ### 枪类 class Gun(): def __init__(self,bulletbox): # 存放的是弹夹对象 self.bulletbox = bulletbox def shoot(self,shootcount): if self.bulletbox.bulletcount < shootcount: print("对不起,请先填充子弹~") else: # 剩余的子弹 = 总的子弹数量 - 射击的数量 self.bulletbox.bulletcount -= shootcount print("突" * shootcount , "你射出了{}发,还剩下{}发".format(shootcount,self.bulletbox.bulletcount))
person.py(人)
# ### 人类 class Person(): def __init__(self,gun,name): self.gun = gun self.name = "宋云杰" # 填充子弹 def fillcount(self,fillnum): # 往弹夹里面赛子弹 # self.枪对象 -> 弹夹对象 -> 弹夹数量属性 self.gun.bulletbox.bulletcount += fillnum # 射击 def fire(self,num): print("{}此刻正在野外射击~".format(self.name)) # 枪对象.shoot self.gun.shoot(num)
关于小人射击项目的总结
在小人项目中,.要时刻遵循面向对象的思想
1.在主函数main.py中,不要写任何逻辑,只写对象,让对象来操作一切
2.采用连贯操作,虽然实例化了三个对象,但是在调用方法的时候,只需要用一个对象去调用所有类中的方法