• 032.Python魔术方法__new__和单态模式



    一 __new__ 魔术方法

    1.1 介绍

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

    1.2 基本用法

    复制代码
    class MyClass():
            abc = 123
            def __new__(cls):      #把class这个类传递__new__这个方法
                    print (123)
                    return None     #返回一个None
    
    #实例化对象
    obj = MyClass()
    print (obj)
    复制代码

    执行

    这样就不能使用使用obj这个对象调用abc的值

    复制代码
    class MyClass():
            abc = 123
            def __new__(cls):
                    print (123)
                    return None
    
    #实例化对象
    obj = MyClass()
    print (obj)
    print (obj.abc)      #在这里就相当于使用None.abc.这种此写法不允许,就会报错
    复制代码

    执行

    借助父类创建对象

    返回本类对象

    复制代码
    class MyClass():
            abc = 123
            def __new__(cls):
              print (cls) print (123) #要借助父类object的__new__创建对象 obj = object.__new__(cls) return obj #实例化对象 obj = MyClass() print (obj) print (obj.abc)
    复制代码

    执行

    复制代码
    [root@node10 python]# python3 test.py
    <class '__main__.MyClass'> #cls是一个类 123 <__main__.MyClass object at 0x7ff2808ba3c8> 123 [root
    复制代码

    返回空对象

    复制代码
    class MyClass():
            abc = 123
            def __new__(cls):
                    print (cls)
                    print (123)
                    #要借助父类object的__new__创建对象
                    obj = object.__new__(cls)
                    #return obj
                    return None
    
    #实例化对象
    obj = MyClass()
    print (obj)
    print (obj.abc)
    复制代码

    执行

    返回一个其他类的对象

    复制代码
    class MyClass2():
            ccc = 4
    obj2 = MyClass2()
    class MyClass():
            abc = 123
            def __new__(cls):
                    print (cls)
                    print (123)
                    #要借助父类object的__new__创建对象
                    obj = object.__new__(cls)
                    #return obj
                    #return None
                    return obj2
    
    #实例化对象
    obj = MyClass()
    print (obj)
    print (obj.abc)
    复制代码

    执行

    修改属性

    复制代码
    [root@node10 python]# cat test.py
    class MyClass2():
            ccc = 4
    obj2 = MyClass2()
    class MyClass():
            abc = 123
            def __new__(cls):
                    print (cls)
                    print (123)
                    #要借助父类object的__new__创建对象
                    obj = object.__new__(cls)
                    #return obj
                    #return None
                    return obj2
    
    #实例化对象
    obj = MyClass()
    print (obj)
    print (obj.ccc)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    <class '__main__.MyClass'>
    123
    <__main__.MyClass2 object at 0x7fb463cc7470>
    4

    1.3 对__new__和__init__这两个魔术方法的区别

    调用的顺序

    复制代码
    class Boat():
            def __new__(cls):
                    print (1)
                    return object.__new__(cls)
            def __init__(self):
                    print (2)
    obj = Boat()
    print (obj)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    1
    2
    <__main__.Boat object at 0x7f9bb5fcf400>

    先调用__new__在调用__init__

    调用和定义的顺序无关

    复制代码
    class Boat():
            def __init__(self):
                    print (2)
            def __new__(cls):
                    print (1)
                    return object.__new__(cls)
    obj = Boat()
    print (obj)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    1
    2
    <__main__.Boat object at 0x7f95a73cf400>

    结果一样

    复制代码
    __new__ 的触发时机要快于 __init__
    __new__  是用来创建对象的
    __init__ 是用来初始化对象的
    
    先得有对象
    才能初始化对象
    
    new 和 init 他门的参数要保持一致.
    复制代码

    1.4  如果返回的不是一个本类对象__init__就不会触发

    复制代码
    class Boat():
            def __new__(cls):
                    print (1)
                    #return object.__new__(cls)
                    return None
            def __init__(self):
                    print (2)
    obj = Boat()
    print (obj)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    1
    None

    初始化参数

    复制代码
    class Boat():
            def __new__(cls):
                    print (1)
                    return object.__new__(cls)
                    #return None
            def __init__(self,name):
                    self.name = name
    obj = Boat("John")
    print (obj.name)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    Traceback (most recent call last):
      File "test.py", line 8, in <module>
        obj = Boat("John")
    TypeError: __new__() takes 1 positional argument but 2 were given

    这是因为,__new__先于__init__调用,但是,在调用的时候,已经传递了一个类(cls)的参数,name的参数就不能对应报错

    复制代码
    class Boat():
            def __new__(cls,name):
                    print (1)
                    return object.__new__(cls)
                    #return None
            def __init__(self,name):
                    self.name = name
    obj = Boat("John")
    print (obj.name)
    复制代码

    执行,而可以调用

    [root@node10 python]# python3 test.py
    1
    John

    1.5 使用参数的普通参数和关键字实参

    复制代码
    lass Boat():
            def __new__(cls,*args,**kwargs):
                    print (1)
                    return object.__new__(cls)
                    #return None
            def __init__(self,*args,**kwargs):
                    strvar = ""
                    for i in args:
                            strvar += i + " "
                    print (strvar)
                    print (kwargs)
    obj = Boat("John","Jim","Tom",name="David")
    复制代码

    执行

    [root@node10 python]# python3 test.py
    1
    John Jim Tom
    {'name': 'David'}

    1.6 如果__new__魔术方法返回的时其他类的对象,不会触发__init__ 本类的魔术方法

    复制代码
    class MyClass2():
            ccc = 4
    obj2 = MyClass2()
    class Boat():
            def __new__(cls,*args,**kwargs):
                    print (1)
                    #return object.__new__(cls)
                    return obj2
            def __init__(self,*args,**kwargs):
                    print (111)
    obj = Boat("John","Jim","Tom",name="David")
    print (obj.ccc)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    1
    4

    二 单态模式

    无论实例化类几次,都有且只有一个对象.为了节省内存空间

    2.1 创建一个类,实例化三个对象

    复制代码
    [root@node10 python]# cat test.py
    class Singleton():
            pass
    obj1 = Singleton()
    print (obj1)
    obj2 = Singleton()
    print (obj2)
    obj3 = Singleton()
    print (obj3)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    <__main__.Singleton object at 0x7efd7ec76400>
    <__main__.Singleton object at 0x7efd7ec76438>
    <__main__.Singleton object at 0x7efd7ec76470>

    可以看到占用不同的内存空间

    2.2 使用单态模式

    复制代码
    class Singleton():
            #创建一个私有的对象,类外无法调用
            __obj = None
            #定义一个方法
            def __new__(cls):
                    #判断这个对象是否为None对象
                    if cls.__obj is None:
                            obj = object.__new__(cls)   #如果是,就重新创建一个新的对象
                            cls.__obj = obj             #把这新的对象夫给类的私有方法
                    return cls.__obj                    #如果不是None,直接返回
    obj1 = Singleton()
    print (obj1)
    obj2 = Singleton()
    print (obj2)
    obj3 = Singleton()
    print (obj3)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    <__main__.Singleton object at 0x7fbae7edb4a8>
    <__main__.Singleton object at 0x7fbae7edb4a8>
    <__main__.Singleton object at 0x7fbae7edb4a8>

    发现三个对象都是一个内存地址

    2.3 实际的含义,对象和init之间的关系

    复制代码
    class Singleton():
            #创建一个私有的对象,类外无法调用
            __obj = None
            #定义一个方法
            def __new__(cls,name):
                    #判断这个对象是否为None对象
                    if cls.__obj is None:
                            cls.__obj = object.__new__(cls)
                    return cls.__obj
            def __init__(self,name):
                    self.name = name
    obj1 = Singleton("John")
    obj2 = Singleton("Frnak")
    print (obj1.name)
    print (obj2.name)
    复制代码

    执行

    [root@node10 python]# python3 test.py
    Frnak
    Frnak
    学习记录,小白一枚
  • 相关阅读:
    半夜的时候,干了个活,反了个小软件
    bzoj2243[SDOI2011]染色
    bzoj4034[HAOI2015]T2
    bzoj2661[BeiJing wc2012]连连看
    bzoj1406[AHOI2007]密码箱
    bzoj1452[JSOI2009]Count
    bzoj1934[Shoi2007]Vote 善意的投票
    bzoj1787[Ahoi2008]Meet 紧急集合&bzoj1832[AHOI2008]聚会
    bzoj1293[SCOI2009]生日礼物
    bzoj1221[HNOI2001] 软件开发
  • 原文地址:https://www.cnblogs.com/wangsirde0428/p/14322601.html
Copyright © 2020-2023  润新知