本文所有实例代码在python3.7下
一.__new__和__init__区别
1.__new__先于__init__执行;__new__是相当于其他OOP语言的构造方法,负责创建实例;之后,__init__负责初始化实例属性。__new__处理对象创建,__ init__处理对象初始化。
2.__new__是一个特殊的静态方法(没有使用装饰器 @staticmethod);由python解释器调用,如果该类没有__new__,则调用父类的__new__.
3.如果我们创建一个类的实例,代码如下:
class Foo: def __new__(cls, *args, **kwargs): return super().__new__(cls) def __init__(self, x, y): self.__x = x self.__y = y foo = Foo(10, 20)
__init__返回为None;
__new__返回了一个创建的实例,其后作为__init__中的self传入
4.通过__new__创建实例,通常是
super().__new__(cls)
# cls为当前要创建的类
5.如果__new__返回它自己的类的实例,那么将使用实例作为第一个被调用的__init__方法的self参数,__init__将隐式调用。
如果__new__方法返回除这个类之外的其他实例,则不会调用实例__init__方法。在这种情况下,您必须自己调用__init__方法。
看一个返回类实例之外的例子:
class Foo: def __init__(self, x): self.__x = x @property def x(self): return self.__x class Bar: def __new__(cls, *args, **kwargs): foo = super().__new__(Foo) foo.__init__(*args, **kwargs) return foo bar = Bar(10) print(bar.x)
看一个返回自身类实例的:
class Bar: def __new__(cls, *args, **kwargs): foo = super().__new__(cls) return foo def __init__(self, x): self.__x = x @property def x(self): return self.__x bar = Bar(10) print(bar.x)
二.__new__的一些用途
大多数情况下都不需要重写__new__。
1.单例模式:
class Foo: __instance = None def __new__(cls, *args, **kwargs): if not cls.__instance: cls.__instance = super().__new__(cls) return cls.__instance foo1 = Foo() foo2 = Foo() print(foo1, foo2)
输出:
<__main__.Foo object at 0x0000029A4B879048> <__main__.Foo object at 0x0000029A4B879048>
可以看出foo1和foo2是同一个实例
2.限制实例的创建数量:
class Foo: __instance = [] limit = 2 def __new__(cls, *args, **kwargs): print(len(cls.__instance)) if len(cls.__instance) == cls.limit: raise RuntimeError("Count not create instance. Limit %s reached" % cls.limit) instance = super().__new__(cls) cls.__instance.append(instance) return instance def __del__(self): self.__instance.remove(self) foo1 = Foo() foo2 = Foo() print(foo1, foo2)
3.自定义实例创建
您可以自定义创建的实例,并在调用初始化程序__init__之前对其进行一些操作。此外,您可以基于某些约束对实例创建施加限制
def is_create(): #根据条件判断是否可以创建 return True class Foo: def __new__(cls, a, b): if not is_create(): raise RuntimeError('实例不能被创建') instance = super().__new__(cls) instance.count = a + b return instance def __init__(self, a, b): pass foo = Foo(1, 2) print(foo.count)
4.自定义返回的对象
通常,当您实例化类时,它将返回该类的实例。您可以自定义此行为,并且可以返回所需的对象。
class Foo: def __new__(cls, a, b): instance = super().__new__(cls) instance.__init__(a, b) return a + b def __init__(self, a, b): print('a+b') foo = Foo(1, 2) print(foo)
如果我们不从__new__方法返回实例对象,则必须显式调用__init__。