0

I wondered why list.__str__() stringifies each element by __repr__() in follow case:

class A:
    def __repr__(self):
        return 'repr()'

    def __str__(self):
        return 'str()'

print(str([A(), A()]))  # output: [repr(), repr()]

(screen shot)

First, I tried running above code in other python interpreter and get same result.

Then I googled whether this behavior has been defined in the spec or not, however I couldn't find any document about list.__str__()'s procedure. I found this document, but it's not enough. It doesn't defined any procedure.

Do any specifications for list.__str__ exist or not?

MSeifert
  • 145,886
  • 38
  • 333
  • 352
Kiikurage
  • 195
  • 1
  • 6
  • 4
    The specification is "whatever CPython does". – Ignacio Vazquez-Abrams Aug 22 '17 at 15:26
  • Check this answer https://stackoverflow.com/a/2626364/840582 – Chen A. Aug 22 '17 at 15:34
  • 1
    If an object doesn't define `__str__`, calling `str` on it delegates to the object's `__repr__` method. All objects have a `__repr__`: if its class doesn't explicitly define one, then it will inherit one from its parent, possibly the `__repr__` defined in the base `object` class. However, calling `str()` on a list _always_ calls `repr()` on each list item, whether or not that item defines `__str__`. – PM 2Ring Aug 22 '17 at 15:55

3 Answers3

0

This might not be explicitly specified, but there is certainly logic to it. You're looking at the per type methods for repr and str in the list type. If you read the documentation for __str__, it shows that the default implementation is to fall back on __repr__. The core difference between the two is that __str__ is not expected to produce a valid Python expression, while __repr__ is. Lists, being a Python standard type, are naturally expected to show as valid expressions, thus should have repr, and repr will rely on calling repr for the contained items as well, or the expression might break.

We end up with one question: How should lists be shown differently for str than for repr? This is where for instance a type for a deck of cards might produce "queen of hearts" instead of Card(1,12). There's no obvious choice for a list, so it just has no __str__.

We can even verify that this is the case:

>>> list.__str__
<slot wrapper '__str__' of 'object' objects>
>>> list.__repr__
<slot wrapper '__repr__' of 'list' objects>

The __str__ is inherited from object, and not specialized for list.

Yann Vernier
  • 15,414
  • 2
  • 28
  • 26
  • Thank you! I understood the difference of semantics between `__str__()` and `__repr__()`, and why `list` doesn't have default implementation of `__str__()`. – Kiikurage Aug 22 '17 at 15:49
  • Also your method to check whether list has own `__str__` implementation or inherits from super class is very useful. thank you! – Kiikurage Aug 22 '17 at 15:55
0

In the absence of __str__ any container will default to __repr__ if passed to str. As it happens the containers in CPython (list, etc.) generally don't have a __str__ method and thus they will delegate to __repr__. For the __repr__ it makes sense to call the __repr__ of the elements.

So it's no formal specification. It's just because these containers have no __str__ method.

MSeifert
  • 145,886
  • 38
  • 333
  • 352
0

I think that this behavior can be considered as specified. https://docs.python.org/3/library/stdtypes.html#list states that lists implement all of the common and mutable sequence operations (none of them include __str__ or __repr__) plus sort. So, according to the specification, there's no list.__str__ or list.__repr__ (despite that in CPython you can see them).

Therefore str(a_list) is resolved as str(a_list) -> repr(a_list) -> list.__repr__ -> object.__repr__ (since list is a subclass of object). And according to https://docs.python.org/3/reference/datamodel.html#object.repr, object.__repr__ returns "the “official” string representation of an object". It's obvious from the docs that the official string representation for lists looks like [...] (where each element is repr-ed), that's what you observed.

Kirill Bulygin
  • 3,658
  • 1
  • 17
  • 23
  • Not really true. [lists implement `__repr__`](https://github.com/python/cpython/blob/v3.6.2/Objects/listobject.c#L2637) but they [don't implement `__str__`](https://github.com/python/cpython/blob/v3.6.2/Objects/listobject.c#L2643). – MSeifert Aug 22 '17 at 15:51
  • @MSeifert Note that the question is about the specification (i.e., the docs). Also note this: "despite that in CPython [I mean the program, not its sources] you can see them". – Kirill Bulygin Aug 22 '17 at 15:57
  • If you combine the [list display syntax](https://docs.python.org/3/reference/expressions.html#list-displays) and "if at all possible" part regarding [repr](https://docs.python.org/3/reference/datamodel.html#object.__repr__), I'd say the central documents do guide lists to have this repr form. The spaces after the commas are recommended per PEP 8. – Yann Vernier Aug 22 '17 at 16:05
  • @YannVernier Thanks, this is the final bit to describe the behavior using only the docs. – Kirill Bulygin Aug 22 '17 at 16:23