Printing and Formatting¶
Indices and tables¶
Printing¶
Strings, and things that can automatically be converted to a string (like int), are printed to a text stream using the print()
method, which has the following signature:
-
print
(*objects, sep=" ", end="\n", file=sys.stdout, flush=False)¶
By default, any output gets sent to stdout. However, print statements can also direct their output to stderr, or, any text file opened using the open()
function.
When printing, the stream may be buffered. To flush the buffer at any given time, set the flush
keyword argument to True
.
The print()
function allows multiple, separate strings to be output at once, each demarkated using the string given by sep
. After all strings are output, print()
inserts the end
string to finish it off. For example:
With default sep
and end
, there is a space between strings and a newline at the end:
>>> print('foo', 'bar', 'baz')
foo bar baz
The sep
string can be changed to alter the intra-string space:
>>> print('foo', 'bar', 'baz', sep='-')
foo-bar-baz
>>> print('foo', 'bar', 'baz', sep='')
foobarbaz
The end
string can be changed to alter the end of the output:
>>> print('foo', 'bar', 'baz', end='#')
foo bar baz#
Setting end
to be an empty string is a good way to prevent newlines between multiple print()
statements. Consider the following examples:
>>> print('foo'); print('bar'); print('baz')
foo
bar
baz
>>> print('foo', end=''); print('bar', end=''); print('baz', end='')
foobarbaz
Python can output 2 types of strings:
- The “informal” string, which is nicely formatted and meant to be easily understandable by users. This format cannot be passed to the
eval()
function to recreate the object. This is the format theprint()
function attempts to always produce by default (under the hood, it calls the objects__str__()
method). For example:>>> import datetime >>> alarm = datetime.time(7, 30, 00) >>> print(alarm) 07:30:00
- The “formal” string, which is not necessarily nicely formatted, but, it can be passed to the
eval()
function to recreate the object. This format is also called the, representational or reproducing format, and is obtained by calling the objects__repr__()
method. For example:>>> import datetime >>> alarm = datetime.time(7, 30, 00) >>> alarm.__repr__() 'datetime.time(7, 30)' >>> alarm2 = eval('datetime.time(7, 30)') >>> type(alarm2) datetime.time >>> print(alarm2) 07:30:00Not all objects can produce a reproducing output. If the there is no reproducing output available, an informational string is output between
< >
brackets instead. For example:>>> a = object() # As instance of the base class of all objects >>> a.__repr__() '<object object at 0x7f6ab24d7590>'
Try it!
- Create two, multi-line strings.
- Print the multi-line strings created above using one print statement such that the strings are separated by “::”, and a single “%” is printed at the end of the printed text.
Formatting¶
In contrast to the Zen of Python (PEP 20) idea that there should be one obvious way to do something, Python supports several methods for formatting strings for display.
C-Style printf¶
This is the “old” style that uses the %
operator (a.k.a. the string formatting or interpolation operator) and resembles the printf
support in C. It works as follows:
- Embed
%
in string to indicate a replacement field- After
%
in string, place a conversion type character- After string is closed, place a
%
, followed by a single non-tuple, a tuple or a dict.
For example:
>>> print("ERROR NUM: %d MSG: %s" % (5, 'Engine shutdown late.'))
ERROR NUM: 5 MSG: Engine shutdown late.
There are many conversion types that are supported as well as flags for padding and justification. However, this style is deprecated in favor of other methods (it doesn’t work well with tuples and dicts) so it won’t be discussed further.
Template Strings¶
Template strings provide a simple substitution method that uses the $
character instead of %
. It works as follows:
Import Template from the string standard library package
Construct the template string that needs fields replaced at runtime using:
$$
is an escape to get a literal$
- $identifier as a placeholder for a value that needs to be substituted in when expanded.
Call
substitute()
on the template to expand the embedded identifiers and fill them with values passed into thesubstitute()
method.
For example:
>>> from string import Template
>>> t = Template('Hello $thing')
>>> t.substitute(thing="World")
'Hello World'
>>> t.substitute(thing="Students")
'Hello Students'
The upside to Template strings is that they allow you to accept formatting strings from users at run-time. Additionally, due to their simplistic nature they can only access values passed in to the substitute()
method which prevents malicious format strings from accessing data in your program that should be off limits.
The downside to template strings is you can’t include any additional format conversion or alignment flags in the template like you can with the other formatting methods. If required, you must pre-format the data prior to substituting in the final values.
Format Strings¶
Format strings are the “new” style (defined in PEP 3101) used to format strings. There are 2 ways to access this machinery
- the built-in function
format()
, or,- the
format()
method on instances of the string class.
Both use the same implementation under the hood.
A format string contains 2 types of elements:
- Literal text, which is copied verbatim to the output.
- Replacement fields, which have formatted text substituted in.
A replacement field is surrounded by {}
braces and specifies 2 things:
- What to print
- How to format the thing being printed.
A full description of replacement fields is provided here. In short, a replacement field can be represented by the production shown below:
replacement_field ::= “{” [field_name] [“!” conversion] [“:”format_spec
] “}” field_name ::= arg_name (“.” attribute_name | “[” element_index “]”)* arg_name ::= [identifier
|integer
] attribute_name ::=identifier
element_index ::=integer
| index_string
In it:
field_name
is the “what to print”, and,format_spec
is the “how to format the thing being printed”.
Let’s run though some examples of how to choose what to print. There are several options:
By position using the order of arguments, as in:
>>> print("The {} and the {}".format("foo", "bar", "baz"))
The foo and the bar
By position using specific arguments by number, as in:
>>> print("The {0} and the {1}".format("foo", "bar", "baz"))
The foo and the bar
>>> print("The {0} and the {2}".format("foo", "bar", "baz"))
The foo and the baz
By referring to arguments by name, as in:
>>> print("The {a} and the {b}".format(a="foo", b="bar", c="baz"))
The foo and the bar
>>> print("The {c} and the {a}".format(a="foo", b="bar", c="baz"))
The baz and the foo
If you have an argument that is a sequence, you can pull out elements by index, as in:
>>> vals = ('foo', 'bar', 'baz')
>>> print("The {0[0]} and the {0[1]}".format(vals))
The foo and the bar
>>> print("The {0[0]} and the {0[2]}".format(vals))
The foo and the baz
You can do the same thing with a mapping, as in;
>>> vals = {'a' : 'foo',
'b' : 'bar',
'c' : 'baz'}
>>> print("The {0[a]} and the {0[b]}".format(vals))
The foo and the bar
>>> print("The {0[a]} and the {0[c]}".format(vals))
The foo and the baz
Note
When specifying a string index to a mapping in a replacement field, you don’t use quotes.
And of course, for either a sequence or a mapping, you can give the argument a name like we did earlier, as in:
>>> vals = ('foo', 'bar', 'baz')
>>> print("The {v[0]} and the {v[1]}".format(v=vals))
The foo and the bar
>>> vals = {'a' : 'foo',
'b' : 'bar',
'c' : 'baz'}
>>> print("The {v[a]} and the {v[b]}".format(v=vals))
The foo and the bar
This isn’t an exhaustive set of examples of what you can do. Reading the official documentation on the Python website will serve you well in the long term.
Once you have determined what you want to print, you have the option of deciding how you want it printed. This choice relates to the format_spec
portion of the replacement field and there is an entire format specification language which you can (and should) read about here.
In short, a format_spec, which is a string of characters, can be represented by the production shown below;
format_spec ::= [[fill]align][sign][#][0][width][,][.precision][type]
A summary of what you can do using each field is shown in Fig. 29:
Note
Don’t forget that the format_spec
always comes after the :
.
Let’s run through some examples.
Padding and alignment with a minimum field width:
>>> print("The {:-<8} and the {:-^8} and the {:->8}".format("foo", "bar", "baz"))
The foo----- and the --bar--- and the -----baz
Using the minimum and maximum field width:
>>> print("The {:.5} {:.5}".format("fookoozoo"))
The fooko
Showing the sign of a number:
>>> print("A={:+} B={:-} C={: }".format(-1, -1, -1))
A=-1 B=-1 C=-1
>>> print("A={:+} B={:-} C={: }".format(1, 1, 1))
A=+1 B=1 C= 1
Format conversion of integers to different bases:
>>> print("{0} {0:b} {0:o} {0:x} {0:X}".format(95))
95 1011111 137 5f 5F
>>> print("{0} {0:#b} {0:#o} {0:#x} {0:#X".format(95))
95 0b1011111 0o137 0x5f 0X5F
Format conversion of integers to their character equivalent:
>>> print("{0} {0:c}".format(95))
95 _
Format conversion of floats to scientific exponent notation:
>>> print("{0} {0:e} {0:E}".format(95.62524895212))
95.62524895212 9.562525e+01 9.562525E+01
Format conversion of floats to fixed point notation with a precision given by the precision field (defaults to 6 digits):
>>> print("{0} {0:f} {0:F}".format(95.62524895212))
95.62524895212 95.625249 95.625249
>>> print("{0} {0:.8f} {0:.8F}".format(95.62524895212))
95.62524895212 95.62524895 95.62524895
Format conversion of floats to the general format which rounds to number of significant digits given by the precision field (defaults to 6 digits):
>>> print("{0} {0:g} {0:G}".format(95.62524895212))
95.62524895212 95.6252 95.6252
>>> print("{0} {0:.8g} {0:.8G}".format(95.62524895212))
95.62524895212 95.625249 95.625249
Format conversion of floats to percentage:
>>> print("{0} {0:%}".format(95.62524895212))
95.62524895212 9562.524895%
The built-in format() is good for formatting single values, as in:
>>> foo = format(255, ':>5x')
>>> foo
':::ff'
Similar to the discussion around field_name, this isn’t an exhaustive set of examples of how you can format the output. Reading the official documentation on the Python website will serve you well in the long term.
F-strings¶
While this course only covers what is available in Python 3.5, there is yet another way to generate strings that became available in Python v3.6. It is powerful and exciting new feature that deserves a brief mention even if they can’t be used in this course.
F-strings, or Formatted String Literals, supports the same syntax as str.format()
but they also allow you to do embed expressions inside string literals. The replacement fields are expressions that are evaluated at run-time (thus the string literal is not actually a constant) and the results are then formatted using format()
.
To create an f-string literal, you just prepend the string with ‘f’, as in:
>>> f'Hello World'
Here is an example from PEP 498 that gives an example of its use:
>>> import datetime
>>> name = 'Fred'
>>> age = 50
>>> anniversary = datetime.date(1991, 10, 12)
>>> f'My name is {name}, my age next year is {age+1}, my anniversary is {anniversary:%A,
%B %d, %Y}.'
'My name is Fred, my age next year is 51, my anniversary is Saturday, October 12, 1991.'
>>> f'He said his name is {name!r}.'
"He said his name is 'Fred'."
Try it!
Since C-Style strings are deprecated, template strings have limited use and F-strings are only available in Python 3.6, this Try-It section will focus specifically on Format Strings.
Given the integer value, 1234, use formatting to print it in the following ways:
- As a hexadecimal value with the 0x prefix, right justified in a column 10 characters wide.
- As a decimal value, centered in a column 10 characters wide, with “*“‘s around it.
- As a binary value