The question I'm about to ask seems to be a duplicate of Python's use of __new__ and __init__?, but regardless, it's still unclear to me exactly what the practical difference between __new__ and __init__ is.

在你急于告诉我__new__是用来创建对象,__init__是初始化对象之前,让我明确地说:I get that.,事实上,这个区别对我来说是很自然的,因为我有C++的经验,我们有placement new个,这同样地将对象分配与初始化分开.

Python C API tutorial人解释如下:

新成员负责

所以,是的,我知道__new__是做什么的,但尽管如此,我不明白为什么它在Python中有用.给出的示例表明,如果您希望"确保实例变量的初始值",那么__new__可能很有用.__init__不就是这么做的吗?

在C API教程中,显示了一个示例,其中创建了一个新类型(称为"Noddy"),并定义了该类型的__new__函数.Noddy类型包含一个名为first的字符串成员,该字符串成员初始化为空字符串,如下所示:

static PyObject * Noddy_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
    .....

    self->first = PyString_FromString("");
    if (self->first == NULL)
    {
       Py_DECREF(self);
       return NULL;
    }

    .....
}

请注意,如果没有这里定义的__new__方法,我们必须使用PyType_GenericNew,它只是将所有实例变量成员初始化为NULL.所以__new__方法的唯一好处是实例变量将以空字符串开始,而不是NULL.But why is this ever useful, since if we cared about making sure our instance variables are initialized to some default value, we could have just done that in the 103 method?

推荐答案

区别主要出现在可变类型和不可变类型之间.

__new__接受type作为第一个参数,并且(通常)返回该类型的新实例.因此,它适用于可变和不可变类型.

__init__接受instance作为第一个参数,并修改该实例的属性.这不适用于不可变类型,因为它允许在创建后通过调用obj.__init__(*args)修改它们.

比较tuplelist的行为:

>>> x = (1, 2)
>>> x
(1, 2)
>>> x.__init__([3, 4])
>>> x # tuple.__init__ does nothing
(1, 2)
>>> y = [1, 2]
>>> y
[1, 2]
>>> y.__init__([3, 4])
>>> y # list.__init__ reinitialises the object
[3, 4]

至于为什么它们是分开的(除了简单的历史原因):__new__个方法需要一堆样板才能正确(最初创建对象,然后记住在结束时返回对象).相比之下,__init__方法非常简单,因为您只需设置需要设置的任何属性.

除了__init__个方法更容易编写,以及上面提到的可变与不可变的区别之外,还可以利用这种分离,通过在__new__中设置任何绝对必需的实例不变量,使在子类中调用父类__init__成为可选的.不过,这通常是一种可疑的做法——如果需要,只调用父类__init__方法通常会更清楚.

C++相关问答推荐

AVX-512 BF 16:直接加载bf 16值,而不是从fp 32转换

从组播组地址了解收到的数据包长度

如何使用低级C++写出数值

将常量转换为指针会增加.数据大小增加1000字节

使用双指针动态分配和初始化2D数组

字符是否必须转换为无符号字符,然后才能与getc家族的返回值进行比较?

X86/x64上的SIGSEGV,由于原始内存访问和C中的DS寄存器之间的冲突,在Linux上用TCC编译为JIT引擎

为什么cudaFree不需要数据 struct 的地址?

为什么中断函数会以这种方式影响数组?

OpenSSL:如何将吊销列表与SSL_CTX_LOAD_VERIFY_LOCATIONS一起使用?

S和查尔有什么不同[1]?

指向不同类型的指针是否与公共初始序列规则匹配?

C语言中的数字指针

GetText不适用于包含国际字符的帐户名称

如何读取程序中嵌入的数据S自己的ELF?

unions 的原子成员是个好主意吗?

当我将偏移量更改为任何非零值时,C中的mmap共享内存出现无效参数错误

';malloc():损坏的顶部大小';分配超过20万整数后

UpDown控制与预期相反

malloc 属性不带参数