classification
Title: str(super()) != super().__str__()
Type: behavior Stage: resolved
Components: Versions: Python 3.6
process
Status: closed Resolution: not a bug
Dependencies: Superseder:
Assigned To: Nosy List: Guillaume Dominici, eric.snow, rhettinger, serhiy.storchaka
Priority: normal Keywords:

Created on 2018-09-21 08:37 by Guillaume Dominici, last changed 2018-09-21 17:08 by eric.snow. This issue is now closed.

Messages (3)
msg325976 - (view) Author: Guillaume Dominici (Guillaume Dominici) Date: 2018-09-21 08:37
The super proxy does not seem to forward call to .__str__() when the call occurs via str() function.
It may be an expected behavior, but it looks unexpected to me.

Minimal reproduction (tested on Python 3.6, but I believe may newer versions have similar behavior):

class Parent():
  def __str__(self):
    return "Parent"

class Child(Parent):
  def foo(self):
    s = super(Child, self)
    print(s.__str__())
    print(str(s))


c = Child()
c.foo()

# Output :
### Parent
### <super: <class 'Child'>, <Child object>>
msg325978 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-09-21 09:14
It is an expected behavior.

From https://docs.python.org/3/library/functions.html#super:

    Return a proxy object that delegates method calls to a parent or sibling class of type.

super() delegates explicit method calls. You shouldn't expect that it will delegate special methods called indirectly. For example, super() + 2 doesn't call super().__add__(2), and float(super()) doesn't call super().__float__().
msg326008 - (view) Author: Eric Snow (eric.snow) * (Python committer) Date: 2018-09-21 17:08
As Serhiy said, this is the correct behavior.  Nearly all builtin operations are made using the appropriate "dunder" method from the object's type (not looked up on the object itself).  So the following (based on your example) are equivalent:

  s = super(Child, self)
  print(type(s).__str__(s))
  print(str(s))

In contrast, explicitly calling __str__() on the instance involves lookup there, so the following are equivalent:

  s = super(Child, self)
  print(s.__str__())
  print(type(s).__getattribute__(s, '__str__')())

You can read more about "dunder" (AKA "special") methods and how they are looked up in the docs. [1][2][3]

I'm going to close this issue, but if you think there's anything further we can do in the documentation to avoid confusion then please let us know.


[1] https://docs.python.org/3/reference/datamodel.html#special-lookup
[2] https://docs.python.org/3/reference/datamodel.html#special-method-names
[3] https://docs.python.org/3/library/inspect.html#fetching-attributes-statically
History
Date User Action Args
2018-09-21 17:08:57eric.snowsetstatus: open -> closed

nosy: + eric.snow
messages: + msg326008

resolution: not a bug
stage: resolved
2018-09-21 09:14:09serhiy.storchakasetnosy: + rhettinger, serhiy.storchaka
messages: + msg325978
2018-09-21 08:37:47Guillaume Dominicicreate