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.
--
https://mail.python.org/mailman/listinfo/python-list