As mentioned earlier, Python 2.6 and 3.0 introduced a new way to format strings that is seen by some as a bit more Python-specific. Unlike formatting expressions, formatting method calls are not closely based upon the C language’s “printf” model, and are sometimes more explicit in intent. On the other hand, the new technique still relies on core “printf” concepts, such as type codes and formatting specifications. Moreover, it largely overlaps with—and sometimes requires a bit more code than—formatting expressions, and in practice can be just as complex in many roles. Because of this, there is no best-use recommendation between expressions and method calls today, and most programmers would be well served by a cursory understanding of both schemes. Luckily, the two are similar enough that many core concepts overlap.
The string object’s format method, available in Python 2.6, 2.7, and 3.X, is based on normal function call syntax, instead of an expression. Specifically, it uses the subject string as a template, and takes any number of arguments that represent values to be substituted according to the template.
Its use requires knowledge of functions and calls, but is mostly straightforward. Within the subject string, curly braces designate substitution targets and arguments to be inserted either by position (e.g., {1}), or keyword (e.g., {food}), or relative position in 2.7, 3.1, and later ({}). As we’ll learn when we study argument passing in depth in Chapter 18, arguments to functions and methods may be passed by position or keyword name, and Python’s ability to collect arbitrarily many positional and keyword arguments allows for such general method call patterns. For example:
>>>template = '{0}, {1} and {2}'# By position >>>template.format('spam', 'ham', 'eggs')'spam, ham and eggs' >>>template = '{motto}, {pork} and {food}'# By keyword >>>template.format(motto='spam', pork='ham', food='eggs')'spam, ham and eggs' >>>template = '{motto}, {0} and {food}'# By both >>>template.format('ham', motto='spam', food='eggs')'spam, ham and eggs' >>>template = '{}, {} and {}'# By relative position >>>template.format('spam', 'ham', 'eggs')# New in 3.1 and 2.7 'spam, ham and eggs'
By comparison, the last section’s formatting expression can be a bit more concise, but uses dictionaries instead of keyword arguments, and doesn’t allow quite as much flexibility for value sources (which may be an asset or liability, depending on your perspective); more on how the two techniques compare ahead:
>>>template = '%s, %s and %s'# Same via expression >>>template % ('spam', 'ham', 'eggs')'spam, ham and eggs' >>>template = '%(motto)s, %(pork)s and %(food)s'>>>template % dict(motto='spam', pork='ham', food='eggs')'spam, ham and eggs'
Note the use of dict() to make a dictionary from keyword arguments here, introduced in Chapter 4 and covered in full in Chapter 8; it’s an often less-cluttered alternative to the {...} literal. Naturally, the subject string in the format method call can also be a literal that creates a temporary string, and arbitrary object types can be substituted at targets much like the expression’s %s code:
>>> '{motto}, {0} and {food}'.format(42, motto=3.14, food=[1, 2])
'3.14, 42 and [1, 2]'
Just as with the % expression and other string methods, format creates and returns a new string object, which can be printed immediately or saved for further work (recall that strings are immutable, so format really must make a new object). String formatting is not just for display:
>>>X = '{motto}, {0} and {food}'.format(42, motto=3.14, food=[1, 2])>>>X'3.14, 42 and [1, 2]' >>>X.split(' and ')['3.14, 42', '[1, 2]'] >>>Y = X.replace('and', 'but under no circumstances')>>>Y'3.14, 42 but under no circumstances [1, 2]'
Like % formatting expressions, format calls can become more complex to support more advanced usage. For instance, format strings can name object attributes and dictionary keys—as in normal Python syntax, square brackets name dictionary keys and dots denote object attributes of an item referenced by position or keyword. The first of the following examples indexes a dictionary on the key “spam” and then fetches the attribute “platform” from the already imported sys module object. The second does the same, but names the objects by keyword instead of position:
>>>import sys>>>'My {1[kind]} runs {0.platform}'.format(sys, {'kind': 'laptop'})'My laptop runs win32' >>>'My {map[kind]} runs {sys.platform}'.format(sys=sys,map={'kind': 'laptop'})'My laptop runs win32'
Square brackets in format strings can name list (and other sequence) offsets to perform indexing, too, but only single positive offsets work syntactically within format strings, so this feature is not as general as you might think. As with % expressions, to name negative offsets or slices, or to use arbitrary expression results in general, you must run expressions outside the format string itself (note the use of *parts here to unpack a tuple’s items into individual function arguments, as we did in Chapter 5 when studying fractions; more on this form in Chapter 18):
>>>somelist = list('SPAM')>>>somelist['S', 'P', 'A', 'M'] >>>'first={0[0]}, third={0[2]}'.format(somelist)'first=S, third=A' >>>'first={0}, last={1}'.format(somelist[0], somelist[-1])# [-1] fails in fmt 'first=S, last=M' >>>parts = somelist[0], somelist[-1], somelist[1:3]# [1:3] fails in fmt >>>'first={0}, last={1}, middle={2}'.format(*parts)# Or '{}' in 2.7/3.1+ "first=S, last=M, middle=['P', 'A']"
Another similarity with % expressions is that you can achieve more specific layouts by adding extra syntax in the format string. For the formatting method, we use a colon after the possibly empty substitution target’s identification, followed by a format specifier that can name the field size, justification, and a specific type code. Here’s the formal structure of what can appear as a substitution target in a format string—its four parts are all optional, and must appear without intervening spaces:
{fieldname component !conversionflag :formatspec}
In this substitution target syntax:
fieldname is an optional number or keyword identifying an argument, which may be omitted to use relative argument numbering in 2.7, 3.1, and later.
component is a string of zero or more “.name” or “[index]” references used to fetch attributes and indexed values of the argument, which may be omitted to use the whole argument value.
conversionflag starts with a ! if present, which is followed by r, s, or a to call repr, str, or ascii built-in functions on the value, respectively.
formatspec starts with a : if present, which is followed by text that specifies how the value should be presented, including details such as field width, alignment, padding, decimal precision, and so on, and ends with an optional data type code.
The formatspec component after the colon character has a rich format all its own, and is formally described as follows (brackets denote optional components and are not coded literally):
[[fill]align][sign][#][0][width][,][.precision][typecode]
In this, fill can be any fill character other than { or }; align may be <, >, =, or ^, for left alignment, right alignment, padding after a sign character, or centered alignment, respectively; sign may be +, −, or space; and the , (comma) option requests a comma for a thousands separator as of Python 2.7 and 3.1. width and precision are much as in the % expression, and the formatspec may also contain nested {} format strings with field names only, to take values from the arguments list dynamically (much like the * in formatting expressions).
The method’s typecode options almost completely overlap with those used in % expressions and listed previously in Table 7-4, but the format method also allows a b type code used to display integers in binary format (it’s equivalent to using the bin built-in call), allows a % type code to display percentages, and uses only d for base-10 integers (i or u are not used here). Note that unlike the expression’s %s, the s type code here requires a string object argument; omit the type code to accept any type generically.
See Python’s library manual for more on substitution syntax that we’ll omit here. In addition to the string’s format method, a single object may also be formatted with the format(object, formatspec) built-in function (which the method uses internally), and may be customized in user-defined classes with the __format__ operator-overloading method (see Part VI).
As you can tell, the syntax can be complex in formatting methods. Because your best ally in such cases is often the interactive prompt here, let’s turn to some examples. In the following, {0:10} means the first positional argument in a field 10 characters wide, {1:<10} means the second positional argument left-justified in a 10-character-wide field, and {0.platform:>10} means the platform attribute of the first argument right-justified in a 10-character-wide field (note again the use of dict() to make a dictionary from keyword arguments, covered in Chapter 4 and Chapter 8):
>>>'{0:10} = {1:10}'.format('spam', 123.4567)# In Python 3.3 'spam = 123.4567' >>>'{0:>10} = {1:<10}'.format('spam', 123.4567)' spam = 123.4567 ' >>>'{0.platform:>10} = {1[kind]:<10}'.format(sys, dict(kind='laptop'))' win32 = laptop '
In all cases, you can omit the argument number as of Python 2.7 and 3.1 if you’re selecting them from left to right with relative autonumbering—though this makes your code less explicit, thereby negating one of the reported advantages of the formatting method over the formatting expression (see the related note ahead):
>>>'{:10} = {:10}'.format('spam', 123.4567)'spam = 123.4567' >>>'{:>10} = {:<10}'.format('spam', 123.4567)' spam = 123.4567 ' >>>'{.platform:>10} = {[kind]:<10}'.format(sys, dict(kind='laptop'))' win32 = laptop '
Floating-point numbers support the same type codes and formatting specificity in formatting method calls as in % expressions. For instance, in the following {2:g} means the third argument formatted by default according to the “g” floating-point representation, {1:.2f} designates the “f” floating-point format with just two decimal digits, and {2:06.2f} adds a field with a width of six characters and zero padding on the left:
>>>'{0:e}, {1:.3e}, {2:g}'.format(3.14159, 3.14159, 3.14159)'3.141590e+00, 3.142e+00, 3.14159' >>>'{0:f}, {1:.2f}, {2:06.2f}'.format(3.14159, 3.14159, 3.14159)'3.141590, 3.14, 003.14'
Hex, octal, and binary formats are supported by the format method as well. In fact, string formatting is an alternative to some of the built-in functions that format integers to a given base:
>>>'{0:X}, {1:o}, {2:b}'.format(255, 255, 255)# Hex, octal, binary 'FF, 377, 11111111' >>>bin(255), int('11111111', 2), 0b11111111# Other to/from binary ('0b11111111', 255, 255) >>>hex(255), int('FF', 16), 0xFF# Other to/from hex ('0xff', 255, 255) >>>oct(255), int('377', 8), 0o377# Other to/from octal, in 3.X ('0o377', 255, 255) # 2.X prints and accepts 0377
Formatting parameters can either be hardcoded in format strings or taken from the arguments list dynamically by nested format syntax, much like the * syntax in formatting expressions’ width and precision:
>>>'{0:.2f}'.format(1 / 3.0)# Parameters hardcoded '0.33' >>>'%.2f' % (1 / 3.0)# Ditto for expression '0.33' >>>'{0:.{1}f}'.format(1 / 3.0, 4)# Take value from arguments '0.3333' >>>'%.*f' % (4, 1 / 3.0)# Ditto for expression '0.3333'
Finally, Python 2.6 and 3.0 also introduced a new built-in format function, which can be used to format a single item. It’s a more concise alternative to the string format method, and is roughly similar to formatting a single item with the % formatting expression:
>>>'{0:.2f}'.format(1.2345)# String method '1.23' >>>format(1.2345, '.2f')# Built-in function '1.23' >>>'%.2f' % 1.2345# Expression '1.23'
Technically, the format built-in runs the subject object’s __format__ method, which the str.format method does internally for each formatted item. It’s still more verbose than the original % expression’s equivalent here, though—which leads us to the next section.
If you study the prior sections closely, you’ll probably notice that at least for positional references and dictionary keys, the string format method looks very much like the % formatting expression, especially in advanced use with type codes and extra formatting syntax. In fact, in common use cases formatting expressions may be easier to code than formatting method calls, especially when you’re using the generic %s print-string substitution target, and even with autonumbering of fields added in 2.7 and 3.1:
print('%s=%s' % ('spam', 42)) # Format expression: in all 2.X/3.X
print('{0}={1}'.format('spam', 42)) # Format method: in 3.0+ and 2.6+
print('{}={}'.format('spam', 42)) # With autonumbering: in 3.1+ and 2.7
As we’ll see in a moment, more complex formatting tends to be a draw in terms of complexity (difficult tasks are generally difficult, regardless of approach), and some see the formatting method as redundant given the pervasiveness of the expression.
On the other hand, the formatting method also offers a few potential advantages. For example, the original % expression can’t handle keywords, attribute references, and binary type codes, although dictionary key references in % format strings can often achieve similar goals. To see how the two techniques overlap, compare the following % expressions to the equivalent format method calls shown earlier:
>>>'%s, %s and %s' % (3.14, 42, [1, 2])# Arbitrary types '3.14, 42 and [1, 2]' >>>'My %(kind)s runs %(platform)s' % {'kind': 'laptop', 'platform': sys.platform}'My laptop runs win32' >>>'My %(kind)s runs %(platform)s' % dict(kind='laptop', platform=sys.platform)'My laptop runs win32' >>>somelist = list('SPAM')>>>parts = somelist[0], somelist[-1], somelist[1:3]>>>'first=%s, last=%s, middle=%s' % parts"first=S, last=M, middle=['P', 'A']"
When more complex formatting is applied the two techniques approach parity in terms of complexity, although if you compare the following with the format method call equivalents listed earlier you’ll again find that the % expressions tend to be a bit simpler and more concise; in Python 3.3:
# Adding specific formatting >>>'%-10s = %10s' % ('spam', 123.4567)'spam = 123.4567' >>>'%10s = %-10s' % ('spam', 123.4567)' spam = 123.4567 ' >>>'%(plat)10s = %(kind)-10s' % dict(plat=sys.platform, kind='laptop')' win32 = laptop ' # Floating-point numbers >>>'%e, %.3e, %g' % (3.14159, 3.14159, 3.14159)'3.141590e+00, 3.142e+00, 3.14159' >>>'%f, %.2f, %06.2f' % (3.14159, 3.14159, 3.14159)'3.141590, 3.14, 003.14' # Hex and octal, but not binary (see ahead) >>>'%x, %o' % (255, 255)'ff, 377'
The format method has a handful of advanced features that the % expression does not, but even more involved formatting still seems to be essentially a draw in terms of complexity. For instance, the following shows the same result generated with both techniques, with field sizes and justifications and various argument reference methods:
# Hardcoded references in both >>>import sys>>>'My {1[kind]:<8} runs {0.platform:>8}'.format(sys, {'kind': 'laptop'})'My laptop runs win32' >>>'My %(kind)-8s runs %(plat)8s' % dict(kind='laptop', plat=sys.platform)'My laptop runs win32'
In practice, programs are less likely to hardcode references like this than to execute code that builds up a set of substitution data ahead of time (for instance, to collect input form or database data to substitute into an HTML template all at once). When we account for common practice in examples like this, the comparison between the format method and the % expression is even more direct:
# Building data ahead of time in both >>>data = dict(platform=sys.platform, kind='laptop')>>>'My {kind:<8} runs {platform:>8}'.format(**data)'My laptop runs win32' >>>'My %(kind)-8s runs %(platform)8s' % data'My laptop runs win32'
As we’ll see in Chapter 18, the **data in the method call here is special syntax that unpacks a dictionary of keys and values into individual “name=value” keyword arguments so they can be referenced by name in the format string—another unavoidable far conceptual forward reference to function call tools, which may be another downside of the format method in general, especially for newcomers.
As usual, though, the Python community will have to decide whether % expressions, format method calls, or a toolset with both techniques proves better over time. Experiment with these techniques on your own to get a feel for what they offer, and be sure to see the library reference manuals for Python 2.6, 3.0, and later for more details.
String format method enhancements in Python 3.1 and 2.7: Python 3.1 and 2.7 added a thousand-separator syntax for numbers, which inserts commas between three-digit groups. To make this work, add a comma before the type code, and between the width and precision if present, as follows:
>>>'{0:d}'.format(999999999999)'999999999999' >>>'{0:,d}'.format(999999999999)'999,999,999,999'
These Pythons also assign relative numbers to substitution targets automatically if they are not included explicitly, though using this extension doesn’t apply in all use cases, and may negate one of the main benefits of the formatting method—its more explicit code:
>>>'{:,d}'.format(999999999999)'999,999,999,999' >>>'{:,d} {:,d}'.format(9999999, 8888888)'9,999,999 8,888,888' >>>'{:,.2f}'.format(296999.2567)'296,999.26'
See the 3.1 release notes for more details. See also the formats.py comma-insertion and money-formatting function examples in Chapter 25 for a simple manual solution that can be imported and used prior to Python 3.1 and 2.7. As typical in programming, it’s straightforward to implement new functionality in a callable, reusable, and customizable function of your own, rather than relying on a fixed set of built-in tools:
>>>from formats import commas, money>>>'%s' % commas(999999999999)'999,999,999,999' >>>'%s %s' % (commas(9999999), commas(8888888))'9,999,999 8,888,888' >>>'%s' % money(296999.2567)'$296,999.26'
And as usual, a simple function like this can be applied in more advanced contexts too, such as the iteration tools we met in Chapter 4 and will study fully in later chapters:
>>>[commas(x) for x in (9999999, 8888888)]['9,999,999', '8,888,888'] >>>'%s %s' % tuple(commas(x) for x in (9999999, 8888888))'9,999,999 8,888,888' >>>''.join(commas(x) for x in (9999999, 8888888))'9,999,9998,888,888'
For better or worse, Python developers often seem to prefer adding special-case built-in tools over general development techniques—a tradeoff explored in the next section.
Now that I’ve gone to such lengths to compare and contrast the two formatting techniques, I wish to also explain why you still might want to consider using the format method variant at times. In short, although the formatting method can sometimes require more code, it also:
Has a handful of extra features not found in the % expression itself (though % can use alternatives)
Has more flexible value reference syntax (though it may be overkill, and % often has equivalents)
Can make substitution value references more explicit (though this is now optional)
Trades an operator for a more mnemonic method name (though this is also more verbose)
Does not allow different syntax for single and multiple values (though practice suggests this is trivial)
As a function can be used in places an expression cannot (though a one-line function renders this moot)
Although both techniques are available today and the formatting expression is still widely used, the format method might eventually grow in popularity and may receive more attention from Python developers in the future. Further, with both the expression and method in the language, either may appear in code you will encounter so it behooves you to understand both. But because the choice is currently still yours to make in new code, let’s briefly expand on the tradeoffs before closing the book on this topic.
The method call supports a few extras that the expression does not, such as binary type codes and (as of Python 2.7 and 3.1) thousands groupings. As we’ve seen, though, the formatting expression can usually achieve the same effects in other ways. Here’s the case for binary formatting:
>>>'{0:b}'.format((2 ** 16) − 1)# Expression (only) binary format code '1111111111111111' >>>'%b' % ((2 ** 16) − 1)ValueError: unsupported format character 'b'... >>>bin((2 ** 16) − 1)# But other more general options work too '0b1111111111111111' >>>'%s' % bin((2 ** 16) - 1)# Usable with both method and % expression '0b1111111111111111' >>>'{}'.format(bin((2 ** 16) - 1))# With 2.7/3.1+ relative numbering '0b1111111111111111' >>>'%s' % bin((2 ** 16) - 1)[2:]# Slice off 0b to get exact equivalent '1111111111111111'
The preceding note showed that general functions could similarly stand in for the format method’s thousands groupings option, and more fully support customization. In this case, a simple 8-line reusable function buys us the same utility without extra special-case syntax:
>>>'{:,d}'.format(999999999999)# New str.format method feature in 3.1/2.7 '999,999,999,999' >>>'%s' % commas(999999999999)# But % is same with simple 8-line function '999,999,999,999'
See the prior note for more comma comparisons. This is essentially the same as the preceding bin case for binary formatting, but the commas function here is user-defined, not built in. As such, this technique is far more general purpose than precoded tools or special syntax added for a single purpose.
This case also seems indicative, perhaps, of a trend in Python (and scripting language in general) toward relying more on special-case “batteries included” tools than on general development techniques—a mindset that makes code dependent on those batteries, and seems difficult to justify unless one views software development as an end-user enterprise. To some, programmers might be better served learning how to code an algorithm to insert commas than be provided a tool that does.
We’ll leave that philosophical debate aside here, but in practical terms the net effect of the trend in this case is extra syntax for you to have to both learn and remember. Given their alternatives, it’s not clear that these extra features of the methods by themselves are compelling enough to be decisive.
The method call also supports key and attribute references directly, which some may see as more flexible. But as we saw in earlier examples comparing dictionary-based formatting in the % expression to key and attribute references in the format method, the two are usually too similar to warrant a preference on these grounds. For instance, both can reference the same value multiple times:
>>>'{name} {job} {name}'.format(name='Bob', job='dev')'Bob dev Bob' >>>'%(name)s %(job)s %(name)s' % dict(name='Bob', job='dev')'Bob dev Bob'
Especially in common practice, though, the expression seems just as simple, or simpler:
>>>D = dict(name='Bob', job='dev')>>>'{0[name]} {0[job]} {0[name]}'.format(D)# Method, key references 'Bob dev Bob' >>>'{name} {job} {name}'.format(**D)# Method, dict-to-args 'Bob dev Bob' >>>'%(name)s %(job)s %(name)s' % D# Expression, key references 'Bob dev Bob'
To be fair, the method has even more specialized substitution syntax, and other comparisons might favor either scheme in small ways. But given the overlap and extra complexity, one could argue that the format method’s utility seems either a wash, or features in search of use cases. At the least, the added conceptual burden on Python programmers who may now need to know both tools doesn’t seem clearly justified.
One use case where the format method is at least debatably clearer is when there are many values to be substituted into the format string. The lister.py classes example we’ll meet in Chapter 31, for example, substitutes six items into a single string, and in this case the method’s {i} position labels seem marginally easier to read than the expression’s %s:
'\n%s<Class %s, address %s:\n%s%s%s>\n' % (...) # Expression '\n{0}<Class {1}, address {2}:\n{3}{4}{5}>\n'.format(...) # Method
On the other hand, using dictionary keys in % expressions can mitigate much of this difference. This is also something of a worst-case scenario for formatting complexity, and not very common in practice; more typical use cases seem more of a tossup. Further, as of Python 3.1 and 2.7, numbering substitution targets becomes optional when relative to position, potentially subverting this purported benefit altogether:
>>>'The {0} side {1} {2}'.format('bright', 'of', 'life')# Python 3.X, 2.6+ 'The bright side of life' >>>'The {} side {} {}'.format('bright', 'of', 'life')# Python 3.1+, 2.7+ 'The bright side of life' >>>'The %s side %s %s' % ('bright', 'of', 'life')# All Pythons 'The bright side of life'
Given its conciseness, the second of these is likely to be preferred to the first, but seems to negate part of the method’s advantage. Compare the effect on floating-point formatting, for example—the formatting expression is still more concise, and still seems less cluttered:
>>>'{0:f}, {1:.2f}, {2:05.2f}'.format(3.14159, 3.14159, 3.14159)'3.141590, 3.14, 03.14' >>>'{:f}, {:.2f}, {:06.2f}'.format(3.14159, 3.14159, 3.14159)'3.141590, 3.14, 003.14' >>>'%f, %.2f, %06.2f' % (3.14159, 3.14159, 3.14159)'3.141590, 3.14, 003.14'
The formatting method also claims an advantage in replacing the % operator with a more mnemonic format method name, and not distinguishing between single and multiple substitution values. The former may make the method appear simpler to beginners at first glance (“format” may be easier to parse than multiple “%” characters), though this probably varies per reader and seems minor.
Some may see the latter difference as more significant—with the format expression, a single value can be given by itself, but multiple values must be enclosed in a tuple:
>>>'%.2f' % 1.2345# Single value '1.23' >>>'%.2f %s' % (1.2345, 99)# Multiple values tuple '1.23 99'
Technically, the formatting expression accepts either a single substitution value, or a tuple of one or more items. As a consequence, because a single item can be given either by itself or within a tuple, a tuple to be formatted must be provided as a nested tuple—a perhaps rare but plausible case:
>>>'%s' % 1.23# Single value, by itself '1.23' >>>'%s' % (1.23,)# Single value, in a tuple '1.23' >>>'%s' % ((1.23,),)# Single value that is a tuple '(1.23,)'
The formatting method, on the other hand, tightens this up by accepting only general function arguments in both cases, instead of requiring a tuple both for multiple values or a single value that is a tuple:
>>>'{0:.2f}'.format(1.2345)# Single value '1.23' >>>'{0:.2f} {1}'.format(1.2345, 99)# Multiple values '1.23 99' >>>'{0}'.format(1.23)# Single value, by itself '1.23' >>>'{0}'.format((1.23,))# Single value that is a tuple '(1.23,)'
Consequently, the method might be less confusing to beginners and cause fewer programming mistakes. This seems a fairly minor issue, though—if you always enclose values in a tuple and ignore the nontupled option, the expression is essentially the same as the method call here. Moreover, the method incurs a price in inflated code size to achieve its constrained usage mode. Given the expression’s wide use over Python’s history, this issue may be more theoretical than practical, and may not justify porting existing code to a new tool that is so similar to that it seeks to subsume.
The final rationale for the format method—it’s a function that can appear where an expression cannot—requires more information about functions than we yet have at this point in the book, so we won’t dwell on it here. Suffice it to say that both the str.format method and the format built-in function can be passed to other functions, stored in other objects, and so on. An expression like % cannot directly, but this may be narrow-sighted—it’s trivial to wrap any expression in a one-line def or partial-line lambda once to turn it into a function with the same properties (though finding a reason to do so may be more challenging):
def myformat(fmt, args): return fmt % args # See Part IV myformat('%s %s', (88, 99)) # Call your function object str.format('{} {}', 88, 99) # Versus calling the built-in otherfunction(myformat) # Your function is an object too
In the end, this may not be an either/or choice. While the expression still seems more pervasive in Python code, both formatting expressions and methods are available for use in Python today, and most programmers will benefit from being familiar with both techniques for years to come. That may double the work of newcomers to the language in this department, but in this bazaar of ideas we call the open source software world, there always seems to be room for more.[17]
Plus one more: Technically speaking, there are 3 (not 2) formatting tools built into Python, if we include the obscure string module’s Template tool mentioned earlier. Now that we’ve seen the other two, I can show you how it compares. The expression and method can be used as templating tools too, referring to substitution values by name via dictionary keys or keyword arguments:
>>>'%(num)i = %(title)s' % dict(num=7, title='Strings')'7 = Strings' >>>'{num:d} = {title:s}'.format(num=7, title='Strings')'7 = Strings' >>>'{num} = {title}'.format(**dict(num=7, title='Strings'))'7 = Strings'
The module’s templating system allows values to be referenced by name too, prefixed by a $, as either dictionary keys or keywords, but does not support all the utilities of the other two methods—a limitation that yields simplicity, the prime motivation for this tool:
>>>import string>>>t = string.Template('$num = $title')>>>t.substitute({'num': 7, 'title': 'Strings'})'7 = Strings' >>>t.substitute(num=7, title='Strings')'7 = Strings' >>>t.substitute(dict(num=7, title='Strings'))'7 = Strings'
See Python’s manuals for more details. It’s possible that you may see this alternative (as well as additional tools in the third-party domain) in Python code too; thankfully this technique is simple, and is used rarely enough to warrant its limited coverage here. The best bet for most newcomers today is to learn and use %, str.format, or both.
[17] See also the Chapter 31 note about a str.format bug (or regression) in Pythons 3.2 and 3.3 concerning generic empty substitution targets for object attributes that define no __format__ handler. This impacted a working example from this book’s prior edition. While it may be a temporary regression, it does at the least underscore that this method is still a bit of a moving target—yet another reason to question the feature redundancy it implies.