Python __new__
翻译一点 https://www.python.org/download/releases/2.2/descrintro/#__new__ 有些感觉还是挺生硬的,方便自己理解吧。
__new__ 的一些规则:
__new__是一个静态方法。定义它的时候并不需要执行__new__ = staticmethod(__new__),因为它的名字就包含了这个含义(这个对于类构造方法来说是个特殊的函数)__new__的第一个参数,必须是一个类,其余的参数是留给构造方法的。- 覆盖了基类的
__new__方法的类有可能会调用基类的__new__方法。传递给基类的__new__方法的第一个参数,应该是覆盖基类的__new__方法的类,而不是基类,如果传递了基类,你得到的将是基类的示例。 - 除非你想要按照后面两条描述的方法来使用,否则
__new__方法必须要调用基类的__new__方法,这个是创建你的对象的实例的唯一方法。子类的__new__方法可以从两个方面影响产生的实例:传递不同的参数给基类的__new__,以及修改基类产生的对象(例如初始化一些实例变量) __new__方法必须返回一个对象。并不一定必须返回一个新的对象,虽然通常都那么做。如果你返回一个已经存在的对象,依然会有对于__init__构造函数的调用。如果你返回一个其他函数的对象,那个对象的__init__也会被调用。如果忘记返回,python 会给你返回 None,你程序的调用方也许会觉得很奇怪。- 对于不可变对象,
__new__可以返回一个之前缓存的对象。对于一些比较小的 int, str, tuple 类型就是这么做的。这也是为什么他们的__init__什么都没做:否则之前缓存的对象会被 init 很多次。(另外一个原因是本身页没有东西可以给__init__初始化的了,__new__返回的就是一个已经初始化的对象)。 - 如果你想要给一个内置的不可变类型增加一些可变的状态(例如给 string 类型增加一个默认的转换方法),最好是在
__init__方法里面初始化可变状态,而不要在__new__里面。 - 如果你想要修改构造方法的签名,一般需要覆盖
__new__和__init__方法来接受心的签名。然而,大部分内置类型都会忽视自己不用的参数,尤其是不可变类型(int,long,float,complex,str,unicode,tuple)都有一个假的__init__,而可变类型(dict,list,file,super,classmethod,staticmethd,property)有一个假的__new__。内置类型object有假的__init__和__new__(给其他对象继承)。内置类型type在很多方面都很特别,请参考 metaclasses。 - (这条和
__new__没关系,但是页应该了解一下)如果新建一个type的子类,实例会自动给__dict__和__weakrefs__预留空间(__dict__在你使用前不会初始化,所以你不需要担心创建的所有实例被一个空的字典所占用的空间)。如果不需要这个多余的空间,可以给你的类设置__slots__ = [](更多信息可以参考__slots__。 - Factoid:
__new__是一个静态方法,不是类方法。我开始的时候觉得他应该是一个类方法,and that’s why I added the classmethod primitive。不幸的是,对于一个类方法,在这种情况下面 upcalls 不工作,所以我只好把他设计成一个第一个参数是一个 class 的静态方法。讽刺的是,there are now no known uses for class methods in the Python distribution (other than in the test suite). I might even get rid of classmethod in a future release if no good use for it can be found!