使用__new__从现有对象中获取Python对象

rla*_*ter 13 python types object instantiation

在学习Python的数据模型时,我正在使用该__new__方法从现有对象创建对象.以下是一些创建各种类型的新对象的示例:

x = 2;     print type(x).__new__(x.__class__)
x = {};    print type(x).__new__(x.__class__)
x = [1,2]; print type(x).__new__(x.__class__)
x = 2.34;  print type(x).__new__(x.__class__)
x = '13';  print type(x).__new__(x.__class__)
x = 1.0j;  print type(x).__new__(x.__class__)
x = True;  print type(x).__new__(x.__class__)
x = (1,2); print type(x).__new__(x.__class__)
Run Code Online (Sandbox Code Playgroud)

但是,以下三个实验给出了错误:

x = None;           print type(x).__new__(x.__class__)
x = lambda z: z**2; print type(x).__new__(x.__class__)
x = object;         print type(x).__new__(x.__class__)
Run Code Online (Sandbox Code Playgroud)

错误是(分别):

TypeError: object.__new__(NoneType) is not safe, use NoneType.__new__()
TypeError: Required argument 'code' (pos 1) not found
TypeError: type() takes 1 or 3 arguments
Run Code Online (Sandbox Code Playgroud)

为什么这三个例子不起作用?(注意:对于lambda示例,我在调用__new__方法时似乎必须传入代码片段,但我不知道该怎么做.)我使用的是Python 2.6.

请注意,我意识到这不一定是您想要在实际代码中创建新对象的方式,但我的目的不实际,而是要了解低级对象方法的工作原理.

Bre*_*arn 14

它没什么特别的,只是对于某些类型,有一种类型的默认"空"对象,而对于其他类型则没有.您的工作示例基本上等同于:

int()
dict()
list()
float()
str()
complex()
tuple()
Run Code Online (Sandbox Code Playgroud)

...所有这些工作.您的最后三个示例基本上是尝试创建NoneType的新实例function,和type.

  1. NoneType由于一个独特的原因而失败,因为None是一个单例--- NoneType类型只能有一个实例,即None对象.(您获得的具体错误消息有点奇怪,但如果您这样做,types.NoneType()您将收到更直接的消息,说"无法创建NoneType实例".)
  2. function失败是因为,如你所见,它需要一个参数,而你没有提供参数.您需要的是一个代码对象,您可以从现有函数或compile函数中获取该代码对象.(它还需要一个globals参数,这可能只是一个字典.)
  3. type失败是因为你没有给出足够的论据.您既可以type(foo)获取foo的类型,也type(name, bases, dict)可以创建新类型(即类).

顺便提一下,在你的上一个例子中,你采用的是类型object,它本身就是一种类型.如果你x = object()改为(使x成为单个对象而不是对象类型),那么它将起作用并创建一个"空白"对象.

要记住的是,召唤__new__并不是那么神奇.当您直接尝试通过执行实例化类型时,会发生什么someType().如果该类型需要参数,则调用__new__将失败,就像任何其他函数调用将失败一样,如果您没有给它正确的参数,因为type(x).__new__它只是一个函数,就像任何其他函数一样.您可以使用用户定义的类来查看:

>>> class Foo(object):
...     pass
>>> x = Foo();           print type(x).__new__(x.__class__)
<__main__.Foo object at 0x00EB0370>
>>> class Foo(object):
...     def __init__(self, someArg):
...         pass
>>> class Foo(object):
...     def __new__(cls, someArg):
...         return super(Foo, cls).__new__(cls)
>>> x = Foo(2);           print type(x).__new__(x.__class__)
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    x = Foo(2);           print type(x).__new__(x.__class__)
TypeError: __new__() takes exactly 2 arguments (1 given)
Run Code Online (Sandbox Code Playgroud)

它在第一种情况下成功了,因为我的班级不需要论证; 它在第二个类中失败了,因为第二个类确实需要参数.

__new__不会失败的任何秘密原因; 它只是失败,因为您尝试实例化的类型需要参数才能构造实例.(这None是唯一一个不同的情况;那个因特殊原因而失败,因为它None是Python中的一个特殊对象.)