On Sun, May 4, 2014 at 8:16 AM, Steven D'Aprano <steve+comp.lang.pyt...@pearwood.info> 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. > > Whatever the difficulty is with __new__, it isn't something obvious.
You cheated on two counts here. First, you're using super; I think Guido's comment about "upcalls" in the link you posted earlier was in reference to calls that explicitly name the name parent class, i.e. "dict.fromkeys()", not "super(MyDict, cls).fromkeys()". Second, you didn't override the method in AnotherDict, so "MyDict.fromkeys" and "AnotherDict.fromkeys" refer to the same method, the only difference being in which class is passed to the descriptor when it is accessed. Compare to this: class MyDict(dict): @classmethod def fromkeys(cls, *args, **kwargs): print "MyDict Called from", cls return dict.fromkeys(*args, **kwargs) class AnotherDict(MyDict): @classmethod def fromkeys(cls, *args, **kwargs): print "AnotherDict Called from", cls return MyDict.fromkeys(*args, **kwargs) >>> MyDict.fromkeys('abc') MyDict Called from <class '__main__.MyDict'> {'a': None, 'c': None, 'b': None} >>> AnotherDict.fromkeys('abc') AnotherDict Called from <class '__main__.AnotherDict'> MyDict Called from <class '__main__.MyDict'> {'a': None, 'c': None, 'b': None} -- https://mail.python.org/mailman/listinfo/python-list