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.

039-feature-image.png
Python: the !r string format and the __repr__() and __str__() methods.

An usage example of the string format !r:

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

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 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 )

– 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 ) )

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')

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 ) )

And it does work as expected:

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

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) )

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')

– 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})"
        ...		

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) )

And the output looks like:

 Create Own   Create Other    View Own
   False          False         True

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.