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
Since Python 3.8: See https://bugs.python.org/issue36817
f'{expr=}'
expands to the text of the expression, an equal sign, then the repr of the evaluated expression
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