Python之__new__,__init__

先看一个简单的类,包括一个__init__和一个__new__方法

#!/usr/bin/env python

# -*- coding: utf-8 -*-
# Time : 2019-08-22 18:24
# Auth : lihui
# File : start.py

class A:
    def __init__(self):
        print("A __init__")

    def __new__(cls, *args, **kwargs):
        print("A __new__")
        return super(A, cls).__new__(cls)

if __name__ == "__main__":
    A()

先看下执行结果

A __new__
A __init__

从这里可以看出,整个对象的初始化过程,是先执行__new__方法,再来执行__init__方法的

看一下Python的官方文档,这里版本是Python3.7.4

从官方文档可以总结出以下几点:

1:创建cls类实例的是__new__方法,如果要得到当前类的实例,得在当前类的__new__方法中调用其父类的__new__方法

2:__new__创建实例之后,返回一个cls实例,传给__init__的self参数,来完成一些初始化工作

3:如果__new__并没有返回一个cls实例,那么__init__方法是不会执行的

4:__init__必须返回None

下面就逐一测试一下

首先可以在__new__和__init__加一些类和实例的打印

#!/usr/bin/env python

# -*- coding: utf-8 -*-
# Time : 2019-08-22 18:24
# Auth : lihui
# File : start.py

class A:
    def __init__(self):
        print("__init__ A")
        print("__init__", self)

    def __new__(cls, *args, **kwargs):
        print("__new__ A")
        print("__new__", cls)
        a = super(A, cls).__new__(cls)
        print("__new__", a)
        return a

if __name__ == "__main__":
    A()

输出结果如下

__new__ A
__new__ <class '__main__.A'>
__new__ <__main__.A object at 0x101f0c290>
__init__ A
__init__ <__main__.A object at 0x101f0c290>

从结果可以看出来__new__里返回的对象a和__init__里初始化的self是同一个class A类型的对象

但如果__new__方法没有返回实例的话

#!/usr/bin/env python

# -*- coding: utf-8 -*-
# Time : 2019-08-22 18:24
# Auth : lihui
# File : start.py

class A:
    def __init__(self):
        print("__init__ A")
        print("__init__", self)

    def __new__(cls, *args, **kwargs):
        print("__new__ A")
        print("__new__", cls)
        a = super(A, cls).__new__(cls)
        print("__new__", a)

if __name__ == "__main__":
    A()

输出结果只有__new__方法的执行情况,__init__并没有执行

__new__ A
__new__ <class '__main__.A'>
__new__ <__main__.A object at 0x10df32290>

也就是说,这时候class A类型实例都没有创建出来,调用__init__也没啥意义

再如果__new__正常返回了,但是__init__完成之后有一个返回值,看看结果

#!/usr/bin/env python

# -*- coding: utf-8 -*-
# Time : 2019-08-22 18:24
# Auth : lihui
# File : start.py

class A:
    def __init__(self):
        print("__init__ A")
        print("__init__", self)
        return True

    def __new__(cls, *args, **kwargs):
        print("__new__ A")
        print("__new__", cls)
        a = super(A, cls).__new__(cls)
        print("__new__", a)
        return a

if __name__ == "__main__":
    A()

这时候就会出现报错

Traceback (most recent call last):
  File "/Users/lihui/Documents/Python/leetcode/start.py", line 22, in 
    A()
TypeError: __init__() should return None, not 'int'
__new__ A
__new__ <class '__main__.A'>
__new__ <__main__.A object at 0x10cc632d0>
__init__ A
__init__ <__main__.A object at 0x10cc632d0>

Process finished with exit code 1

最后再来看下初始化参数传入

#!/usr/bin/env python

# -*- coding: utf-8 -*-
# Time : 2019-08-22 18:24
# Auth : lihui
# File : start.py

class A:
    def __init__(self, a, b):
        print("__init__:", a, b)
        print("__init__:", id(a), id(b))
        self.a = a
        self.b = b
        print("__init__:", self.a, self.b)

    def __new__(cls, *args, **kwargs):
        print("__new__:", args)
        print("__new__:", id(args[0]), id(args[1]))
        return super(A, cls).__new__(cls)

if __name__ == "__main__":
    A(1, 2)

执行结果如下

__new__: (1, 2)
__new__: 4347465488 4347465520
__init__: 1 2
__init__: 4347465488 4347465520
__init__: 1 2

在执行A(1, 2)时,先执行类A的__new__方法,cls就是A,args就是1和2,方法里执行A的父类的__new__方法,并入args两个参数,创建了A的实例并返回,实例创建之后就会调用__init__方法,self指向这个实例对象,接收参数进行对象的一些初始化工作,这就是两者的区别

发表评论