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}' On !r, PEP 3101 – Advanced String Formatting states:
!r - convert the value to a string using repr().
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:
- repr(object) calls object.__repr__(self); and we implement the later in our own codes.
- class str(object='') calls object.__str__(self); and we implement the later in our own codes.
- The purpose of object.__str__(self) is to provide a friendly human readable string presentation of an object instance.
- The purpose of object.__repr__(self) is to provide a string representation of an object instance, AND the eval(expression[, globals[, locals]]) function should be able to take this string and convert it to the same original object instance from which the string is generated from.
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.
Top comments (2)
Your passage is really helpful.It helped me.
Thank you.