DEV Community

Cover image for Python: the !r string format and the __repr__() and __str__() methods.
Be Hai Nguyen
Be Hai Nguyen

Posted on

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.

Top comments (2)

Collapse
 
orangebirddrinkswater profile image
OrangeBirdDrinksWater

Your passage is really helpful.It helped me.

Collapse
 
behainguyen profile image
Be Hai Nguyen

Thank you.