Unexpected behavior when calling super().__repr__() on a subclass of set?

Viewed 54

See edit below for an explanation of this behavior (in CPython)

In Python 3.9.5, I'm creating two custom collection types, one inheriting from list and the other from set. I want them to have custom __repr__ methods. Simple example:

class MyList(list):

    def __repr__(self) -> str:
        return f'MyList({super().__repr__()})'


class MySet(set):

    def __repr__(self) -> str:
        return f'MySet({super().__repr__()})'

Note the __repr__() definitions are identical except for the initial string prefix. But when I print them, I get different results:

ml = MyList('abc')
print(ml) # MyList(['a', 'b', 'c'])

ms = MySet('abc')
print(ms) # MySet(MySet({'c', 'a', 'b'}))

The display of MyList is what I would expect. But for some reason MySet is printed twice, as if the __repr__ is being called recursively or something. Does anyone know what's going on, or how best to get it to show MySet({'c', 'a', 'b'}), instead of MySet(MySet({'c', 'a', 'b'}))?

[Edit] As of 3.9.5, in https://github.com/python/cpython/blob/main/Objects/setobject.c function set_repr has the code:

    if (!PySet_CheckExact(so))
        result = PyUnicode_FromFormat("%s({%U})",
                                      Py_TYPE(so)->tp_name,
                                      listrepr);
    else
        result = PyUnicode_FromFormat("{%U}", listrepr);

In other words, set is hardcoded so that its __repr__ omits the class name if the type is exactly a set and the set is non-empty, but shows the class name otherwise. But dict and list don't do this, for some reason.

1 Answers

That is the default print of set, it prints the class name. If you remove the format you added it comes out exactly as you wanted.

class MySet(set):

    def __repr__(self) -> str:
        return super().__repr__()

if __name__ == '__main__':

    ms = MySet('abc')
    print(ms)
    MySet.__name__ = 'New_name'
    print(ms)

Oututput :

MySet({'b', 'c', 'a'})
New_name({'b', 'c', 'a'})
Related