1. 程式人生 > >python的__init__和__new__

python的__init__和__new__

本文所有例項程式碼在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__。