一个类实例的创建过程——`__new__`

__new__() 是一种负责创建类实例的静态方法,它无需使用 @staticmethod 装饰器修饰,且该方法会优先 __init__() 初始化方法被调用。
一般情况下,覆写 __new__()的实现将会使用合适的参数调用其超类的 super().__new__(),并在返回之前修改实例。例如:
13_newMethodInCls.py

class DemoClass:
    instances_created = 0

    def __new__(cls, *args, **kwargs):
        print("__new__():", cls, args, kwargs)
        instance = super().__new__(cls)
        print('instance:', instance)
        instance.number = cls.instances_created
        cls.instances_created += 1
        return instance

    def __init__(self, attribute):
        print("__init__():", self, attribute)
        self.attribute = attribute


test1 = DemoClass("abc")
print('test1:', test1)
print("\n----------------\n")
test2 = DemoClass("xyz")
print('test2:', test2)
print("\n----------------\n")
print(test1.number, test1.instances_created)
print(test2.number, test2.instances_created)

输出结果为:
__new__(): <class '__main__.DemoClass'> ('abc',) {}
instance: <__main__.DemoClass object at 0x00000161CA9F2EB0> 0
__init__(): <__main__.DemoClass object at 0x00000161CA9F2EB0> abc
test1: <__main__.DemoClass object at 0x00000161CA9F2EB0>

----------------

__new__(): <class '__main__.DemoClass'> ('xyz',) {}
instance: <__main__.DemoClass object at 0x00000161CA9F2DF0> 1
__init__(): <__main__.DemoClass object at 0x00000161CA9F2DF0> xyz
test2: <__main__.DemoClass object at 0x00000161CA9F2DF0>

----------------

0 2
1 2
  • Python中存在于类中的构造方法__init__()负责将类实例化,而在__init__()执行之前,__new__()负责制造这样的一个实例对象,以便__init__()去让该实例对象更加的丰富(为其添加属性等)。

  • 同时:__new__()方法还决定是否要使用该__init__()方法,因为__new__()可以调用其他类的构造方法或者直接返回别的对象来作为本类的实例。

如果将类比喻为工厂,那么init()方法则是该工厂的生产工人,init()方法接受的初始化参 数则是生产所需原料,init()方法会按照方法中的语句负责将原料加工成实例以供工厂出货。而 new()则是生产部经理,new()方法可以决定是否将原料提供给该生产部工人,同时它还决定着出 货产品是否为该生产部的产品,因为这名经理可以借该工厂的名义向客户出售完全不是该工厂的产品。

需要注意的是

  1. 在实例化test1的时候,“项目经理”把自己的cls.instances_createdtest1.instances_created地址弄成一样的了
  2. 在在实例化test2的时候,“项目经理”还是那个项目经理,把自己的cls.instances_created地址改变赋给test2.instances_created,此时test1.instances_created地址跟着改变。
    所以最后test1test2instances_created属性值一样。

用这个原理,就可以将__new__重新覆写,让他返回单例

class Singleton(object):

    def __new__(cls):
        # 关键在于这,每一次实例化的时候,我们都只会返回这同一个instance对象
        if not hasattr(cls, 'instance'):
            cls.instance = super(Singleton, cls).__new__(cls)

        return cls.instance


obj1 = Singleton()
obj2 = Singleton()
obj1.attr1 = 'value1'
print(obj1.attr1, obj2.attr1)
print(obj1 is obj2)

输出结果为:
value1 value1
True
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容