Skip to content

Latest commit

 

History

History
149 lines (106 loc) · 7.82 KB

File metadata and controls

149 lines (106 loc) · 7.82 KB

About

String Formatting in Python

The Zen of Python asserts there should be "one obvious way to do something in Python". But when it comes to string formatting, things are a little .... less zen. It can be surprising to find out that there are four main ways to perform string formatting in Python - each for a different scenario.

literal string interpolation. f-string

Literal string interpolation or f-string is a way of quickly and efficiently formatting and evaluating expressions to str using the f (or F) prefix before the brackets, like so f'{object}'. It can be used with all enclosing string types as: single quote ', double quote " and with multi-lines and escaping triple quotes ''' or """.

In this example, we insert two variable values in the sentence: one str and one float:

>>> name, value = 'eighth', 1/8
>>> f'An {name} is approximately {value:.2f}.'
'An eighth is approximately 0.12.' # .2f truncates so it displays 0.12.

The expressions evaluated can be almost anything, to mention some of the possibilities that can be evaluated: str, numbers, variables, arithmetic expressions, conditional expressions, built-in types, slices, functions or any objects with either __str__ or __repr__ methods defined. Some examples:

>>> waves = {'water': 1, 'light': 3, 'sound': 5}

>>> f'"A dict can be represented with f-string: {waves}."'
'"A dict can be represented with f-string: {\'water\': 1, \'light\': 3, \'sound\': 5}."'

>>> f'Tenfold the value of "light" is {waves["light"]*10}.'
'Tenfold the value of "light" is 30.'

f-string supports control mechanisms such as width, alignment, precision that are described for the .format() method.

An advanced example of f-string:

>>> precision, verb, the_end = 3, "see", ['end', 'of', 'transmission']
>>> verb = 'meet'
>>> f'"Have a {"NICE".lower()} day, I will {verb} you after {f"{30e8*111_000:6.{precision}e}"} light-years."{{{the_end}}}'
'"Have a nice day, I will meet you after 3.330e+14 light-years."{[\'end\', \'of\', \'transmission\']}'
# This example includes a function, str, nested f-string, arithmetic expression, precision, bracket escaping and object formatting.

There is a couple of limitations to be aware of: f-string expressions can't be empty and cannot contain comments:

>>> f"An empty expression will error: {}"
SyntaxError: f-string: empty expression not allowed

>>> word = 'word'
>>> f"""A comment in a triple quoted f-string will error: {
    word # I chose a nice variable
}"""
SyntaxError: f-string expression part cannot include '#'

String interpolation cannot be used together with the GNU gettext API for internationalization (I18N) and localization (L10N), so str.format() needs to be used instead of an f-string in translation scenarios. Keep in mind that using an expression inside the brackets {} is similar to using eval() or exec(), so it isn't very safe and should be used sparingly.

str.format() method

The str.format() allows to replace placeholders with values, the placeholders are identified with named indexes {price} or numbered indexes {0} or empty placeholders {}. The values are specified as parameters in the format() method.

Example:

>>> 'My text: {placeholder1} and {}.'.format(12, placeholder1='value1')
'My text: value1 and 12.'

Python .format() supports a whole range of mini language format specifier that can be used to align text, convert, etc.

The complete formatting specifier pattern is {[<name>][!<conversion>][:<format_specifier>]}:

  • <name> can be a named placeholder or a number or empty.
  • !<conversion> is optional and should be one of this three conversions: !s for str(), !r for repr() or !a for ascii(). By default, str() is used.
  • :<format_specifier> is optional and has a lot of options, which we are listed here.

Example of conversions for a diacritical letter:

>>> '{0!s}'.format('ë')
'ë'
>>> '{0!r}'.format('ë')
"'ë'"
>>> '{0!a}'.format('ë')
"'\\xeb'"

>>> 'She said her name is not {} but {!r}.'.format('Chloe', 'Zoë')
"She said her name is not Chloe but 'Zoë'."

Example of format specifiers:

>>> "The number {0:d} has a representation in binary: '{0: >8b}'.".format(42)
"The number 42 has a representation in binary: '  101010'."

More examples at the end of this documentation. str.format() should be used together with the GNU gettext API for internationalization (I18N) and localization (L10N) in translation scenarios.

The % operator

The % operator comes from the C language and it allows to use positional arguments to build a str.

This method is now superseded by the .format() method, which is why the nickname of % is The 'Old Style'. It can be still found is python 2 or legacy code. The % operator is usually avoided because less efficient, fewer options are available and any placeholder-argument mismatch can raise an exception. This operator is similar to printf().

>> name = "Anna-conda"
>> "The snake's name is %s." % name
"The snake's name is Anna-conda."

The % operator substitutes at runtime the placeholder %s with the variable name. If you want to add multiple variables to a string you would need a tuple containing one object per placeholder after the %.

Template strings

Template is a module from the string standard library, which is always shipped with Python. It is simpler but also less capable than the options mentioned before, but can be sometimes enough to build a nice str.

>> from string import Template
>> template_string = Template("The snake called `$snake_name` has escaped!")
>> template_string.substitute(snake_name=name)
'The snake called `Anna-conda` has escaped'

More information about Template string can be found in the Python documentation.

How to choose which formatting method to use?

  1. The f-string is the newest and easiest to read, it should be preferred when using Python 3.6+.
  2. Then .format() is versatile, very powerful and compatible with most versions of Python.
  3. Template string can be used to mitigate risks when inputs from users need to be handled, for simplicity or multiple substitutions.
  4. The % operator is not supported in some of the new distributions of Python, it is mostly used for compatibility with old code. This operator can lead to issues displaying non-ascii characters and has less functionalities than other methods.

If you want to go further: all about formatting.