15

In learning about Python's data model, I am playing with creating objects from existing objects using the __new__ method. Here are some examples which create new objects of various types:

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__)

However, the following three experiments give me errors:

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__)

The errors are (respectively):

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

Why don't these three examples work? (Note: for the lambda example it appears that I have to pass in a code fragment when I invoke the __new__ method but I don't know how to do that.) I am using Python 2.6.

Please note that I realize this is not necessarily the way you would want to create new objects in real code, but my purpose is not practical, rather, it is to understand how the low-level object methods work.

rlandster
  • 7,294
  • 14
  • 58
  • 96

1 Answers1

16

It's nothing too special, it's just that for some types there is a default "empty" object of that type, while for others there is not. Your working examples are basically equivalent to:

int()
dict()
list()
float()
str()
complex()
tuple()

. . . all of which work. Your last three examples are basically trying to create new instances of NoneType, function, and type.

  1. NoneType fails for a unique reason, because None is a singleton --- the NoneType type can only ever have one instance, namely the None object. (The specific error message you get is a little strange, but if you do types.NoneType() you'll get a more direct message saying "Can't create NoneType instances".)
  2. function fails because, as you saw, it requires an argument, and you don't provide one. What you'd need is a code object, which you could get from an existing function or from the compile function. (It also requires a globals argument, which can just be a dict.)
  3. type fails because you didn't give enough arguments. You can either do type(foo) to get the type of foo, or type(name, bases, dict) to create a new type (i.e., a class).

Notice incidentally that in your last example you are taking the type of object, which is itself a type. If you do x = object() instead (making x be an individual object rather than the object type) then it will work and create a "blank" object.

The thing to remember is that calling __new__ is not really that magical. It is just what happens when you directly try to instantiate the type by doing someType(). If that type requires arguments, calling __new__ will fail, just like any other function call will fail if you don't give it the right arguments, because type(x).__new__ is just a function like any other function. You can see this with a user-defined class:

>>> 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)

It succeeded in the first case, because my class didn't require arguments; it failed in the second class, because the second class does require arguments.

The __new__ does not fail for any secret reason; it just fails because the type you are trying to instantiate requires arguments in order to construct an instance. (The None case is the only one that's different here; that one does fail for a special reason, because None is a special object in Python.)

BrenBarn
  • 242,874
  • 37
  • 412
  • 384