python的new与init

基于文章:Why is init() always called after new()?code

特别说明:对象

  1. 这篇文章的灵感来源于stackoverflow的一个提问,准确说,我只是作了些知识梳理的工做,对其中的优秀回答进行了总结和提炼,旨在帮助本身和读者对此有个深入的认识。内存

  2. 本文章节中的new是__new__的简写,init是__init__的简称,只是为了语言叙述的方便而作出的省略。get

Part I: 为何new老是先于init?

new是静态的类方法,static method。
init是实例方法it

它们有不一样的参数与返回值:io

  1. new的参数老是:cls 返回值老是self
  2. init的参数老是:self 老是无返回值

Part II: 三段代码的思考

Block 1: 基于原文的代码

class B(object):
    _dict = dict()

    def __new__(cls):
        if 'key' in B._dict:
            print("EXISTS:", B._dict['key'])
            return B._dict['key']
        else:
            print("NEW")
            return super(B, cls).__new__(cls)

    def __init__(self):
        print("INIT")
        B._dict['key'] = self
        print("")


b1 = B()
b2 = B()
b3 = B()

# 运行结果以下:
NEW
INIT

EXISTS: <__main__.B object at 0x0000028F29820828>
INIT

EXISTS: <__main__.B object at 0x0000028F29820828>
INIT

关于原文中的代码解释:class

在每次实例化以前,也就是new的操做时,都查询了是否存在第一个实例。在第一次初始化时,把第一个实例self赋值给了类的公有属性:test_dict。以后的每次实例化以前,new都会查询到它(实例)已经存在,new而且老是返回了第一个实例给了init。而后init参与对该实例(老是第一个实例)进行构建工做。test

我只能揣测,原问题的做者彷佛意外建立了一个单例的类。你能够在init中执行print(self),会发现打印出来的对象老是第一个实例。固然,若是确实是想要实现单例模式,应该使用装饰器。即:object

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...

为何instances使用的是字典?由于Python老是用字典去存储一个新的实例,而且init中的属性也一样以字典的方法存储的。固然,若是你想节约内存,不使用字典而用列表,能够重载new方法,或者使用__slot__方法

Block 2: 基于Block 1 的修改

class A(object):
    test_dict = dict()                   

    def __new__(cls):                    
        if 'key' in A.test_dict:
            print("EXISTS:", A.test_dict['key'])
            return A.test_dict['key']
        else:
            print("NEW")
            return super(A, cls).__new__(cls)

    def __init__(self):                  
        print("INIT")
        if 'key' in A.test_dict:
            print('修改')
            A.test_dict['key'] += 1
        else:
            print('第一次建立')
            A.test_dict['key'] = 0
        print('')


a1 = A()
a2 = A()
a3 = A()

Block 3: 基于Block 2 的修改

class A(object):
    test_dict = dict()                    1.类的公有属性

    def __new__(cls):                     2.执行__new__
        if 'key' in A.test_dict:
            print("EXISTS:", A.test_dict['key'])
            return super(A, cls).__new__(cls)
        else:
            print("NEW")
            return super(A, cls).__new__(cls)

    def __init__(self):                  
        print("INIT")
        if 'key' in A.test_dict:
            print('修改')
            A.test_dict['key'] += 1
        else:
            print('第一次建立')
            A.test_dict['key'] = 0
        print('')


a1 = A()
a2 = A()
a3 = A()

Q&A

  1. new 老是先于 int 执行,为何?
    答:
    注意事项: new是类的静态方法,
    Use new when you need to control the creation of a new instance.
    Use init when you need to control initialization of a new instance.
    前者用于控制建立一个新实例,后者用于控制对该新实例进行初始化。

精要:
它们负责的工做不一样:前者负责建立新实例,后者负责实例初始化
它们服务的层级不一样:前者是cls(类),后者是self(实例自己)
__new__是秘书给领导打工,后者领导的一众小弟们打工。

  1. 为何上述代码的__init__没有被执行,而下面的每次都正常执行了?
    答:
    用于我在上述代码中恶意使用了new, 没有对new进行返回实例。
    __new__老是第一个被Call(调用),而且他的返回值:当且仅当是一个新的实例!!
    代码1中,并无返回这个新的实例,第一次实例化对象,自动进行了int,后面的, 都是只建立了新示例
相关文章
相关标签/搜索