Python: the !r string format and the __repr__() and __str__() methods.

behainguyen

Be Hai Nguyen

Posted on September 21, 2022

Python: the !r string format and the __repr__() and __str__() methods.

The !r string format is a convenient one to use in certain cases. It is related closely to the __repr__() dunder method; and this method and the __str__() are often discussed together. In this post, we review __repr__() and __str__() methods and then the !r string format.

An usage example of the string format !r:

fmt_data = '{!r:^12} {!r:^15} {!r:^10}'
Enter fullscreen mode Exit fullscreen mode

On !r, PEP 3101 – Advanced String Formatting states:

!r - convert the value to a string using repr().

https://peps.python.org/pep-3101/#explicit-conversion-flag

repr() and str() official documentations can be found in the following links repr(object), class str(object=''), object.__repr_(self) and <a href="https://docs.python.org/3/reference/datamodel.html#object.str" title="object.str(self)" target="_blank">object.__str_(self)

Basically:

Let's illustrate this with an example:

class Person( object ):
    def __init__( self, given_name, surname ):
        self.__given_name = given_name
        self.__surname = surname

    def __repr__( self ):
        fmt = u"{}(given_name='{}', surname='{}')"

        return fmt.format( self.__class__.__name__, \
            self.__given_name, self.__surname )

    def __str__( self ):
        fmt = u"{}: Given Name: '{}', Surname: '{}')"

        return fmt.format( self.__class__.__name__, \
            self.__given_name, self.__surname )
Enter fullscreen mode Exit fullscreen mode

-- Please note, in case you wonder if I've copied this example from elsewhere... I have 😂, it is a very popular example used to illustrate this topic, I've also made some minor adjustments to it.

Let's see how it works:

person = Person( 'Văn Bé Hai', 'Nguyễn' ) 
# My full name, written in Vietnamese: Nguyễn Văn Bé Hai 😂

print( person.__str__() )
print( str( person ) )
print( '---' )
print( person.__repr__() )
print( repr( person ) )
Enter fullscreen mode Exit fullscreen mode

As expected, the output of object_instance.__str__() and str( object_instance ) are the same; and so do object_instance.__repr__() and repr( object_instance ).

Person: Given Name: 'Văn Bé Hai', Surname: 'Nguyễn')
Person: Given Name: 'Văn Bé Hai', Surname: 'Nguyễn')
---
Person(given_name='Văn Bé Hai', surname='Nguyễn')
Person(given_name='Văn Bé Hai', surname='Nguyễn')
Enter fullscreen mode Exit fullscreen mode

Continue on, let's see how person.__repr__() works with eval(expression[, globals[, locals]]):

repr_str = person.__repr__()
person1 = eval( repr_str )
print( str( person1 ) )
Enter fullscreen mode Exit fullscreen mode

And it does work as expected:

Person: Given Name: 'Văn Bé Hai', Surname: 'Nguyễn')
Enter fullscreen mode Exit fullscreen mode

Now, we try out !r string format with object instances person and person1:

print( '"person" instance reads: {!r}'.format(person) )
print( '"person1" instance reads: {!r}'.format(person1) )
Enter fullscreen mode Exit fullscreen mode

And we get:

"person" instance reads: Person(given_name='Văn Bé Hai', surname='Nguyễn')
"person1" instance reads: Person(given_name='Văn Bé Hai', surname='Nguyễn')
Enter fullscreen mode Exit fullscreen mode

-- The !r format does eventually call __repr__().

Back to class Person, we could get rid of the double single quote around the curly bracket pairs ( '{}' ) in the two variables fmt, and use {!r}:

class Person( object ):
    ...

    def __repr__( self ):
        # fmt = u"{}(given_name='{}', surname='{}')"
        fmt = u"{}(given_name={!r}, surname={!r})"
        ...     

    def __str__( self ):
        # fmt = u"{}: Given Name: '{}', Surname: '{}')"
        fmt = u"{}: Given Name: {!r}, Surname: {!r})"
        ...     
Enter fullscreen mode Exit fullscreen mode

Finally, let's look at the example listed in the beginning of this post: fmt_data = '{!r:^12} {!r:^15} {!r:^10}' -- please see this official document Format Specification Mini-Language for much more info. In a nutshell, ^ centres the string within the specified width, in this example, widths are 12, 15 and 10 respectively -- I have three ( 3 ) Boolean fields, and I would like to display them in tabular format, in the middle of three ( 3 ) headers with different lengths:

create_own = False
create_other = False 
view_own = True

fmt_header = '{:^12} {:^15} {:^10}'
fmt_data = '{!r:^12} {!r:^15} {!r:^10}'

print( fmt_header.format('Create Own', 'Create Other', 'View Own' ) )
print( fmt_data.format(create_own, create_other, view_own) )
Enter fullscreen mode Exit fullscreen mode

And the output looks like:

 Create Own   Create Other    View Own
   False          False         True
Enter fullscreen mode Exit fullscreen mode

This is what I mean in the beginning “The !r string format is a convenient one to use in certain cases.”

It seems Python offers a lot in term of string formatting. I find this information very useful. And I hope you do too. I certainly enjoy writing this post. Thank you for reading and stay safe as always.

💖 💪 🙅 🚩
behainguyen
Be Hai Nguyen

Posted on September 21, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related