Python 2.6 introduced the str.format() method with a slightly different syntax from the existing %
operator. Which is better and for what situations?
Pyt
For python version >= 3.6 (see PEP 498)
s1='albha'
s2='beta'
f'{s1}{s2:>10}'
#output
'albha beta'
But please be careful, just now I've discovered one issue when trying to replace all %
with .format
in existing code: '{}'.format(unicode_string)
will try to encode unicode_string and will probably fail.
Just look at this Python interactive session log:
Python 2.7.2 (default, Aug 27 2012, 19:52:55)
[GCC 4.1.2 20080704 (Red Hat 4.1.2-48)] on linux2
; s='й'
; u=u'й'
; s
'\xd0\xb9'
; u
u'\u0439'
s
is just a string (called 'byte array' in Python3) and u
is a Unicode string (called 'string' in Python3):
; '%s' % s
'\xd0\xb9'
; '%s' % u
u'\u0439'
When you give a Unicode object as a parameter to %
operator it will produce a Unicode string even if the original string wasn't Unicode:
; '{}'.format(s)
'\xd0\xb9'
; '{}'.format(u)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'latin-1' codec can't encode character u'\u0439' in position 0: ordinal not in range(256)
but the .format
function will raise "UnicodeEncodeError":
; u'{}'.format(s)
u'\xd0\xb9'
; u'{}'.format(u)
u'\u0439'
and it will work with a Unicode argument fine only if the original string was Unicode.
; '{}'.format(u'i')
'i'
or if argument string can be converted to a string (so called 'byte array')
Python 3.6.7 comparative:
#!/usr/bin/env python
import timeit
def time_it(fn):
"""
Measure time of execution of a function
"""
def wrapper(*args, **kwargs):
t0 = timeit.default_timer()
fn(*args, **kwargs)
t1 = timeit.default_timer()
print("{0:.10f} seconds".format(t1 - t0))
return wrapper
@time_it
def new_new_format(s):
print("new_new_format:", f"{s[0]} {s[1]} {s[2]} {s[3]} {s[4]}")
@time_it
def new_format(s):
print("new_format:", "{0} {1} {2} {3} {4}".format(*s))
@time_it
def old_format(s):
print("old_format:", "%s %s %s %s %s" % s)
def main():
samples = (("uno", "dos", "tres", "cuatro", "cinco"), (1,2,3,4,5), (1.1, 2.1, 3.1, 4.1, 5.1), ("uno", 2, 3.14, "cuatro", 5.5),)
for s in samples:
new_new_format(s)
new_format(s)
old_format(s)
print("-----")
if __name__ == '__main__':
main()
Output:
new_new_format: uno dos tres cuatro cinco
0.0000170280 seconds
new_format: uno dos tres cuatro cinco
0.0000046750 seconds
old_format: uno dos tres cuatro cinco
0.0000034820 seconds
-----
new_new_format: 1 2 3 4 5
0.0000043980 seconds
new_format: 1 2 3 4 5
0.0000062590 seconds
old_format: 1 2 3 4 5
0.0000041730 seconds
-----
new_new_format: 1.1 2.1 3.1 4.1 5.1
0.0000092650 seconds
new_format: 1.1 2.1 3.1 4.1 5.1
0.0000055340 seconds
old_format: 1.1 2.1 3.1 4.1 5.1
0.0000052130 seconds
-----
new_new_format: uno 2 3.14 cuatro 5.5
0.0000053380 seconds
new_format: uno 2 3.14 cuatro 5.5
0.0000047570 seconds
old_format: uno 2 3.14 cuatro 5.5
0.0000045320 seconds
-----
If your python >= 3.6, F-string formatted literal is your new friend.
It's more simple, clean, and better performance.
In [1]: params=['Hello', 'adam', 42]
In [2]: %timeit "%s %s, the answer to everything is %d."%(params[0],params[1],params[2])
448 ns ± 1.48 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [3]: %timeit "{} {}, the answer to everything is {}.".format(*params)
449 ns ± 1.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
In [4]: %timeit f"{params[0]} {params[1]}, the answer to everything is {params[2]}."
12.7 ns ± 0.0129 ns per loop (mean ± std. dev. of 7 runs, 100000000 loops each)
As of Python 3.6 (2016) you can use f-strings to substitute variables:
>>> origin = "London"
>>> destination = "Paris"
>>> f"from {origin} to {destination}"
'from London to Paris'
Note the f"
prefix. If you try this in Python 3.5 or earlier, you'll get a SyntaxError
.
See https://docs.python.org/3.6/reference/lexical_analysis.html#f-strings
Yet another advantage of .format
(which I don't see in the answers): it can take object properties.
In [12]: class A(object):
....: def __init__(self, x, y):
....: self.x = x
....: self.y = y
....:
In [13]: a = A(2,3)
In [14]: 'x is {0.x}, y is {0.y}'.format(a)
Out[14]: 'x is 2, y is 3'
Or, as a keyword argument:
In [15]: 'x is {a.x}, y is {a.y}'.format(a=a)
Out[15]: 'x is 2, y is 3'
This is not possible with %
as far as I can tell.