{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Lecture 7\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "-Introduction: [>>](#Introduction) \n", "-Boolean variables: [>>](#Boolean-variables) \n", "-Pretty printing: [>>](#Pretty-printing) \n", "-Using f-strings: [>>](#Using-f-strings) \n", "-Using format statements: [>>](#Using-format-statements) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Introduction\n", "\n", "In this lecture we will learn about boolean variable and then look at some ways of improving the clarity of printed output. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Boolean variables\n", "\n", "There are many situations where expressions are either true or false, so Python has `bool` variables (short for boolean), named after [George Boole](https://en.wikipedia.org/wiki/George_Boole), which can only take these two values. For example:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "boolVar1 True\n" ] } ], "source": [ "boolVar1 = True\n", "print(\"boolVar1\",boolVar1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Numbers can be compared in a variety of ways, producing the values `True` or `False`, for example:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "boolVar2 True\n" ] } ], "source": [ "#\n", "# greater than\n", "boolVar2 = 3 > 2\n", "print(\"boolVar2\",boolVar2)" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "boolVar3 False\n" ] } ], "source": [ "boolVar3 = 2 > 3\n", "print(\"boolVar3\",boolVar3)" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2 < 3 True\n" ] } ], "source": [ "#\n", "# less than\n", "print(\"2 < 3\",2 < 3) " ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2 == 2 True\n" ] } ], "source": [ "#\n", "# equal to\n", "print(\"2 == 2\",2 == 2) " ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2 >= 2 True\n" ] } ], "source": [ "#\n", "# greater than or equal to\n", "print(\"2 >= 2\",2 >= 2) " ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3 <= 2 False\n" ] } ], "source": [ "#\n", "# less than or equal to\n", "print(\"3 <= 2\",3 <= 2) " ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2 != 2 False\n" ] } ], "source": [ "#\n", "# not equal to\n", "print(\"2 != 2\",2 != 2) " ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "floatX == floatY True\n" ] } ], "source": [ "#\n", "# equal to\n", "floatX = 2.0\n", "floatY = 2.0\n", "print(\"floatX == floatY\",floatX == floatY) # This is a really bad idea!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As mentioned in previous lectures, there are some potential pitfalls in comparing numbers. While it makes sense to test if two integers are equal, this is very risky (that means don't do it!) for `floats`, as even real numbers that you know should be mathematically identical may be different on your computer because of errors in their calculation or representation. For `floats`, \"equality\" can be tested in the following way:\n", "\n", "```Python\n", "epsilon = 1E-10\n", "boolVar = np.abs(floatX - floatY) < epsilon\n", "```\n", "Choose a sensible value of `epsilon`, dependent on the errors you expect in the calculation of `floatX` and `floatY` and the precision of your machine. (We saw how to determine the latter last week!)\n", "\n", "Boolean operators (`and`, `or`, and `not`) can also be used to act on `bool` objects: " ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True and True = True\n" ] } ], "source": [ "print(\"True and True =\",True and True)" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True and False = False\n" ] } ], "source": [ "print(\"True and False =\",True and False)" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "not True = False\n" ] } ], "source": [ "print(\"not True =\",not True)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False or True = True\n" ] } ], "source": [ "print(\"False or True =\",False or True)" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False or False = False\n" ] } ], "source": [ "print(\"False or False =\",False or False)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True or True = True\n" ] } ], "source": [ "print(\"True or True =\",True or True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we have already seen, one nice feature of Python is the ease with which strings can be manipulated. Last week, we looked at the letters in \"Constantinople\". Here, we see how we can easily determine if a particular character or word is `in` (or `not in`) a string. These tests return a `bool`:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'Mary' is in ' Mary had a little lamb ' is True\n" ] } ], "source": [ "testString = \"Mary had a little lamb\"\n", "wordFound = \"Mary\" in testString\n", "print(\"'Mary' is in '\",testString,\"' is\",wordFound)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Notice that \"Mary\" and \"mary\" are not the same; in Python, size matters!" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'mary' is in ' Mary had a little lamb ' is False\n" ] } ], "source": [ "wordFound = \"mary\" in testString\n", "print(\"'mary' is in '\",testString,\"' is\",wordFound)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note, we don't have to use a variable like `wordFound`, we could put the test in the print statement. It might be a little confusing, though! " ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'Wolf' is not in ' Mary had a little lamb ' is True\n" ] } ], "source": [ "print(\"'Wolf' is not in '\",testString,\"' is\",\"Wolf\" not in testString)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Of course, we could also write `testString` directly into the print statement:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "'Wolf' is not in 'Mary had a little lamb' is True\n" ] } ], "source": [ "print(\"'Wolf' is not in 'Mary had a little lamb' is\",\"Wolf\" not in \"Mary had a little lamb\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Pretty printing\n", "\n", "We have seen in previous lectures how we can improve printed output by using formatted strings, or `f-strings`. We will now look at these in a bit more detail. Then we will look at how `format` statements can be used as an alternative to `f-strings`. While `format` statements have long been a feature of Python, `f-strings` were first introduced in Python 3.6 (in 2016). This means that many programs still use `format` statements, so it is useful to know something about them, even if it is usually better to use `f-strings`!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "## Using f-strings\n", "\n", "An example illustrating printing using the `f-string` syntax is shown below, together with the equivalent \"plain\" print statement. Notice how the `\\b` control character must be used to produce a backspace in the latter case to ensure that there aren't spurious spaces in front of the comma and the full stop!" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 999.999999, small is 6.66666666e-17, number is 33 and string is letters!\n", "Big is 999.999999, small is 6.66666666e-17, number is 33 and string is letters!\n" ] } ], "source": [ "big = 999.999999\n", "small = 666.666666E-19\n", "number = 33\n", "string = 'letters'\n", "print(f\"Big is {big}, small is {small}, number is {number} and string is {string}!\")\n", "print(\"Big is\",big,\"\\b, small is\",small,\"\\b, number is\",number,\"and string is\",string,\"\\b!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `f-string` allows us to include a *format field* in the string we want to write, denoted by curly brackets (braces), which indicates that a variable (or expression - see later!) should be incorporated into the string at that point. Python chooses sensible defaults for the format used for these variables, but symbols inside the braces can be used to specify the format required, e.g. `f` for float, `e` for scientific notation, `d` for integer and `s` for string. How these are included is illustrated below:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 999.999999, small is 6.666667e-17 number is 33 and string is letters!\n" ] } ], "source": [ "big = 999.999999\n", "print(f\"Big is {big:f}, small is {small:e} number is {number:d} and string is {string:s}!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As print statements are often long, it is useful to know that Python will allows us to produce a single line of output using two lines in a print statement as below. Notice that each line in the `print` statement has to be an `f-string`! " ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 999.999999, small is 6.666667e-17, number is 33 and string is letters!\n" ] } ], "source": [ "print(f\"Big is {big:f}, small is {small:e},\",\n", " f\"number is {number:d}\",\n", " f\"and string is {string:s}!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Alternatively, you can use a backslash (\\) at the end of each line that is to be continued, as here:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 999.999999, small is 6.666667e-17, number is 33 and string is letters!\n" ] } ], "source": [ "print(f\"Big is {big:f}, \\\n", "small is {small:e}, \\\n", "number is {number:d} and string is {string:s}!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using an `f-string` above has helped improve the print statement output in some respects (we don't need to use the `\\b` backspace character to ensure the comma and fullstop are in the right place). Another useful feature of the `f-string ` is that we can steer the number of figures we want after the decimal point (for floats or exponentials) as follows:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 1000.00, small is 6.67e-17 and number is 33!\n" ] } ], "source": [ "print(f\"Big is {big:.2f}, small is {small:.2e} and number is {number:d}!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that numbers are rounded sensibly. (You can't specify the number of figures after the decimal point for integers of course!) \n", "\n", "We can also control the length of the number that is printed out (including the spaces in front of the number) by adding an integer in front of the decimal point in the format specifiers:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 1000.00, small is 6.667e-17 and number is 33.\n" ] } ], "source": [ "print(f\"Big is {big:12.2f}, small is {small:12.3e} and number is {number:12d}.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "The equivalent for strings is shown below:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "String is letters .\n" ] } ], "source": [ "print(f\"String is {string:12s}.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "By default, numbers are aligned to the right (right justified) and strings to the left (left justified), but this can be changed using the characters `<`, `>` and `^` for left, right and central alignment, respectively, as illustrated below:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 1000.00 , small is 6.667e-17 , number is 33 and string is letters.\n" ] } ], "source": [ "print(f\"Big is {big:<12.2f}, small is {small:^12.3e}, number is {number:>12d} and string is {string:>12s}.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "In `f-strings`, the `f` can also be an `F`!" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello John, did you know f-strings were introduced in 2016?\n", "No, Fiona, I didn't!\n" ] } ], "source": [ "nameJ = 'John'\n", "nameF = 'Fiona'\n", "year = 2016\n", "print(F\"Hello {nameJ}, did you know f-strings were introduced in {year}?\")\n", "print(F\"No, {nameF}, I didn't!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The braces can contain expressions that are calculated at run time (i.e. when the print statement is executed), for example:" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The product of 2 and 7 is 14. The larger of 2 and 7 is 7.\n" ] } ], "source": [ "x = 2\n", "y = 7\n", "print(f\"The product of {x} and {y} is {x*y}. The larger of {x} and {y} is {max(x, y)}.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The following example illustrates how some of the above techniques can be used to align columns of numbers:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Number Square Cube\n", " 0 0 0\n", " 1 1 1\n", " 2 4 8\n", " 3 9 27\n", " 4 16 64\n", " 5 25 125\n", " 6 36 216\n", " 7 49 343\n", " 8 64 512\n", " 9 81 729\n" ] } ], "source": [ "nMax = 10\n", "nMin = 0\n", "print(\"Number Square Cube\")\n", "for n in range(nMin, nMax):\n", " print(f\"{n:6d} {n**2:6d} {n**3:6d}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Using \"tab\" characters (`\\t`) can also help with formatting columns of numbers (though you might have to do some tweaking to get things to line up as you want!). A tab is eight characters long. Here is an example: " ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Months in the year:\n", "1 \t 2 \t 3 \t 4 \t 5 \t 6 \t 7 \t 8 \t 9 \t 10 \t 11 \t 12\n", "Jan \t Feb \t Mar \t Apr \t May \t Jun \t Jul \t Aug \t Sept \t Oct \t Nov \t Dec\n" ] } ], "source": [ "print(\"Months in the year:\")\n", "print(\"1 \\t 2 \\t 3 \\t 4 \\t 5 \\t 6 \\t 7 \\t 8 \\t 9 \\t 10 \\t 11 \\t 12\")\n", "print(\"Jan \\t Feb \\t Mar \\t Apr \\t May \\t Jun \\t Jul \\t Aug \\t Sept \\t Oct \\t Nov \\t Dec\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Note, there are lots more tools for writing things prettily, see [here](https://docs.python.org/3/tutorial/inputoutput.html), for example." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using format statements\n", "\n", "Everything we have done using `f-strings` can also be done using the `format` syntax, as shown below. Instead of including the variables that are to be printed at the relevant place in the string, they are added (in the required order) in a `format` statement after the string. The *format field* in the string can be used to indicate that an `int`, a `float` or a `str` should be included at that point. The format field is denoted by curly brackets, with the symbols inside the brackets indicating the format of the variable that should be substituted at that point (e.g. `f` for float, `e` for scientific notation, `d` for integer and `s` for string, as for `f-strings`). " ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 999.999999, small is 6.666667e-17, number is 33 and string is letters!\n" ] } ], "source": [ "print(\"Big is {:f}, small is {:e}, number is {:d} and string is {:s}!\".format(big, small, number, string))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "The `format` printing method allows us to steer the number of figures we want after the decimal point (for floats or exponentionals) as follows:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 1000.00, small is 6.667e-17 and number is 33.\n" ] } ], "source": [ "print(\"Big is {:.2f}, small is {:.3e} and number is {:d}.\".format(big, small, number))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "We can also control the length of the number that is printed out:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 1000.00, small is 6.667e-17 and number is 33.\n" ] } ], "source": [ "print(\"Big is {:12.2f}, small is {:12.3e} and number is {:12d}.\".format(big, small, number))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "Alignment can be changed, as for `f-strings`:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Big is 1000.00 , small is 6.667e-17 and number is 33 .\n" ] } ], "source": [ "print(\"Big is {:<12.2f}, small is {:^12.3e} and number is {:<12d}.\".format(big, small, number))" ] } ], "metadata": { "anaconda-cloud": {}, "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.5" } }, "nbformat": 4, "nbformat_minor": 4 }