7.2. String Interpolation

7.2.1. Mod Operator

  • Since Python 1.0

  • positional

  • keyword

  • %s - str

  • %d - int

  • %f - float

name = 'José Jiménez'
age = 42
pi = 3.141592653589793

'My name... %s' % name             # My name... José Jiménez
'My name... %d' % name             # TypeError: %d format: a number is required, not str
'My name... %f' % name             # TypeError: must be real number, not str

'I have %s years' % age             # 'I have 42 years'
'I have %d years' % age             # 'I have 42 years'
'I have %f years' % age             # 'I have 42.000000 years'

'Number PI is %s' % pi              # 'Number PI is 3.141592653589793'
'Number PI is %f' % pi              # 'Number PI is 3.141593'
'Number PI is %d' % pi              # 'Number PI is 3'
name = 'José Jiménez'
age = 42

'%s has %s years' % (name, age))      # José Jiménez has 42 years
'%s has %s years' % (age, name))      # 42 has José Jiménez years
pi = 3.141592653589793

def square(value):
    return value ** 2

'PI squared is %f' % square(pi)      # 'PI squared is 9.869604'
data = {
    'name': 'José Jiménez',
    'age': 42,
}

'%(name)s has %(age)d years' % data
# 'José Jiménez has 42 years'

'%(name)s has %(age)d years' % {'name': 'José Jiménez', 'age': 42}
# 'José Jiménez has 42 years'
name = 'José Jiménez'
age = 42

'My name... %(name)s' % locals()
# 'My name... José Jiménez'

7.2.2. Format Method

  • Since Python 3.0

  • Since Python 3.0: PEP 3101 -- Advanced String Formatting

name = 'José Jiménez'
age = 42

'{} is {} years'.format(name, age)                     # 'José Jiménez is 42 years'
'{0} is {1} years'.format(name, age)                   # 'José Jiménez is 42 years'
'{1} is {0} years'.format(name, age)                   # '42 is José Jiménez years'
name = 'José Jiménez'
age = 42

'{a} is {b} years'.format(a=name, b=age)               # 'José Jiménez is 42 years'
'{name} is {age} years'.format(name=name, age=age)     # 'José Jiménez is 42 years'
'{age} is {name} years'.format(**locals())             # '42 is José Jiménez years'

7.2.3. f-strings

  • Since Python 3.6

  • Preferred way

name = 'José Jiménez'
pi = 3.141592653589793

def square(value):
    return value ** 2

f'My name... {name}'                      # 'My name... José Jiménez'
f'PI squared is {square(pi)}'             # 'PI squared is 9.869604401089358'
from datetime import datetime


now = datetime.now()
iso = '%Y-%m-%dT%H:%M:%SZ'

f'Today is: {now:%Y-%m-%d}')              # 'Today is: 1969-07-21'
f'Today is: {now:{iso}}')                 # 'Today is: 1969-07-21T02:56:15Z'

7.2.4. Basic formatting

text = 'PI'
number = 3.14

f'{text} = {number}'            # 'PI = 3.14'

7.2.5. Padding and aligning strings

text = 'hello'

f'{text:10}'                    # 'hello     '
f'{text:<10}'                   # 'hello     '
f'{text:^10}'                   # '  hello   '
f'{text:>10}'                   # '     hello'
f'{text:.<10}'                  # 'hello.....'
f'{text:_^10}'                  # '__hello___'

7.2.6. Type casting

number = 3

f'{number}'                    # '3'
f'{number:d}'                  # '3'
f'{number:f}'                  # '3.000000'
number = 3.141592653589793

f'{number}'                     # '3.141592653589793'
f'{number:d}'                   # ValueError: Unknown format code 'd' for object of type 'float'
f'{number:f}'                   # '3.141593'
text = 'hello'

f'{text}'                       # 'hello'
f'{text:d}'                     # ValueError: Unknown format code 'd' for object of type 'str'
f'{text:f}'                     # ValueError: Unknown format code 'f' for object of type 'str'
f'{14:#b}'                      # '0b1110'
f'{14:b}'                       # '1110'
f'{10:#o}'                      # '0o12'
f'{10:o}'                       # '12'
f'{255:#x}'                     # '0xff'
f'{255:x}'                      # 'ff'
f'{255:X}'                      # 'FF'

7.2.7. Truncating and rounding

text = 'Lorem Ipsum'

f'{text:.5}'                    # 'Lorem'
f'{text:10.5}'                  # 'Lorem     '
number = 3.141592653589793

f'{number:.2f}'                 # '3.14'
f'{number: 6.2f}'               # '  3.14'
f'{number:06.2f}'               # '003.14'
f'{number:.6.2f}'               # ValueError: Invalid format specifier

7.2.8. Signed numbers

positive = 42
negative = -42


f'{positive:d}'                 # '42'
f'{negative:d}'                 # '-42'

f'{positive: d}'                # ' 42'
f'{negative: d}'                # '-42'

f'{positive:+d}'                # '+42'
f'{negative:+d}'                # '-42'

f'{negative:=5d}'               # '-  42'
f'{positive:=+5d}'              # '+  42'

7.2.9. Get from dict

data = {
    'firstname': 'Mark',
    'lastname': 'Watney'
}

f'{data["firstname"]}'         # 'Mark'
f'{data["lastname"]}'          # 'Watney'

7.2.10. Get from sequence

data = ['a', 'b', 'c']

f'{data[1]}'                    # 'b'
f'{data[0]} -> {data[2]}'       # 'a -> c'
data = ('a', 'b', 'c')

f'{data[1]}'                    # 'b'
f'{data[0]} -> {data[2]}'       # 'a -> c'
data = {'a', 'b', 'c'}

f'{data[1]}'
# Traceback (most recent call last):
# TypeError: 'set' object is not subscriptable

7.2.11. Get from class

class Iris:
    species = 'setosa'
    measurements = {
        'sepal_length': 5.1,
        'sepal_width': 3.5,
        'petal_length': 1.3,
        'petal_width': 0.4,
    }

flower = Iris()

f'{flower.species}'                             # 'setosa'
f'{flower.species:.3}'                          # 'set'
f'{flower.measurements["sepal_width"]}'         # '3.5'
f'{flower.measurements["sepal_width"]:.3f}'     # '3.500'

7.2.12. Parametrized formats

text = 'hello'

align = '^'
width = 10


f'{text:{align}}'               # 'hello'
f'{text:{align}{width}}'        # '  hello   '
number = 3.14159

align = '>'
width = 10
precision = 2
sign = '+'


f'{number:.{precision}f}'                       # '3.14'
f'{number:{width}.{precision}f}'                # '      3.14'
f'{number:{align}{sign}{width}.{precision}f}'   # '     +3.14'

7.2.13. Datetime

from datetime import datetime


now = datetime(1969, 7, 21, 2, 56, 15)

iso = '%Y-%m-%dT%H:%M:%SZ'
date = '%Y-%m-%d'
time = '%H:%M'


f'{now:%Y-%m-%d %H:%M}'       # '1969-07-21 02:56'

f'{now:{iso}}'                # '1969-07-21T02:56:15Z'
f'{now:{date}}'               # '1969-07-21'
f'{now:{time}}'               # '02:56'

7.2.14. Custom object formatting

class Point:
    def __init__(self, x, y, z=0):
        self.x = x
        self.y = y
        self.z = z

    def __format__(self, format):

        if format == '2D':
            return f"({self.x}, {self.y})"

        elif format == '3D':
            return f"({self.x}, {self.y}, {self.z})"

        elif format == 'dict':
            return str(self.__dict__)

        elif format == 'tuple':
            return str(tuple(self.__dict__.values()))

        elif format == 'json':
            import json
            return json.dumps(self.__dict__)

        else:
            raise ValueError


point = Point(x=1, y=2)

f'{point:2D}'           # '(1, 2)'
f'{point:3D}'           # '(1, 2, 0)'
f'{point:tuple}'        # '(1, 2, 0)'
f'{point:dict}'         # "{'x': 1, 'y': 2, 'z': 0}"
f'{point:json}'         # '{"x": 1, "y": 2, "z": 0}'

7.2.15. str and repr

  • !s executes __str__()

  • !r executes __repr__()

class Point:
    def __init__(self, x, y, z=0):
        self.x = x
        self.y = y
        self.z = z

    def __str__(self):
        return f'({self.x}, {self.y}, {self.z})'

    def __repr__(self):
        return f'Point(x={self.x}, y={self.y}, z={self.z})'


point = Point(x=1, y=2)

f'{point!s}'            # '(1, 2, 0)'
f'{point!r}'            # 'Point(x=1, y=2, z=0)'

7.2.16. Quick and easy debugging

number = 3

f'{number*9 + 15=}'
# x*9 + 15=42
astronaut = 'Watney'
birthdate = date(1975, 7, 31)
delta = date.today() - member_since

f'{user=} {member_since=}'
# "astronaut='Watney' birthdate=datetime.date(1975, 7, 31)"

f'{astronaut=!s}  {delta.days=:,d}'
# 'astronaut=Watney  delta.days=16,075'
print(f'{theta=}  {cos(radians(theta))=:.3f}')
# theta=30  cos(radians(theta))=0.866
>>> clsname = 'User'
>>> method = 'init'
>>> args = ('Mark', 'Watney')
>>> kwargs = {'age':40, 'weight': 70, 'height': 175}
>>> result = None
>>> print(f'Method was called: {clsname}, {method}, {args}, {kwargs}, {result}')
Method was called: User, init, ('Mark', 'Watney'), {'age': 40, 'weight': 70, 'height': 175}, None
>>> print(f'Method was called: {clsname=}, {method=}, {args=}, {kwargs=}, {result=}')
Method was called: clsname='User', method='init', args=('Mark', 'Watney'), kwargs={'age': 40, 'weight': 70, 'height': 175}, result=None