0

The AddressBook class finds uses regex to find a string that matches the pattern, which is a name.

self.contacts loops through the Contact class and prints out the pattern in a dictionary format

import re
import sys


class Contact(object):

    def __init__(self, match):
        for key, value in match.groupdict().items():
            setattr(self, key, value)

    def __str__(self):
        return '\n'.join(
            sorted(
                ["\t{}: {}".format(key, val) for key, val in self.__dict__.items()]))


class AddressBook(object):

    def __init__(self, filename):
        self.names_file = open(filename, encoding="utf-8")
        self.data = self.names_file.read()
        self.names_file.close()
        line = re.compile('(?P<name>^([A-Z][a-z]*((\s)))+[A-Z][a-z]*$)')
        self.contacts = [Contact(match) for match in line.finditer(self.data)]

address_book = AddressBook('contacts.txt')
print (address_book)

This will give me a python object:

<__main__.AddressBook object at 0x0338E410>

But if I add another __str__method like this...

import re
import sys


class Contact(object):
    ... #same code as above


class AddressBook(object):
    def __init__(self, filename):
        self.names_file = open(filename, encoding="utf-8")
        self.data = self.names_file.read()
        self.names_file.close()
        line = re.compile('(?P<name>^([A-Z][a-z]*((\s)))+[A-Z][a-z]*$)')
        self.contacts = [Contact(match) for match in line.finditer(self.data)]

    def __str__(self):
       return '\n'.join('{}'.format(i) for i in self.contacts)

address_book = AddressBook('contacts.txt')
print (address_book)

It actually prints it out:

name: Rick James
name: Charlie Murphy
name: Prince

My question is why does it give me a python object even though I have a __str__ method in the Contact class?

dyao
  • 983
  • 3
  • 12
  • 25
  • 5
    Because you're printing an `AddressBook`, not a `Contact`? – Ismail Badawi Oct 22 '15 at 03:30
  • Is there another way to do this without having to resort to 2 `__str__` methods? – dyao Oct 22 '15 at 03:34
  • 1
    @bLunt You can do all the work in the `AddressBook.__str__()` method and format all the `Contact` instances it contains there, but it's probably better to keep the logic in the two `__str__()` methods - let each object be responsible of its own readable representation. – plamut Oct 22 '15 at 03:52

1 Answers1

2

The reason is that print() uses the instance's __str__() method, which by default uses the object's __repr__() method. Now, your second example overrides the inherited __str__() method, giving you a nice output you wanted.

The following example illustrates this behavior:

>>> class Foo:
...     x = 42
... 
>>> f = Foo()
>>> print(f)
<__main__.Foo object at 0x7fb12d4c6890>
>>> class Foo2:
...     x = 42
...     def __str__(self):
...         return 'x = {}'.format(self.x)
... 
>>> f2 = Foo2()
>>> print(f2)
x = 42

For more information about the differences between __str__() and __repr__() you can also read this, a very good and exhaustive explanation.

Community
  • 1
  • 1
plamut
  • 3,085
  • 10
  • 29
  • 40
  • That's a good link, but the best answer may be deeply hidden. :) – Russia Must Remove Putin Oct 22 '15 at 03:50
  • You have a point here. :) Though the link was meant more as a _"further reading"_ resource for a curious reader than anything else, I wanted to spare OP the potentially unnecessary details, just described the core mechanism behind the observed behavior. :) – plamut Oct 22 '15 at 04:03