{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# 1.3 Types" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Estimated time for this notebook: 20 minutes*" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We have seen that Python objects have a 'type':" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3.1 Floats and integers" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python has two core numeric types, `int` for integer, and `float` for real number." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "one = 1\n", "ten = 10\n", "one_float = 1.0\n", "ten_float = 10.0" ] }, { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "Zero after a point is optional. But the **Dot** makes it a float." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [], "source": [ "tenth = one_float / ten_float" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.1" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "tenth" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(one)" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(one_float)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The meaning of an operator varies depending on the type it is applied to!" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n" ] } ], "source": [ "print(one // ten)" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.1" ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "one_float / ten_float" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "print(type(one / ten))" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(tenth)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The divided by operator when applied to floats, and integers means divide by for real numbers.\n", "\n", "The `//` operator means divide and then round down" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3" ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "10 // 3" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.3333333333333335" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "10.0 / 3" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.3333333333333335" ] }, "execution_count": 13, "metadata": {}, "output_type": "execute_result" } ], "source": [ "10 / 3.0" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There is a function for every type name, which is used to convert the input to an output of the desired type." ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "float" ] }, "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], "source": [ "x = float(5)\n", "type(x)" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "3.3333333333333335" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "10 / float(3)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "I lied when I said that the `float` type was a real number. It's actually a computer representation of a real number\n", "called a \"floating point number\". Representing $\\sqrt 2$ or $\\frac{1}{3}$ perfectly would be impossible in a computer, so we use a finite amount of memory to do it." ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.9999999999999062" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "N = 10000.0\n", "sum([1 / N] * int(N))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "*Supplementary material*:\n", "\n", "* https://docs.python.org/3/tutorial/floatingpoint.html\n", "* http://floating-point-gui.de/formats/fp/\n", "* Advanced: http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3.2 Strings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python has a built in `string` type, supporting many\n", "useful methods." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [], "source": [ "given = \"James\"\n", "family = \"Hetherington\"\n", "full = given + \" \" + family" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So `+` for strings means \"join them together\" - *concatenate*." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "JAMES HETHERINGTON\n" ] } ], "source": [ "print(full.upper())" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As for `float` and `int`, the name of a type can be used as a function to convert between types:" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(10, 1)" ] }, "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], "source": [ "ten, one" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11\n" ] } ], "source": [ "print(ten + one)" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "101.0\n" ] } ], "source": [ "print(float(str(ten) + str(one)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can remove extraneous material from the start and end of a string:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'Hello'" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\" Hello \".strip()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that you can write strings in Python using either single (`' ... '`) or double (`\" ... \"`) quote marks. The two ways are equivalent. However, if your string includes a single quote (e.g. an apostrophe), you should use double quotes to surround it:" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "\"James's Class\"" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"James's Class\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And vice versa: if your string has a double quote inside it, you should wrap the whole string in single quotes." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'\"Wow!\", said Bob.'" ] }, "execution_count": 24, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'\"Wow!\", said Bob.'" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3.3 Lists" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python's basic **container** type is the `list`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can define our own list with square brackets:" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[1, 3, 7]" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[1, 3, 7]" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "list" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type([1, 3, 7])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists *do not* have to contain just one type:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [], "source": [ "various_things = [1, 2, \"banana\", 3.4, [1, 2]]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We access an **element** of a list with an `int` in square brackets:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'banana'" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "various_things[2]" ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 29, "metadata": {}, "output_type": "execute_result" } ], "source": [ "index = 0\n", "various_things[index]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that list indices start from zero." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can use a string to join together a list of strings:" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "James==Philip==John==Hetherington\n" ] } ], "source": [ "name = [\"James\", \"Philip\", \"John\", \"Hetherington\"]\n", "print(\"==\".join(name))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And we can split up a string into a list:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Ernst', 'Stavro', 'Blofeld']" ] }, "execution_count": 31, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"Ernst Stavro Blofeld\".split(\" \")" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['Ernst Stavr', ' Bl', 'feld']" ] }, "execution_count": 32, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"Ernst Stavro Blofeld\".split(\"o\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And combine these:" ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'John->Ronald->Reuel->Tolkien'" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"->\".join(\"John Ronald Reuel Tolkien\".split(\" \"))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A matrix can be represented by **nesting** lists -- putting lists inside other lists." ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "identity = [[1, 0], [0, 1]]" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "identity[0][0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "... but later we will learn about a better way of representing matrices." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3.4 Ranges" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another useful type is range, which gives you a sequence of consecutive numbers. In contrast to a list, ranges generate the numbers as you need them, rather than all at once.\n", "\n", "If you try to print a range, you'll see something that looks a little strange: " ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "range(0, 5)" ] }, "execution_count": 36, "metadata": {}, "output_type": "execute_result" } ], "source": [ "range(5)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We don't see the contents, because *they haven't been generatead yet*. Instead, Python gives us a description of the object - in this case, its type (range) and its lower and upper limits." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can quickly make a list with numbers counted up by converting this range:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4]\n" ] } ], "source": [ "count_to_five = range(5)\n", "print(list(count_to_five))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Ranges in Python can be customised in other ways, such as by specifying the lower limit or the step (that is, the difference between successive elements). You can find more information about them in the [official Python documentation](https://docs.python.org/3/library/stdtypes.html#ranges)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3.5 Sequences" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Many other things can be treated like `lists`. Python calls things that can be treated like lists `sequences`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A string is one such *sequence type*." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sequences support various useful operations, including:\n", "- Accessing a single element at a particular index: `sequence[index]`\n", "- Accessing multiple elements (a *slice*): `sequence[start:end_plus_one]`\n", "- Getting the length of a sequence: `len(sequence)`\n", "- Checking whether the sequence contains an element: `element in sequence`\n", "\n", "The following examples illustrate these operations with lists, strings and ranges." ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n" ] } ], "source": [ "print(count_to_five[1])" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "m\n" ] } ], "source": [ "print(\"James\"[2])" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [], "source": [ "count_to_five = range(5)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "range(1, 3)" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "count_to_five[1:3]" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'o Wo'" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"Hello World\"[4:8]" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "5" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(various_things)" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "6" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "len(\"Python\")" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['James', 'Philip', 'John', 'Hetherington']" ] }, "execution_count": 45, "metadata": {}, "output_type": "execute_result" } ], "source": [ "name" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"John\" in name" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "True" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "3 in count_to_five" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 1.3.6 Unpacking" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Multiple values can be **unpacked** when assigning from sequences, like dealing out decks of cards." ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "World\n" ] } ], "source": [ "mylist = [\"Hello\", \"World\"]\n", "a, b = mylist\n", "print(b)" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "range(0, 4)" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" } ], "source": [ "range(4)" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [], "source": [ "zero, one, two, three = range(4)" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "2" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "two" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If there is too much or too little data, an error results:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "too many values to unpack (expected 4)", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/var/folders/q7/nl3w6z854711jwsdy0hj7sxhwypcgh/T/ipykernel_63975/2891450249.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mzero\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtwo\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mthree\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m7\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: too many values to unpack (expected 4)" ] } ], "source": [ "zero, one, two, three = range(7)" ] }, { "cell_type": "code", "execution_count": 53, "metadata": { "tags": [ "raises-exception" ] }, "outputs": [ { "ename": "ValueError", "evalue": "not enough values to unpack (expected 4, got 2)", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mValueError\u001b[0m Traceback (most recent call last)", "\u001b[0;32m/var/folders/q7/nl3w6z854711jwsdy0hj7sxhwypcgh/T/ipykernel_63975/4218591722.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mzero\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mtwo\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mthree\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m2\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mValueError\u001b[0m: not enough values to unpack (expected 4, got 2)" ] } ], "source": [ "zero, one, two, three = range(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python provides some handy syntax to split a sequence into its first element (\"head\") and the remaining ones (its \"tail\"):" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "head is 0\n", "tail is [1, 2, 3]\n" ] } ], "source": [ "head, *tail = range(4)\n", "print(\"head is\", head)\n", "print(\"tail is\", tail)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note the syntax with the \\*. The same pattern can be used, for example, to extract the middle segment of a sequence whose length we might not know:" ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [], "source": [ "one, *two, three = range(10)" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "one is 0\n", "two is [1, 2, 3, 4, 5, 6, 7, 8]\n", "three is 9\n" ] } ], "source": [ "print(\"one is\", one)\n", "print(\"two is\", two)\n", "print(\"three is\", three)" ] } ], "metadata": { "jekyll": { "display_name": "Types" }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "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.8" } }, "nbformat": 4, "nbformat_minor": 1 }