python的__init__和__new__
阿新 • • 發佈:2019-01-05
本文所有例項程式碼在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__。