2

I've learned that __str__ can define an output of the string of the object.

Example:

class Person(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return self.name

p1 = Person('Steve Jobs')
p2 = Person('Bill Gates')
p3 = Person('Mark Zuckerberg')

print(p1)  # >>> Steve Jobs

it output Steve Jobs as I wished, instead of <__main__.Person object at 0x10410c588>

However, if I create a list:

lst = [p1, p2, p3]
print(lst)
# >>> [<__main__.Person object at 0x1045433c8>, <__main__.Person object at 0x1045434e0>, <__main__.Person object at 0x104543550>]

I have to :

print([i.__str__() for i in lst])
# >>> ['Steve Jobs', 'Bill Gates', 'Mark Zuckerberg']

to make it work??

This does not make sense much, right?

Lundin
  • 195,001
  • 40
  • 254
  • 396
jxie0755
  • 1,682
  • 1
  • 16
  • 35

2 Answers2

2

The list.__str__ uses the object's __repr__ to build the string. So, just delegate __repr__ to __str__:

In [1]: class Person(object):
   ...:     def __init__(self, name):
   ...:         self.name = name
   ...:     def __str__(self):
   ...:         return self.name
   ...:     def __repr__(self):
   ...:         return str(self)
   ...:
   ...: p1 = Person('Steve Jobs')
   ...: p2 = Person('Bill Gates')
   ...: p3 = Person('Mark Zuckerberg')
   ...:

In [2]: print(p1)
Steve Jobs

In [3]: lst = [p1, p2, p3]
   ...:

In [4]: print(lst)
[Steve Jobs, Bill Gates, Mark Zuckerberg]

EDIT

If you want to stick to convention, do somthing like:

In [18]: class Person(object):
    ...:     def __init__(self, name):
    ...:         self.name = name
    ...:     def __str__(self):
    ...:         return self.name
    ...:     def __repr__(self):
    ...:         return f"{type(self).__name__}({self.name})"
    ...:

In [19]: p1 = Person('Steve Jobs')

In [20]: print([p1])
[Person(Steve Jobs)]
juanpa.arrivillaga
  • 88,713
  • 10
  • 131
  • 172
  • Thanks. From what I understand repr() is to represent the codes in python so that `eval(repr(i)) = i`. So is it default that for any python object `__str__ == __repr__` was made when initiated? – jxie0755 Jan 21 '18 at 20:48
  • Correct - output the raw name from `__repr__` goes against the convention. You could output `Person('Steve Jobs')` though, and that would be fine – Eric Jan 21 '18 at 20:49
  • @Code_Control_jxie0755 yes, generally you should stick to that convention. – juanpa.arrivillaga Jan 21 '18 at 20:49
  • So if I changed `__repr__` by doing `__repr__ == __str__`, would this cause the `eval(repr(i)) != i`, and will have some impact in the bigger picture? – jxie0755 Jan 21 '18 at 20:50
  • @Code_Control_jxie0755 unlikely, unless you are relying on using `eval(repr(...))` – juanpa.arrivillaga Jan 21 '18 at 20:52
  • @ juanpa.arrivillaga Got it! Thanks! And I was told that I should avoid using `eval()` almost forever, so I should be fine. – jxie0755 Jan 21 '18 at 20:53
  • 1
    Note that `__str__ = __repr__` is already the default for objects, so you can get away with just defining `__repr__`. "will have some impact in the bigger picture" - yes, you'll make things harder to debug because the output becomes ambiguous - what if someone's name is `"Hello, World"`? Now your list of names looks like it has one extra name! – Eric Jan 21 '18 at 21:14
1

Consider implementing:

class Person(object):
    def __init__(self, name):
        self.name = name
    def __str__(self):
        return self.name
    def __repr__(self):
        return 'Person({!r})'.format(self.name)  # !r adds the quotes correctly

Which gives:

>>> lst
[Person('Steve Jobs'), Person('Bill Gates'), Person('Mark Zuckerberg')]

The reason you're seeing mismatching behavior is that print calls str() on its argument, but list str and repr are the same, and both call repr on each element.

Eric
  • 95,302
  • 53
  • 242
  • 374