为什么在课堂上定义'__new__'和'__init__'

zjm*_*126 10 python class

我认为你可以在一个类中定义' __init__'或' __new__',但为什么在django.utils.datastructures.py中定义了所有.

我的代码:

class a(object):
    def __init__(self):
        print  'aaa'
    def __new__(self):
        print 'sss'

a()#print 'sss'

class b:
    def __init__(self):
        print  'aaa'
    def __new__(self):
        print 'sss'
b()#print 'aaa'
Run Code Online (Sandbox Code Playgroud)

datastructures.py:

class SortedDict(dict):
    """
    A dictionary that keeps its keys in the order in which they're inserted.
    """
    def __new__(cls, *args, **kwargs):
        instance = super(SortedDict, cls).__new__(cls, *args, **kwargs)
        instance.keyOrder = []
        return instance

    def __init__(self, data=None):
        if data is None:
            data = {}
        super(SortedDict, self).__init__(data)
        if isinstance(data, dict):
            self.keyOrder = data.keys()
        else:
            self.keyOrder = []
            for key, value in data:
                if key not in self.keyOrder:
                    self.keyOrder.append(key)
Run Code Online (Sandbox Code Playgroud)

什么情况下SortedDict.__init__会被召唤.

谢谢

Ale*_*lli 20

您可以定义一个或两个__new____init__.

__new__必须返回一个对象 - 可以是一个新对象(通常是该任务被委托type.__new__),一个现有对象(实现单例,从池中"循环"实例等),或者甚至是一个不是实例的对象班级.如果__new__返回类的实例(新的或现有的),__init__则调用它; 如果__new__返回一个对象,这不是一个类的实例,则__init__叫.

__init__传递一个类实例作为其第一个项目(在相同的状态下__new__返回它,即通常为"空"),并且必须根据需要对其进行更改以使其可以使用(通常通过添加属性).

一般来说,最好是尽其所能地使用__init__- 而且__new__,如果留下了一些__init__不能做的事情,那就是"额外的东西".

因此,您通常会定义两者是否可以执行某些有用的操作__init__,但不会定义在实例化类时您希望发生的所有操作.

例如,考虑一个子类int但也有一个foo插槽的类 - 你希望它用一个初始化器int和一个初始化器来实例化.foo.由于int不可变,这部分必须发生__new__,所以迂腐地可以编码:

>>> class x(int):
...   def __new__(cls, i, foo):
...     self = int.__new__(cls, i)
...     return self
...   def __init__(self, i, foo):
...     self.foo = foo
...   __slots__ = 'foo',
... 
>>> a = x(23, 'bah')
>>> print a
23
>>> print a.foo
bah
>>> 
Run Code Online (Sandbox Code Playgroud)

在实践中,对于一个简单的案例,没有人会介意你失去了__init__,只是移动self.foo = foo到了__new__.但是如果初始化很丰富且复杂到最好__init__,那么这个想法值得记住.


pav*_*kha 9

__new____init__做完全不同的事情.该方法__init__启动一个类的新实例---它是一个构造函数.__new__是一个更微妙的东西---它可以改变参数,事实上,它可以改变发起对象的类.例如,以下代码:

class Meters(object):
    def __new__(cls, value):
        return int(value / 3.28083)
Run Code Online (Sandbox Code Playgroud)

如果你打电话,Meters(6)你实际上不会创建一个实例Meters,而是一个实例int.你可能想知道为什么这是有用的; 它对于元类来说实际上是至关重要的,这是一个公认的模糊(但功能强大)的功能.

您会注意到,在Python 2.x中,只有继承自的类object可以利用__new__,如上面的代码所示.

__new__在django中显示的使用似乎是试图在SortedDict对象上保持理智的方法解析顺序.但我承认,通常很难说为什么__new__有必要.标准Python风格表明除非必要,否则不会使用它(一如既往,更好的类设计是您首先使用的工具).

  • `__new__`是构造函数,`__ init__`是......只是初始化 (6认同)
  • @Anurag:小心翼翼地说,你是对的.但是,如果你来自Python以外的语言,最好被告知`__init__`是构造函数 - 人们在没有我帮助的情况下滥用功能就足够了.所以,我在我的回复中保留了`__init__`作为构造函数,以造福于其他人. (2认同)