classification
Title: Calling for super().__str__ seems to call self.__repr__ in list subclass
Type: behavior Stage: resolved
Components: Interpreter Core Versions: Python 3.5
process
Status: open Resolution:
Dependencies: Superseder:
Assigned To: Nosy List: Camion, serhiy.storchaka, xtreak
Priority: normal Keywords:

Created on 2018-11-06 02:48 by Camion, last changed 2018-11-06 11:59 by Camion.

Messages (4)
msg329331 - (view) Author: (Camion) Date: 2018-11-06 02:48
I don't know if this is by design (for what reason ?) or if it is a bug, but I have noticed this quite counter-intuitive behaviour :

Doing that, it seems that the logical way to make the __repr__ and __str__ methods, would be to override respectively the parent __repr__ and _str__ methods, and calling them from the inherited versions, but for some reason, it seems that calling super().__str__ leads to call self.__repr__.

I have written the following piece of python-3 code in which I subclass the list class in order to make a class which supports storing names and unnamed fields the same way you can have variable named and unnamed parameters in a function call :

    class struct(list):
        def __init__(self, *args, **kwargs):
            super().__init__(args)
            for key, value in kwargs.items():
                setattr(self, key, value)
    
        def __repr__(self):
            s = super().__repr__()[1:-1]
            for key, val in self.__dict__.items():
                s += ', '+key+'='+repr(val)
            return 'struct('+s+')'
            
        def __str__(self):
            s = super().__str__()[1:-1]
            print('Debug : super().__str__() = "'+super().__str__()+'"')
            print('Debug : list(self).__str__() = "'+list(self).__str__()+'"')
            print('Debug : s = "'+s+'"')
            for key, val in self.__dict__.items():
                s += ', '+key+'='+str(val)
            return '{'+s+'}'

    a = struct(1, 2, 3, a="akeja", b=21, c=True, d="lkj")
    print('repr(a)="'+repr(a)+'"\n')
    print('str(a)="'+str(a)+'"\n')

Executing this code in idle-3.5.2 will yield the following result :

    >>> 
     RESTART: struct.py 
    repr(a)="struct(1, 2, 3, b=21, d='lkj', a='akeja', c=True)"
    
    Debug : super().__str__() = "struct(1, 2, 3, b=21, d='lkj', a='akeja', c=True)"
    Debug : list(self).__str__() = "[1, 2, 3]"
    Debug : s = "truct(1, 2, 3, b=21, d='lkj', a='akeja', c=True"
    str(a)="{truct(1, 2, 3, b=21, d='lkj', a='akeja', c=True, b=21, d=lkj, a=akeja, c=True}"
    
    >>> 

As one can see in the second debug lines, the call to `super().__str__()` which I expect to return the result from a call to the `__str__` function from my super class (`list`), will in fact return something which looks very much like the expected return from `self.__repr__()`

It seems that `super().__str__()` calls `self.__repr__()` instead of `list(self).__str__()` or even `super().__repr__()`.
msg329339 - (view) Author: Karthikeyan Singaravelan (xtreak) * (Python committer) Date: 2018-11-06 04:32
Adding the related StackOverflow question here for some context : https://stackoverflow.com/questions/53156623/calling-for-super-str-seem-to-call-self-repr-in-list-subclass

Thanks
msg329347 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-11-06 07:26
list inherits __str__ from object. object.__str__() calls __repr__() which can be overridden in subclasses. So if you want repr() and str() returned the same, you need to define only the __repr__() method. This is a feature, not a bug.
msg329352 - (view) Author: (Camion) Date: 2018-11-06 11:59
@Serhiy Storchaka, this doesn't seem logical, is certainly counter intuitive, and I fear there is a lack of expressivity.

- first of all, this is NOT about having str and repr returning the same at all, but about building the same _kind of_ structure representations for str and repr, but with str of sub elements in __str__, and with repr of sub elements in __repr__.

It is not logical at all and completely counter intuitive, if you explicitely ask str of the superclass, to get repr of the subclass. Getting repr of the superclass would be logical, but not repr of the subclass.

Now, it might happen that I missed another way to write what I tried (casting the object to it's super class with super(), to avoid explicitly naming the superclass) but if there is not, we then have something lacking in terms of expressivity.
History
Date User Action Args
2018-11-06 11:59:42Camionsetstatus: closed -> open
resolution: not a bug ->
messages: + msg329352
2018-11-06 07:26:30serhiy.storchakasetstatus: open -> closed

nosy: + serhiy.storchaka
messages: + msg329347

resolution: not a bug
stage: resolved
2018-11-06 04:32:01xtreaksetnosy: + xtreak
messages: + msg329339
2018-11-06 02:48:14Camioncreate