13

Imagine the following situation in python 3 (I'm using 3.6):

class T(object):
    def __call__(self):
        return 5

class U(T):
    def __call__(self):
        return 10 + super()()

U()()

This results in TypeError: 'super' object is not callable.

Making it work requires Uto be defined as follows:

class U(T):
    def __call__(self):
        return 10 + super().__call__()

Why does the first version not work? I found this related question, but it doesn't answer this question. In fact, this question is also asked in a comment on the answer there.

Further reading about what super() actually returns gives me the impression that the proxy returned by super() would have to implement __call__ and forward to the correct __call__ implementation. From this answer, I get that the proxy object that is returned by super() only has a __getattribute__ method that returns the correct function of whichever parent.

If I understand correctly, that means that the proxy would only need to implement the following thing to make super()() work:

def __call__(self, *args, **kwargs):
    try:
        return self["__call__"](*args, **kwargs)  # not sure if self is already bound to the method, if not that needs to be handled
    except AttributeError as ae:
        raise TypeError("Super is not callable") from ae

So why does it not do that?

RunOrVeith
  • 4,487
  • 4
  • 32
  • 50
  • As Martijn states in the linked question, *"This applies to any hook that needs to call the overridden method on the superclass."* Per PEP-20 [*"Special cases aren't special enough to break the rules."*](https://www.python.org/dev/peps/pep-0020/) – jonrsharpe Jan 23 '19 at 10:23
  • @jonrsharpe As to your first comment, it still works in Python 3, so it's still correct syntax if you want to make it backwards compatible. And it's an interesting question, I would imagine though that they made a choice to not build in `__call__` since it would be the odd one out as nothing else is. – Peter Jan 23 '19 at 10:26
  • 2
    @RunOrVeith according to your logic, `super` should also automagically call `__init__` - IOW instead of explicitely calling `super().__init__(arg, otherarg)` we should be able to just write `super(arg, otherarg)`. Which of course won't work since the `super` class needs to have it's own constructor and initializer... – bruno desthuilliers Jan 23 '19 at 10:46
  • 4
    Yeah, I get why it doesn't work for `__init__`. But for `__call__` it would work without any major hacks (in my opinion), or wouldn't it? – RunOrVeith Jan 23 '19 at 11:52
  • Implementing some subset of magic methods just produces inconsistent and confusing behavior. – user2357112 Sep 15 '22 at 21:09

0 Answers0