• day24:多态&魔术方法__new__&单态模式


    目录

    1.多态

    2.__new__魔术方法

      2.1 关于魔术方法__new__

      2.2 基本语法

      2.3 __new__ 触发时机快于构造方法

      2.4 __new__ 和 __init__ 参数一一对应

      2.5 关于__new__的注意点

    3.单态模式

    4.连贯操作

    5.小人射击项目

    多态

    什么是多态?

    不同的子类对象,调用相同的父类方法,产生不同的执行结果

    多态的关键字:继承和改写

    下面的例子完美展示了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.采用连贯操作,虽然实例化了三个对象,但是在调用方法的时候,只需要用一个对象去调用所有类中的方法

  • 相关阅读:
    外部类和内部类的创建调用实例2个
    构造函数实例化
    前端学习(二十三)DOM操作,事件(笔记)
    前端学习(二十二)css3(笔记)
    前端学习(二十一)初识h5(笔记)
    前端学习(二十)jquery属性(笔记)
    前端学习(十九)jquery(笔记)
    前端学习(十八)js的json(笔记)
    前端学习(十七)js数组(笔记)
    前端学习(十六)字符串(笔记)
  • 原文地址:https://www.cnblogs.com/libolun/p/13441576.html
Copyright © 2020-2023  润新知