__new__
does not receive an instance as its first parameter. How can this happen when (a) it is a static method, as you noticed, and (b) its task is to create an instance and return it! The first parameter __new__
conditionally called cls
, since it is a class.
Because of what, the error message you specify is very strange; this is usually an error message that you will get when you call an unrelated method (i.e. what you get by referring to ClassName.methodName
) with something other than an instance of this class, as a self
parameter. However, staticmethods (including __new__
) do not become unrelated methods, they are just simple functions that are class attributes:
>>> class Foo(object): def __new__(cls, *args, **kwargs): return object.__new__(cls) def method(self): pass >>> class Bar(object): pass >>> Foo.method <unbound method Foo.method> >>> Foo.__new__ <function __new__ at 0x0000000002DB1C88> >>> Foo.method(Bar()) Traceback (most recent call last): File "<pyshell#36>", line 1, in <module> Foo.method(Bar()) TypeError: unbound method method() must be called with Foo instance as first argument (got Bar instance instead) >>> Foo.__new__(Bar) <__main__.Bar object at 0x0000000002DB4F28>
From this, you can verify that __new__
should never be an unrelated method. In addition (as opposed to the usual method), you do not care that you agree on what you transmit; I managed to create an instance of Bar
by calling Foo.__new__
, because both he and Bar.__new__
were ultimately implemented the same way (putting aside all the actual work to object.__new__
).
However, this led me to a brief summary of the source code for Django itself. The Django Model
class has a metaclass, ModelBase
. This is quite complicated, and I did not understand what he was doing completely, but I noticed something very interesting.
ModelBase.__new__
(metaclass __new__
, which is the function that creates the class at the end of your class block) calls its super __new__
without passing its class dictionary . Instead, it passes the dictionary only with the __module__
attribute __module__
. Then, after doing a whole bunch of processing, he does the following:
# Add all attributes to the class. for obj_name, obj in attrs.items(): new_class.add_to_class(obj_name, obj)
( attrs
is a dictionary containing all of your definitions in your class block, including your __new__
function; add_to_class
is a metaclass method that is basically just setattr
).
Now I'm 99% sure that the problem is here because __new__
is a strange implicitly static method. Therefore, unlike any other static method, you did not apply the staticmethod
decorator to it. Python (at some level) simply recognizes the __new__
method and treats it as a static method, not a regular method [1]. But I bet that this only happens when __new__
defined in a class block, and not when it is set using setattr
.
Thus, your __new__
, which should be a static method, but not processed by the staticmethod staticmethod
, is converted to a regular instance method. Then, when Python calls it passing the class Test
, according to the protocol for creating a regular instance, it complains that it does not receive an instance of Test
.
If all this is correct, then:
- This is not so because Django is a bit broken, but only in that it does not take into account Python inconsistency about
__new__
, static in mind. - Perhaps you could do this work by applying
@staticmethod
to your __new__
method, although you don't need to.
[1] I think this is Python's historical quirk, since __new__
was introduced before the staticmethod
decorator, but __new__
could not take an instance, since there wasnβt to call it.