Why has __new__ been implemented as a static method?
Rotwang
sg552 at hotmail.co.uk
Sun May 4 12:24:11 EDT 2014
On 04/05/2014 15:16, Steven D'Aprano wrote:
> On Sun, 04 May 2014 20:03:35 +1200, Gregory Ewing wrote:
>
>> Steven D'Aprano wrote:
>>> If it were a class method, you would call it by MyBaseClass.__new__()
>>> rather than explicitly providing the cls argument.
>>
>> But that wouldn't be any good, because the base __new__ needs to receive
>> the actual class being instantiated, not the class that the __new__
>> method belongs to.
>
>
> Which is exactly what method descriptors -- whether instance methods or
> class descriptors -- can do. Here's an example, using Python 2.7:
>
> class MyDict(dict):
> @classmethod
> def fromkeys(cls, *args, **kwargs):
> print "Called from", cls
> return super(MyDict, cls).fromkeys(*args, **kwargs)
>
> class AnotherDict(MyDict):
> pass
>
>
> And in use:
>
> py> MyDict.fromkeys('abc')
> Called from <class '__main__.MyDict'>
> {'a': None, 'c': None, 'b': None}
> py> AnotherDict().fromkeys('xyz')
> Called from <class '__main__.AnotherDict'>
> {'y': None, 'x': None, 'z': None}
>
>
> In both cases, MyDict's __new__ method receives the class doing the
> calling, not the class where the method is defined.
Yes, when a classmethod bound to a subclass or an instance is called.
But this is irrelevant to Gregory's point:
On 04/05/2014 04:37, Steven D'Aprano wrote:
> On Sun, 04 May 2014 11:21:53 +1200, Gregory Ewing wrote:
>> Steven D'Aprano wrote:
>>> I'm not entirely sure what he means by "upcalls", but I believe it
>>> means to call the method further up (that is, closer to the base) of
>>> the inheritance tree.
>>
>> I think it means this:
>>
>> def __new__(cls):
>> MyBaseClass.__new__(cls)
>>
>> which wouldn't work with a class method, because MyBaseClass.__new__
>> would give a *bound* method rather than an unbound one.
>
> If it were a class method, you would call it by MyBaseClass.__new__()
> rather than explicitly providing the cls argument.
The relevant behaviour is this:
>>> class C:
@classmethod
def m(cls):
print("Called from", cls)
>>> class D(C):
@classmethod
def m(cls):
C.m()
>>> C.m()
Called from <class '__main__.C'>
>>> D.m()
Called from <class '__main__.C'>
If __new__ were a classmethod, then a call to MyBaseClass.__new__()
within the body of MySubClass.__new__ would pass MyBaseClass to the
underlying function, not the MySubClass. This means that
class MySubClass(MyBaseClass):
def __new__(cls):
return MyBaseClass.__new__()
would fail, since it would return an instance of MyBaseClass rather than
MySubClass.
More information about the Python-list
mailing list