super() magic-methods.

```class A: def __eq__(self, other): return '__eq__' class B(A): def __eq__(self, other): print(super() == other) print(super().__eq__(other)) B() == ...``` OUTPUT: False __eq__ As you can see here, when you run the code, __uq__ does not get printed twice. somehow, The expression "super() <OPERATOR> other" does not turn into "super().__OPERATOR__(other)". this bug is for any operator that you apply on super(). I'd be happy to hear from you why it happens and whether will it be fixed in python3.10. Regards - Jonatan.

On Mon, Nov 23, 2020 at 6:29 AM Jonatan <pybots.il@gmail.com> wrote:
A super object isn't an instance of the parent class. It's a special placeholder that remembers the object and the current class, and will forward all method calls to that class. So when you try to do a comparison on it, what happens is something like this: s = super(B, self) comparison = type(s).__eq__(s, other) and then, if that comparison returns NotImplemented, tries the other way around, and various things, and then will return False. But at no time does it check s.__eq__, since comparisons like this are done using the type object, not the instance itself. Because of this, what you'll often see is that a dunder method delegates (with super) directly to a dunder method, not to the operator. Basically, like you do in your second line. :)
I'd be happy to hear from you why it happens and whether will it be fixed in python3.10.
Don't assume that it's a bug to be fixed :) It's a consequence of the way that method lookup is done for these kinds of things, and I doubt that that would be changing any time soon. ChrisA

On Sun, Nov 22, 2020 at 07:28:00PM -0000, Jonatan wrote:
somehow, The expression "super() <OPERATOR> other" does not turn into "super().__OPERATOR__(other)".
Is there something documented that lead you to believe that it should? By the way, for most operators, there is no simple relationship between the operator and the dunder method called. For example, consider addition `x + y`. The interpreter does something *roughly* like this: if y is a subclass of x: try calling y.__radd__(x) if it doesn't exist, or if it returns NotImplemented, try calling x.__add__(y) if it doesn't exist, or returns NotImplemented, raise TypeError otherwise: try calling x.__add__(y) if it doesn't exist, or if it returns NotImplemented, try calling y.__radd__(x) if it doesn't exist, or returns NotImplemented, raise TypeError only I expect I have the details wrong and it may be even more complicated. The point is, `super() operator other` will not, in general, turn into a single dunder method, but potentially two or maybe even more.
this bug is for any operator that you apply on super(). I'd be happy to hear from you why it happens and whether will it be fixed in python3.10.
Before we can "fix" it, we have to agree that it is a bug and that it should be fixed. What gives you the impression that this is a bug? Is the behaviour documented somewhere as working? If we made this change, would it extend to other dunder methods like `__str__`, `__len__`, `__enter__`, etc? -- Steve

On Mon, Nov 23, 2020 at 6:29 AM Jonatan <pybots.il@gmail.com> wrote:
A super object isn't an instance of the parent class. It's a special placeholder that remembers the object and the current class, and will forward all method calls to that class. So when you try to do a comparison on it, what happens is something like this: s = super(B, self) comparison = type(s).__eq__(s, other) and then, if that comparison returns NotImplemented, tries the other way around, and various things, and then will return False. But at no time does it check s.__eq__, since comparisons like this are done using the type object, not the instance itself. Because of this, what you'll often see is that a dunder method delegates (with super) directly to a dunder method, not to the operator. Basically, like you do in your second line. :)
I'd be happy to hear from you why it happens and whether will it be fixed in python3.10.
Don't assume that it's a bug to be fixed :) It's a consequence of the way that method lookup is done for these kinds of things, and I doubt that that would be changing any time soon. ChrisA

On Sun, Nov 22, 2020 at 07:28:00PM -0000, Jonatan wrote:
somehow, The expression "super() <OPERATOR> other" does not turn into "super().__OPERATOR__(other)".
Is there something documented that lead you to believe that it should? By the way, for most operators, there is no simple relationship between the operator and the dunder method called. For example, consider addition `x + y`. The interpreter does something *roughly* like this: if y is a subclass of x: try calling y.__radd__(x) if it doesn't exist, or if it returns NotImplemented, try calling x.__add__(y) if it doesn't exist, or returns NotImplemented, raise TypeError otherwise: try calling x.__add__(y) if it doesn't exist, or if it returns NotImplemented, try calling y.__radd__(x) if it doesn't exist, or returns NotImplemented, raise TypeError only I expect I have the details wrong and it may be even more complicated. The point is, `super() operator other` will not, in general, turn into a single dunder method, but potentially two or maybe even more.
this bug is for any operator that you apply on super(). I'd be happy to hear from you why it happens and whether will it be fixed in python3.10.
Before we can "fix" it, we have to agree that it is a bug and that it should be fixed. What gives you the impression that this is a bug? Is the behaviour documented somewhere as working? If we made this change, would it extend to other dunder methods like `__str__`, `__len__`, `__enter__`, etc? -- Steve
participants (3)
-
Chris Angelico
-
Jonatan
-
Steven D'Aprano