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.
The __new__() is a static method of the object class. When you create a new object by calling the class, Python calls the __new__() method to create the object first and then calls the __init__() method to initialize the object's attributes.
The __add__() method in Python specifies what happens when you call + on two objects. When you call obj1 + obj2, you are essentially calling obj1.
TLDR; __init() is not the constructor, __new__() is. Generally, developers new to python are told that __init__() method is called the constructor.
The method __getitem__(self, key) defines behavior for when an item is accessed, using the notation self[key] . This is also part of both the mutable and immutable container protocols. Example: # Code to demonstrate use. # of __getitem__() in python.
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
.
types.NoneType()
you'll get a more direct message saying "Can't create NoneType instances".)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.)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.)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With