Binary Binary - 18 days ago 8
Python Question

How do I append an object class to a list?

So I have the following function :

def find_by_name(self, name):
fitting_list = [p for p in self.__persons if name.lower() in p.name.lower()]
return fitting_list


And I get the following output when I want to print the list :

[<src.store.domain.person.Person object at 0x000001F88705B128>]


Why does this happen and how can I fix it?

Answer

list doesn't care that your class has a __str__ method.

When you print an object, print calls str on the object to get a suitable string. The str function attempts to call the object's __str__ method, but if it doesn't have one then it calls the object's __repr__ method instead. And if their isn't a definition for __repr__ in that object's class definition then you'll get the one inherited from the parent class, typically that will be the default __repr__ from the base object type.

list and the other built-in collections like tuple, set and dict don't have a __str__ method, so when you try to convert them to strings (either explicitly using the str function, or implicitly via print) their __repr__ method is called. And those __repr__ methods in turn call repr on each item in the collection. So when you pass any of those collection objects to print you will always see the __repr__ of the items. And explictly calling str on the collection will make no difference.

If you want to see the __str__ representation of the items in a list or collection you will need to iterate over the collection, calling str explicitly on each item.

Here's a tiny code snippet (suitable for Python 2 & 3) that illustrates these points.

from __future__ import print_function

class Test(object):
    def __str__(self):
        return 'Test str'
    def __repr__(self):
        return 'Test repr'

a = [Test(), Test()]
print(id(a.__repr__), id(a.__str__))
print(a, str(a), repr(a))

for u in a:
    print(u, str(u), repr(u))

output

3075508812 3075508812
[Test repr, Test repr] [Test repr, Test repr] [Test repr, Test repr]
Test str Test str Test repr
Test str Test str Test repr

So if you want to be able to print a list of your objects as a single entity and have the object's strings be more human-friendly, you have a couple of choices:

  1. Change the name of your __str__ method to __repr__. This is the simplest way, and as I said earlier, the __repr__ will be used if a __str__ can't be found when the object gets passed to str.

  2. Leave the existing __str__ method alone and create a __repr__ that's more human-friendly. However, it's suggested that the __repr__ display useful info to a programmer who sees it, and if practical it's nice if the __repr__ string can be copy & pasted into the interpreter or script to recreate the object.

  3. Leave the existing __str__ method alone and create a __repr__ that calls __str__. While valid, this is a bit silly. A related strategy is to set __repr__ as a class attribute that references __str__. See below for an example.

class Test(object):
    def __str__(self):
        return 'Test str'
    __repr__ = __str__