什么可以`__init__`做那个`__new__`不能?

Nei*_*l G 29 python initialization

在Python中,__new__用于初始化不可变类型,__init__通常初始化可变类型.如果__init__从语言中删除,那么就不能再轻松完成了什么?

例如,

class A:

    def __init__(self, *, x, **kwargs):
        super().__init__(**kwargs)
        self.x = x


class B(A):

    def __init__(self, y=2, **kwargs):
        super().__init__(**kwargs)
        self.y = y
Run Code Online (Sandbox Code Playgroud)

可以__new__像这样重写:

class A_N:

    def __new__(cls, *, x, **kwargs):
        obj = super().__new__(cls, **kwargs)
        obj.x = x
        return obj


class B_N(A_N):

    def __new__(cls, y=2, **kwargs):
        obj = super().__new__(cls, **kwargs)
        obj.y = y
        return obj
Run Code Online (Sandbox Code Playgroud)

澄清问题范围:这不是关于如何使用__init____new__使用它们或它们之间有什么区别的问题.这是一个关于如果__init__从语言中删除会发生什么的问题.什么事情会破裂?有什么事情会变得更难或不可能吗?

And*_*yko 19

注意__new__和__init__之间的区别

在解释缺失的功能之前,让我们回到定义__new____init__:

__new__是实例创建的第一步.它首先被调用,并负责返回您的类的新实例.

但是,__ init__不会返回任何内容 ; 它只负责在创建实例后初始化它.

将__init__替换为__new__的后果

主要是你的灵活性会松动.你会得到很多语义上的头痛和初始化和构造的松散分离(通过加入__new__ andinit我们将结构和初始化结合到一个步骤......).我们来看看下面的代码片段:

class A(object):
    some_property = 'some_value'

    def __new__(cls, *args, **kwargs):
        obj = object.__new__(cls, *args, **kwargs)
        obj.some_property = cls.some_property
        return obj


class B(A):
    some_property = 2

    def __new__(cls, *args, **kwargs):
        obj = super(B, cls).__new__(cls)
        return obj
Run Code Online (Sandbox Code Playgroud)

__init__行动转移到的后果__new__:

  1. B之前初始化A:当您使用__new__方法而不是__init__创建B的新实例的第一步是调用A.__new__副作用时,您无法在初始化B之前A初始化(访问并为新B实例分配一些属性).使用可以__init__提供这种灵活性.

  2. 对初始化顺序的松散控制:让我们假设你B_N继承了两个类(A_N1,A_N2),现在你将错过控制初始化新实例B_N的顺序(你要初始化实例的顺序是什么?这可能是问题......什么是奇怪的.)

  3. 属性和方法混乱:你会错过访问A.some_property(cls等同于B实例化新实例B.但是直接访问A.some_property是可能的,但我的猜测至少很奇怪,通过类名访问类中的属性而不是使用classmethods).

  4. 您无法为此创建新的实例或实现特殊逻辑来重新初始化现有实例(感谢@platinhom的想法)

那可以__init__做什么__new__不可以?

没有__new__不能在__init__其中__init__执行的操作,因为执行的操作是可以执行的操作的子集__new__.

来自Python Docs,Pickling和unpickling普通类实例#obob的有趣时刻.getinitargs关于什么时候__init__可能有用:

当pickle类实例被unpickled时,通常不会调用其init()方法.

  • 我知道他们做了什么,但这并不能解决我的问题. (7认同)
  • 你为什么不能访问`A.some_property`? (3认同)
  • @PadraicCunningham你可以.这个答案几乎是完全错误的. (3认同)
  • @NeilG,我不得不说我的想法是一样的,我很惊讶这有多少赞成. (3认同)
  • 1.如果`cls = B`,则'__new__`将创建B的实例.顺序是继承顺序,就像`__init__`一样.3.您可以通过传递的已创建对象访问属性. (2认同)

Gin*_*lus 4

您可以在 中做的一切__init__也可以在 中完成__new__

那么,为什么要使用 呢__init__
因为您不必将实例存储在变量中(obj在示例代码中),然后再费心返回它。您可以专注于您真正想做的事情 - 初始化可变对象。