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

Reply via email to