Printing and Formatting ======================= .. toctree:: :maxdepth: 1 Indices and tables ------------------ * :ref:`genindex` * :ref:`modindex` * :ref:`search` .. _section_heading-Printing: Printing -------- Strings, and things that can automatically be converted to a string (like int), are printed to a text stream using the :py:func:`print` method, which has the following signature: .. py:function:: 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 :py:func:`open` function. When printing, the stream may be buffered. To flush the buffer at any given time, set the ``flush`` keyword argument to :py:obj:`True`. The :py:func:`print` function allows multiple, separate strings to be output at once, each demarkated using the string given by ``sep``. After all strings are output, :py:func:`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 :py:func:`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: 1) The "informal" string, which is nicely formatted and meant to be easily understandable by users. This format cannot be passed to the :py:func:`eval` function to recreate the object. This is the format the :py:func:`print` function attempts to always produce by default (under the hood, it calls the objects :py:meth:`__str__` method). For example: >>> import datetime >>> alarm = datetime.time(7, 30, 00) >>> print(alarm) 07:30:00 2) The "formal" string, which is not necessarily nicely formatted, but, it can be passed to the :py:func:`eval` function to recreate the object. This format is also called the, representational or reproducing format, and is obtained by calling the objects :py:meth:`__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:00 Not 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__() '' .. admonition:: Try it! :class: TryIt * 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. .. _section_heading-Formatting: 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. .. _section_heading-C_Style_Printf: 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. .. _section_heading-Template_Strings: 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 :py:meth:`substitute` on the template to expand the embedded identifiers and fill them with values passed into the :py:meth:`substitute` 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 :py:meth:`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. .. _section_heading-Format_Strings: 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 :py:func:`format`, or, * the :py:meth:`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: .. productionlist:: py_replacement_fields 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; .. productionlist:: py_replacement_fields format_spec : [[fill]align][sign][#][0][width][,][.precision][type] A summary of what you can do using each field is shown in :numref:`figure-Format_Spec_Fields`: .. _figure-Format_Spec_Fields: .. figure:: format_spec_fields.png :scale: 100 % :align: center Format Specification Fields .. 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. .. _section_heading-F_Strings: 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 :py:meth:`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 :py:func:`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'." .. admonition:: Try it! :class: TryIt 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 .. _FormatStringSyntax: https://docs.python.org/3.5/library/string.html#format-string-syntax .. _FormatSpecLanguage: https://docs.python.org/3.5/library/string.html#format-specification-mini-language