{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "\"Open\n", "\n", "| - | - | - |\n", "|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------|\n", "| [Exercise 1 (hello world)](<#Exercise-1-(hello-world)>) | [Exercise 2 (compliment)](<#Exercise-2-(compliment)>) | [Exercise 3 (multiplication)](<#Exercise-3-(multiplication)>) |\n", "| [Exercise 4 (multiplication table)](<#Exercise-4-(multiplication-table)>) | [Exercise 5 (two dice)](<#Exercise-5-(two-dice)>) | [Exercise 6 (triple square)](<#Exercise-6-(triple-square)>) |\n", "| [Exercise 7 (areas of shapes)](<#Exercise-7-(areas-of-shapes)>) | [Exercise 8 (solve quadratic)](<#Exercise-8-(solve-quadratic)>) | [Exercise 9 (merge)](<#Exercise-9-(merge)>) |\n", "| [Exercise 10 (detect ranges)](<#Exercise-10-(detect-ranges)>) | [Exercise 11 (interleave)](<#Exercise-11-(interleave)>) | [Exercise 12 (distinct characters)](<#Exercise-12-(distinct-characters)>) |\n", "| [Exercise 13 (reverse dictionary)](<#Exercise-13-(reverse-dictionary)>) | [Exercise 14 (find matching)](<#Exercise-14-(find-matching)>) | [Exercise 15 (two dice comprehension)](<#Exercise-15-(two-dice-comprehension)>) |\n", "| [Exercise 16 (transform)](<#Exercise-16-(transform)>) | [Exercise 17 (positive list)](<#Exercise-17-(positive-list)>) | [Exercise 18 (acronyms)](<#Exercise-18-(acronyms)>) |\n", "| [Exercise 19 (sum equation)](<#Exercise-19-(sum-equation)>) | [Exercise 20 (usemodule)](<#Exercise-20-(usemodule)>) | |\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "# Python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic concepts" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Basic input and output" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The traditional \"Hello, world\" program is very simple in Python. You can run the program by selecting the cell by mouse and pressing control-enter on keyboard. Try editing the string in the quotes and rerunning the program." ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello world2!\n" ] } ], "source": [ "print(\"Hello world2!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Multiple strings can be printed. By default, they are concatenated with a space:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, John! How are you?\n" ] } ], "source": [ "print(\"Hello,\", \"John!\", \"How are you?\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In the print function, numerical expression are first evaluated and then automatically converted to strings. Subsequently the strings are concatenated with spaces:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 plus 2 equals 3\n" ] } ], "source": [ "print(1, \"plus\", 2, \"equals\", 1+2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Reading textual input from the user can be achieved with the input function. The input function is given a string parameter, which is printed and prompts the user to give input. In the example below, the string entered by the user is stored the variable `name`. Try executing the program in the interactive notebook by pressing control-enter!" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Give me your name: Jarkko\n", "Hello, Jarkko\n" ] } ], "source": [ "name=input(\"Give me your name: \")\n", "print(\"Hello,\", name)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Indentation" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Repetition is possible with the for loop. Note that the body of for loop is indented with a tabulator or four spaces.\n", "Unlike in some other languages, braces are not needed to denote the body of the loop. When the indentation stops, the body of the loop ends." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello\n", "Hello\n", "Hello\n", "Bye!\n" ] } ], "source": [ "for i in range(3):\n", " print(\"Hello\")\n", "print(\"Bye!\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Indentation applies to other compound statements as well, such as bodies of functions, different branches of an if statement, and while loops. We shall see examples of these later." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `range(3)` expression above actually results with the sequence of integers 0, 1, and 2. So, the range is a half-open interval with the end point excluded from the range. In general, expression range(n) gives integers 0, 1, 2, ..., n-1. Modify the above program to make it also print the value of variable i at each iteration. Rerun the code with control-enter." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 1 (hello world)
\n", "Fill in the missing piece in the solution stub file `hello_world.py` in folder `src` to make it print the following:\n", "\n", "`Hello, world!`\n", "\n", "Make sure you use correct indenting. You can run it with command `python3 src/hello_world.py`.\n", "If the output looks good, then you can test it with command `tmc test`. If the tests pass,\n", "submit your solution to the server with command `tmc submit`.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 2 (compliment)
\n", "Fill in the stub solution to make the program work as follows. The program should ask the user for an input, and the print an answer as the examples below show.\n", "\n", "```\n", "What country are you from? Sweden\n", "I have heard that Sweden is a beautiful country.\n", "\n", "What country are you from? Chile \n", "I have heard that Chile is a beautiful country.\n", "```\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 3 (multiplication)
\n", "Make a program that gives the following output. You should use a for loop in your solution.\n", "\n", "```\n", "4 multiplied by 0 is 0\n", "4 multiplied by 1 is 4\n", "4 multiplied by 2 is 8\n", "4 multiplied by 3 is 12\n", "4 multiplied by 4 is 16\n", "4 multiplied by 5 is 20\n", "4 multiplied by 6 is 24\n", "4 multiplied by 7 is 28\n", "4 multiplied by 8 is 32\n", "4 multiplied by 9 is 36\n", "4 multiplied by 10 is 40\n", "```\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Variables and data types\n", "\n", "We saw already earlier that assigning a value to variable is very simple:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1\n" ] } ], "source": [ "a=1\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that we did not need to introduce the variable `a` in any way. No type was given for the variable. Python automatically detected that the type of `a` must be `int` (an integer). We can query the type of a variable with the builtin function `type`:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "int" ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "type(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note also that the type of a variable is not fixed:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "str" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "a=\"some text\"\n", "type(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Python the type of a variable is not attached to the name of the variable, like in C for instance, but instead with the actual value. This is called dynamic typing." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "![typing.svg](typing.svg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We say that a variable is a name that *refers* to a value or an object, and the assignment operator *binds* a variable name to a value." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The basic data types in Python are: `int`, `float`, `complex`, `str` (a string), `bool` (a boolean with values `True` and `False`), and `bytes`. Below are few examples of their use." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Result of the comparison: False\n", "Complex multiplication: (-4+0j)\n", "concatenation\n" ] } ], "source": [ "i=5\n", "f=1.5\n", "b = i==4\n", "print(\"Result of the comparison:\", b)\n", "c=0+2j # Note that j denotes the imaginary unit of complex numbers.\n", "print(\"Complex multiplication:\", c*c)\n", "s=\"conca\" + \"tenation\"\n", "print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The names of the types act as conversion operators between types:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-2\n", "2.0\n", "123\n", "True False\n", "234\n" ] } ], "source": [ "print(int(-2.8))\n", "print(float(2))\n", "print(int(\"123\"))\n", "print(bool(-2), bool(0)) # Zero is interpreted as False\n", "print(str(234))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A *byte* is a unit of information that can represent numbers between 0 and 255. A byte consists of 8 *bits*, which can in turn represent either 0 or 1. All the data that is stored on disks or transmitted across the internet are sequences of bytes. Normally we don't have to care about bytes, since our strings and other variables are automatically converted to a sequence of bytes when needed to. An example of the correspondence between the usual data types and bytes is the characters in a string. A single character is encoded as a sequence of one or more bytes. For example, in the common [UTF-8](https://en.wikipedia.org/wiki/UTF-8) encoding the character `c` corresponds to the byte with integer value 99 and the character `ä` corresponds to sequence of bytes [195, 164]. An example conversion between characters and bytes:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "b'\\xc3\\xa4'\n", "[195, 164]\n" ] } ], "source": [ "b=\"ä\".encode(\"utf-8\") # Convert character(s) to a sequence of bytes\n", "print(b) # Prints bytes in hexadecimal notation\n", "print(list(b)) # Prints bytes in decimal notation" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'ä'" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "bytes.decode(b, \"utf-8\") # convert sequence of bytes to character(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "During this course we don't have to care much about bytes, but in some cases, when loading data sets, we might have to specify the encoding if it deviates from the default one." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Creating strings\n", "A string is a sequence of characters commonly used to store input or output data in a program. The characters of a string are specified either between single (`'`) or double (`\"`) quotes. This optionality is useful if, for example, a string needs to contain a quotation mark:\n", "\"I don't want to go!\". You can also achieve this by *escaping* the quotation mark with the backslash: 'I don\\\\'t want to go'.\n", "\n", "The string can also contain other escape sequences like `\\n` for newline and `\\t` for a tabulator. See [literals](https://docs.python.org/3/reference/lexical_analysis.html#literals) for a list of all escape sequences." ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "One\tTwo\n", "Three\tFour\n" ] } ], "source": [ "print(\"One\\tTwo\\nThree\\tFour\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A string containing newlines can be easily given within triple double or triple single quotes:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [], "source": [ "s=\"\"\"A string\n", "spanning over\n", "several lines\"\"\"" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Although we can concatenate strings using the `+` operator, for effiency reasons, one should use the `join` method to concatenate larger number of strings:" ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "firstsecond\n", "first second second first\n" ] } ], "source": [ "a=\"first\"\n", "b=\"second\"\n", "print(a+b)\n", "print(\" \".join([a, b, b, a])) # More about the join method later\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes printing by concatenation from pieces can be clumsy:" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 plus 3 is equal to 4\n", "1 plus 3 is equal to 4\n" ] } ], "source": [ "print(str(1) + \" plus \" + str(3) + \" is equal to \" + str(4))\n", "# slightly better\n", "print(1, \"plus\", 3, \"is equal to\", 4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The multiple catenation and quotation characters break the flow of thought. *String interpolation* offers somewhat easier syntax.\n", "\n", "There are multiple ways to do sting interpolation:\n", "\n", "* Python format strings\n", "* the `format` method\n", "* f-strings\n", "\n", "Examples of these can be seen below:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2019-06-13T07:20:50.778447Z", "start_time": "2019-06-13T07:20:50.770086Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 plus 3 is equal to 4\n", "1 plus 3 is equal to 4\n", "1 plus 3 is equal to 4\n" ] } ], "source": [ "print(\"%i plus %i is equal to %i\" % (1, 3, 4)) # Format syntax\n", "\n", "print(\"{} plus {} is equal to {}\".format(1, 3, 4)) # Format method\n", "\n", "print(f\"{1} plus {3} is equal to {4}\") # f-string" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `i` format specifier in the format syntacs corresponds to integers and the specifier `f` corresponds to floats. When using f-strings or the `format` method, integers use `d` instead. In format strings specifiers can usually be omitted and are generally used only when specific formatting is required. For example in f-strings `f\"{4:3d}\"` would specify the number 4 left padded with spaces to 3 digits.\n", "\n", "It is often useful to specify the number of decimals when printing floats:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2019-06-13T07:20:11.299655Z", "start_time": "2019-06-13T07:20:11.290634Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.6 1.70 1.800\n", "1.6 1.70 1.800\n", "1.6 1.70 1.800\n" ] } ], "source": [ "print(\"%.1f %.2f %.3f\" % (1.6, 1.7, 1.8)) # Old style\n", "print(\"{:.1f} {:.2f} {:.3f}\".format(1.6, 1.7, 1.8)) # newer style\n", "print(f\"{1.6:.1f} {1.7:.2f} {1.8:.3f}\") # f-string" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The specifier `s` is used for strings. An example:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "ExecuteTime": { "end_time": "2019-06-13T07:22:04.651508Z", "start_time": "2019-06-13T07:22:04.646191Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "water concatenated with melon produces watermelon\n", "water concatenated with melon produces watermelon\n", "water concatenated with melon produces watermelon\n" ] } ], "source": [ "print(\"%s concatenated with %s produces %s\" % (\"water\", \"melon\", \"water\"+\"melon\"))\n", "print(\"{0} concatenated with {1} produces {0}{1}\".format(\"water\", \"melon\"))\n", "print(f\"{'water'} concatenated with {'melon'} produces {'water' + 'melon'}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Look [here](https://pyformat.info/#number) for more details about format specifiers, and for comparison between the old and new style of string interpolation.\n", "\n", "Different ways of string interpolation have different strengths and weaknesses. Generally choosing which to use is a matter of personal preference. On this course examples and model solutions will predominantly use f-strings and the `format` method." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Expressions\n", "An *expression* is a piece of Python code that results in a value. It consists of values combined together with *operators*. Values can be literals, such as `1`, `1.2`, `\"text\"`, or variables. Operators include arithmetics operators, comparison operators, function call, indexing, attribute references, among others. Below there are a few examples of expressions:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "1+2\n", "7/(2+0.1)\n", "a\n", "cos(0)\n", "mylist[1]\n", "c > 0 and c !=1\n", "(1,2,3)\n", "a<5\n", "obj.attr\n", "(-1)**2 == 1\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Note that in Python the operator `//` performs integer division and operator `/` performs float division. The `**` operator denotes exponentiation. These operators might therefore behave differently than in many other common languages.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As another example the following expression computes the kinetic energy of a non-rotating object:\n", "`0.5 * mass * velocity**2`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Statements\n", "Statements are commands that have some effect. For example, a function call (that is not part of another expression) is a statement. Also, the variable assignment is a statement:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "i = 5\n", "i = i+1 # This is a commong idiom to increment the value of i by one\n", "i += 1 # This is a short-hand for the above" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that in Python there are no operators `++` or `--` unlike in some other languages." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It turns out that the operators `+ - * / // % & | ^ >> << **` have the corresponding *augmented assignment operators* `+= -= *= /= //= %= &= |= ^= >>= <<= **=`" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another large set of statements is the flow-control statements such as if-else, for and while loops. We will look into these in the next sections." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Loops for repetitive tasks\n", "In Python we have two kinds of loops: `while` and `for`. We briefly saw the `for` loop earlier. Let's now look at the `while` loop. A `while` loop repeats a set of statements while a given condition holds. An example:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Square of 1 is 1\n", "Square of 2 is 4\n", "Square of 3 is 9\n", "Square of 4 is 16\n", "Square of 5 is 25\n", "Square of 6 is 36\n", "Square of 7 is 49\n", "Square of 8 is 64\n", "Square of 9 is 81\n", "Square of 10 is 100\n", "Square of 11 is 121\n", "Square of 12 is 144\n", "Square of 13 is 169\n", "Square of 14 is 196\n", "Square of 15 is 225\n", "Square of 16 is 256\n", "Square of 17 is 289\n", "Square of 18 is 324\n", "Square of 19 is 361\n", "Square of 20 is 400\n", "Square of 21 is 441\n", "Square of 22 is 484\n", "Square of 23 is 529\n", "Square of 24 is 576\n", "Square of 25 is 625\n", "Square of 26 is 676\n", "Square of 27 is 729\n", "Square of 28 is 784\n", "Square of 29 is 841\n", "Square of 30 is 900\n", "Square of 31 is 961\n", "Finished printing all the squares below 1000.\n" ] } ], "source": [ "i=1\n", "while i*i < 1000:\n", " print(\"Square of\", i, \"is\", i*i)\n", " i = i + 1\n", "print(\"Finished printing all the squares below 1000.\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note again that the body of the while statement was marked with the indentation." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another way of repeating statements is with the `for` statement. An example" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The sum is 45\n" ] } ], "source": [ "s=0\n", "for i in [0,1,2,3,4,5,6,7,8,9]:\n", " s = s + i\n", "print(\"The sum is\", s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `for` loop executes the statements in the block as many times as there are elements in the given list. At each iteration the variable `i` refers to another value from the list in order. Instead of the giving the list explicitly as above, we could have used the *generator* `range(10)` which returns values from the sequence 0,1,...,9 as the for loop asks for a new value. In the most general form the `for` loop goes through all the elements in an *iterable*.\n", "Besides lists and generators there are other iterables. We will talk about iterables and generators later this week." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When one wants to iterate through all the elements in an iterable, then the `for` loop is a natural choice. But sometimes `while` loops offer cleaner solution. For instance, if we want\n", "to go through all Fibonacci numbers up till a given limit, then it is easier to do with a `while` loop." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 4 (multiplication table)
\n", "\n", "In the `main` function print a multiplication table, which is shown below:\n", "```\n", " 1 2 3 4 5 6 7 8 9 10\n", " 2 4 6 8 10 12 14 16 18 20\n", " 3 6 9 12 15 18 21 24 27 30\n", " 4 8 12 16 20 24 28 32 36 40\n", " 5 10 15 20 25 30 35 40 45 50\n", " 6 12 18 24 30 36 42 48 54 60\n", " 7 14 21 28 35 42 49 56 63 70\n", " 8 16 24 32 40 48 56 64 72 80\n", " 9 18 27 36 45 54 63 72 81 90\n", " 10 20 30 40 50 60 70 80 90 100\n", "```\n", "For example at row 4 and column 9 we have 4*9=36.\n", "\n", "Use two nested for loops to achive this. Note that you can use the following form to stop the `print` function from automatically starting a new line:" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "textmore text\n" ] } ], "source": [ "print(\"text\", end=\"\")\n", "print(\"more text\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Print the numbers in a field with width four, so that the numbers are nicely aligned. For instructions on how adjust the field width refer to [pyformat.info](https://pyformat.info/#number_padding).\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Decision making with the if statement\n", "The if-else statement works as can be expected.\n", "Try running the below cell by pressing control+enter." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Give an integer: -1\n", "The absolute value of -1 is 1\n" ] } ], "source": [ "x=input(\"Give an integer: \")\n", "x=int(x)\n", "if x >= 0:\n", " a=x\n", "else:\n", " a=-x\n", "print(\"The absolute value of %i is %i\" % (x, a))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The general from of an if-else statement is\n", "\n", "```\n", "if condition1:\n", " statement1_1\n", " statement1_2\n", " ...\n", "elif condition2:\n", " statement2_1\n", " statement2_2\n", " ...\n", "...\n", "else:\n", " statementn_1\n", " statementn_2\n", " ...\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another example:" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Give a number: 3\n", "c is positive\n" ] } ], "source": [ "c=float(input(\"Give a number: \"))\n", "if c > 0:\n", " print(\"c is positive\")\n", "elif c<0:\n", " print(\"c is negative\")\n", "else:\n", " print(\"c is zero\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Breaking and continuing loop\n", "Breaking the loop, when the wanted element is found, with the `break` statement:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The first negative list element was -1\n" ] } ], "source": [ "l=[1,3,65,3,-1,56,-10]\n", "for x in l:\n", " if x < 0:\n", " break\n", "print(\"The first negative list element was\", x)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Stopping current iteration and continuing to the next one with the `continue` statement:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2019-06-17T13:56:49.327404Z", "start_time": "2019-06-17T13:56:49.318054Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Square root of 1 is 1.000\n", "Natural logarithm of 1 is 0.0000\n", "Square root of 3 is 1.732\n", "Natural logarithm of 3 is 1.0986\n", "Square root of 65 is 8.062\n", "Natural logarithm of 65 is 4.1744\n", "Square root of 3 is 1.732\n", "Natural logarithm of 3 is 1.0986\n", "Square root of 56 is 7.483\n", "Natural logarithm of 56 is 4.0254\n" ] } ], "source": [ "from math import sqrt, log\n", "l=[1,3,65,3,-1,56,-10]\n", "for x in l:\n", " if x < 0:\n", " continue\n", " print(f\"Square root of {x} is {sqrt(x):.3f}\")\n", " print(f\"Natural logarithm of {x} is {log(x):.4f}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 5 (two dice)
\n", "\n", "Let us consider throwing two dice. (A dice can give a value between 1 and 6.) Use two nested `for`\n", "loops in the `main` function to iterate through all possible combinations the pair of dice can give. \n", "There are 36 possible combinations. Print all those combinations as (ordered) pairs that sum to 5. \n", "For example, your printout should include the pair `(2,3)`. Print one pair per line.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Functions\n", "A function is defined with the `def` statement. Let's do a doubling function." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8 2.4 abcabc\n" ] } ], "source": [ "def double(x):\n", " \"This function multiplies its argument by two.\"\n", " return x*2\n", "print(double(4), double(1.2), double(\"abc\")) # It even happens to work for strings!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The double function takes only one parameter. Notice the *docstring* on the second line. It documents the purpose and usage of the function. Let's try to access it." ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The docstring is: This function multiplies its argument by two.\n", "Help on function double in module __main__:\n", "\n", "double(x)\n", " This function multiplies its argument by two.\n", "\n" ] } ], "source": [ "print(\"The docstring is:\", double.__doc__)\n", "help(double) # Another way to access the docstring" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Most of Python's builtin functions, classes, and modules should contain a docstring." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on built-in function print in module builtins:\n", "\n", "print(...)\n", " print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)\n", " \n", " Prints the values to a stream, or to sys.stdout by default.\n", " Optional keyword arguments:\n", " file: a file-like object (stream); defaults to the current sys.stdout.\n", " sep: string inserted between values, default a space.\n", " end: string appended after the last value, default a newline.\n", " flush: whether to forcibly flush the stream.\n", "\n" ] } ], "source": [ "help(print)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's another example function:" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "25\n" ] } ], "source": [ "def sum_of_squares(a, b):\n", " \"Computes the sum of arguments squared\"\n", " return a**2 + b**2\n", "print(sum_of_squares(3, 4))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Note the terminology: in the function definition the names a and b are called parameters of the function; in the function call, however, 3 and 4 are called arguments to the function.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It would be nice that the number of arguments could be arbitrary, not just two. We could pass a list to the function as a parameter." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4\n", "45\n" ] } ], "source": [ "def sum_of_squares(lst):\n", " \"Computes the sum of squares of elements in the list given as parameter\"\n", " s=0\n", " for x in lst:\n", " s += x**2\n", " return s\n", "print(sum_of_squares([-2]))\n", "print(sum_of_squares([-2,4,5]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This works perfectly! There is however some extra typing with the brackets around the lists. Let's see if we can do better:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "4\n", "45\n" ] } ], "source": [ "def sum_of_squares(*t):\n", " \"Computes the sum of squares of arbitrary number of arguments\"\n", " s=0\n", " for x in t:\n", " s += x**2\n", " return s\n", "print(sum_of_squares(-2))\n", "print(sum_of_squares(-2,4,5))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The strange looking argument notation (the star) is called *argument packing*. It packs all the given positional arguments into a tuple `t`. We will encounter tuples again later, but it suffices now to say that tuples are *immutable* lists. With the `for` loop we can iterate through all the elements in the tuple.\n", "\n", "Conversely, there is also syntax for *argument unpacking*. It has confusingly exactly same notation as argument packing (star), but they are separated by the location where used. Packing happens in the parameter list of the functions definition, and unpacking happens where the function is called:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "With list unpacked as arguments to the functions: 90\n" ] } ], "source": [ "lst=[1,5,8]\n", "print(\"With list unpacked as arguments to the functions:\", sum_of_squares(*lst))\n", "# print(sum_of_squares(lst)) # Does not work correctly" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The second call failed because the function tried to raise the list of numbers to the second power. Inside the function body we have `t=([1,5,8])`, where the parentheses denote a tuple with one element, a list." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In addition to positional arguments we have seen so far, a function call can also have *named arguments*. An example will explain this concept best:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "First: 5 Second: 8 Third: 7\n" ] } ], "source": [ "def named(a, b, c):\n", " print(\"First:\", a, \"Second:\", b, \"Third:\", c)\n", "named(5, c=7, b=8)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the named arguments didn't need to be in the same order as in the function definition.\n", "The named arguments must come after the positional arguments. For example, the following function call is illegal `named(a=5, 7, 8)`.\n", "\n", "One can also specify an optional parameter by giving the parameter a default value. The parameters that have default values must come after those parameters that don't. We saw that the parameters of the `print` function were of form `print(value, ..., sep=' ', end='\\n', file=sys.stdout, flush=False)`. There were four parameters with default values. If some default values don't suit us, we can give them in the function call using the name of the parameter:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 -*- 2 -*- 3 |first -*- second -*- third |" ] } ], "source": [ "print(1, 2, 3, end=' |', sep=' -*- ')\n", "print(\"first\", \"second\", \"third\", end=' |', sep=' -*- ')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We did not need to specify all the parameters with default values, only those we wanted to change.\n", "\n", "Let's go through another example of using parameters with default values:" ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5.0\n", "4.497941445275415\n" ] } ], "source": [ "def length(*t, degree=2):\n", " \"\"\"Computes the length of the vector given as parameter. By default, it computes\n", " the Euclidean distance (degree==2)\"\"\"\n", " s=0\n", " for x in t:\n", " s += abs(x)**degree\n", " return s**(1/degree)\n", "print(length(-4,3))\n", "print(length(-4,3, degree=3))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the default parameter this is the Euclidean distance, and if $p\\ne 2$ it is called [p-norm](https://en.wikipedia.org/wiki/P-norm)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We saw that it was possible to use packing and unpacking of arguments with the * notation, when one wants to specify arbitrary number of *positional arguments*. This is also possible for arbitrary number of named arguments with the `**` notation. We will talk about this more in the data structures section." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Visibility of variables\n", "Function definition creates a new *namespace* (also called local scope). Variables created inside this scope are not available from outside the function definition. Also, the function parameters are only visible inside the function definition. Variables that are not defined inside any function are called `global variables`.\n", "\n", "Global variable are readable also in local scopes, but an assignment creates a new local variable without rebinding the global variable. If we are inside a function, a local variable hides a global variable by the same name:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n", "2\n" ] } ], "source": [ "i=2 # global variable\n", "def f():\n", " i=3 # this creates a new variable, it does not rebind the global i\n", " print(i) # This will print 3 \n", "f()\n", "print(i) # This will print 2" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you really need to rebind a global variable from a function, use the `global` statement. Example:" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n", "5\n" ] } ], "source": [ "i=2\n", "def f():\n", " global i\n", " i=5 # rebind the global i variable\n", " print(i) # This will print 5\n", "f()\n", "print(i) # This will print 5" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Unlike languages like C or C++, Python allows defining a function inside another function. This *nested* function will have nested scope:" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "3\n", "2\n" ] } ], "source": [ "def f(): # outer function\n", " b=2\n", " def g(): # inner function\n", " #nonlocal b # Without this nonlocal statement,\n", " b=3 # this will create a new local variable\n", " print(b)\n", " g()\n", " print(b)\n", "f()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Try first running the above cell and see the result. Then uncomment the nonlocal stamement and run the cell again. The `global` and `nonlocal` statements are similar. The first will force a variable refer to a global variable, and the second will force a variable to refer to the variable in the nearest outer scope (but not the global scope)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 6 (triple square)
\n", "\n", "Write two functions: `triple` and `square`. Function `triple` multiplies its parameter by three. Function `square` raises its parameter to the power of two. For example, we have equalities `triple(5)==15`\n", "and `square(5)==25`.\n", "\n", "Part 1.\n", "\n", "In the `main` function write a `for` loop that iterates through values 1 to 10, and for each value prints its triple and its square. The output should be as follows:\n", "```\n", "triple(1)==3 square(1)==1\n", "triple(2)==6 square(2)==4\n", "...\n", "```\n", "\n", "Part 2.\n", "\n", "Now modify this `for` loop so that it stops iteration when the square of a value is larger than the\n", "triple of the value, without printing anything in the last iteration.\n", "\n", "Note that the test cases check that both functions `triple` and `square` are called exactly once per iteration.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 7 (areas of shapes)
\n", "\n", "Create a program that can compute the areas of three shapes, triangles, rectangles and circles, when\n", "their dimensions are given.\n", "\n", "An endless loop should ask for which shape you want the area be calculated. An empty string as input will exit the loop. \n", "If the user gives a\n", "string that is none of the given shapes, the message “unknown shape!” should be printed.\n", "Then it will ask for dimensions for that particular shape. When all the necessary dimensions are\n", "given, it prints the area, and starts the loop all over again. Use format specifier `f` for the area.\n", "\n", "What happens if you give incorrect dimensions, like giving string \"aa\" as radius? You don't have to check for errors in the input.\n", "\n", "Example interaction:\n", "```\n", "Choose a shape (triangle, rectangle, circle): triangle\n", "Give base of the triangle: 20\n", "Give height of the triangle: 5\n", "The area is 50.000000\n", "Choose a shape (triangle, rectangle, circle): rectangel\n", "Unknown shape!\n", "Choose a shape (triangle, rectangle, circle): rectangle\n", "Give width of the rectangle: 20\n", "Give height of the rectangle: 4\n", "The area is 80.000000\n", "Choose a shape (triangle, rectangle, circle): circle\n", "Give radius of the circle: 10\n", "The area is 314.159265\n", "Choose a shape (triangle, rectangle, circle): \n", "```\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Data structures\n", "The main data structures in Python are strings, lists, tuples, dictionaries, and sets. We saw some examples of lists, when we discussed `for` loops. And we saw briefly tuples when we introduced argument packing and unpacking. Let's get into more details now.\n", "\n", "#### Sequences\n", "A *list* contains arbitrary number of elements (even zero) that are stored in sequential order. The elements are separated by commas and written between brackets. The elements don't need to be of the same type. An example of a list with four values:" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "[2, 100, 'hello', 1.0]" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[2, 100, \"hello\", 1.0]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A *tuple* is fixed length, immutable, and ordered container. Elements of tuple are separated by commas and written between parentheses. Examples of tuples:" ] }, { "cell_type": "code", "execution_count": 43, "metadata": {}, "outputs": [], "source": [ "(3,) # a singleton\n", "(1,3) # a pair\n", "(1, \"hello\", 1.0); # a triple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Note the difference between `(3)` and `(3,)`. Because the parentheses can also be used to group expressions, the first one defines an integer, but the second one defines a tuple with single element.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As we can see, both lists and tuples can contain values of different type.\n", "\n", "List, tuples, and strings are called *sequences* in Python, and they have several commonalities:\n", "\n", "* their length can be queried with the `len` function\n", "* `min` and `max` function find the minimum and maximum element of a sequence, and `sum` adds all the elements of numbers together\n", "* Sequences can be concatenated with the `+` operator, and repeated with the `*` operator: `\"hi\"*3==\"hihihi\"`\n", "* Since sequences are ordered, we can refer to the elements of a sequences by integers using the *indexing* notation: `\"abcd\"[2] == \"c\"`\n", "* Note that the indexing begins from 0\n", "* Negative integers start indexing from the end: -1 refers to the last element, -2 refers to the second last, and so on" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Above we saw that we can access a single element of a sequence using *indexing*. If we want a subsequence of a sequence, we can use the *slicing* syntax. A slice consists of elements of the original sequence, and it is itself a sequence as well. A simple slice is a range of elements:" ] }, { "cell_type": "code", "execution_count": 44, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'bcd'" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "s=\"abcdefg\"\n", "s[1:4]" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that Python ranges exclude the last index. The generic form of a slice is\n", "`sequence[first:last:step]`. If any of the three parameters are left out, they are set to default values as follows: first=0, last=len(L), step=1. So, for instance \"abcde\"[1:]==\"bcde\". The step parameter selects elements that are step distance apart from each other. For example:" ] }, { "cell_type": "code", "execution_count": 45, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 3, 6, 9]\n" ] } ], "source": [ "print([0,1,2,3,4,5,6,7,8,9][::3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 8 (solve quadratic)
\n", "\n", "In mathematics, the quadratic equation $ax^2+bx+c=0$ can be solved with the formula \n", "$x=\\frac{-b\\pm \\sqrt{b^2 -4ac}}{2a}$. \n", "\n", "Write a function `solve_quadratic`, that returns both solutions of a generic quadratic as a pair (2-tuple)\n", "when the coefficients are given as parameters. It should work like this:\n", "```python\n", "print(solve_quadratic(1,-3,2))\n", "(2.0,1.0)\n", "print(solve_quadratic(1,2,1))\n", "(-1.0,-1.0)\n", "```\n", "\n", "You may want to use the `math.sqrt` function from the `math` module in your solution. Test that your function works in the main function!\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Modifying lists\n", "We can assign values to elements of a list by indexing or by slicing. An example:" ] }, { "cell_type": "code", "execution_count": 46, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[11, 13, 10, 32]\n" ] } ], "source": [ "L=[11,13,22,32]\n", "L[2]=10 # Changes the third element\n", "print(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Or we can assign a list to a slice:" ] }, { "cell_type": "code", "execution_count": 47, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[11, 4, 32]\n" ] } ], "source": [ "L[1:3]=[4]\n", "print(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also modify a list by using *mutating methods* of the `list` class, namely the methods `append`, `extend`, `insert`, `remove`, `pop`, `reverse`, and `sort`. Try Python's help functionality to find more about these methods: e.g. `help(list.extend)` or `help(list)`.\n", "\n", "
Note that we cannot perform these modifications on tuples or strings since they are *immutable*
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Generating numerical sequences\n", "Trivial lists can be tedious to write: `[0,1,2,3,4,5,6]`. The function `range` creates numeric ranges automatically. The above sequence can be generated with the function call `range(7)`. Note again that then end value is not included in the sequence. An example of using the `range` function:" ] }, { "cell_type": "code", "execution_count": 48, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "range(0, 3)\n" ] } ], "source": [ "L=range(3)\n", "for i in L:\n", " print(i)\n", "# Note that L is not a list!\n", "print(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "So `L` is not a list, but it is a sequence. We can for instace access its last element with `L[-1]`. If really needed, then it can be converted to a list with the `list` constructor:" ] }, { "cell_type": "code", "execution_count": 49, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n" ] } ], "source": [ "L=range(10)\n", "print(list(L))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Note that using a range consumes less memory than the corresponding list. This is because in a list all the elements are stored in the memory, whereas the range generates the requested elements only when needed. For example, when the for loop asks for the next element from the range at each iteration, only a single element from the range exists in memory at the same time. This makes a big difference when using large ranges, like range(1000000).
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `range` function works in similar fashion as slices. So, for instance the step of the sequence can be given:" ] }, { "cell_type": "code", "execution_count": 50, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 2, 4, 6]\n" ] } ], "source": [ "print(list(range(0, 7, 2)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Sorting sequences\n", "\n", "In Python there are two ways to sort sequences. The `sort` *method* modifies the original list, whereas the `sorted` *function* returns a new sorted list and leaves the original intact. A couple of examples will demonstrate this:" ] }, { "cell_type": "code", "execution_count": 51, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 3, 5, 7]\n", "[1, 3, 6, 6, 7]\n", "[6, 1, 7, 3, 6]\n" ] } ], "source": [ "L=[5,3,7,1]\n", "L.sort() # here we call the sort method of the object L\n", "print(L)\n", "L2=[6,1,7,3,6]\n", "print(sorted(L2))\n", "print(L2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The parameter `reverse=True` can be given (both to `sort` and `sorted`) to get descending order of elements:" ] }, { "cell_type": "code", "execution_count": 52, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[7, 5, 3, 1]\n" ] } ], "source": [ "L=[5,3,7,1]\n", "print(sorted(L, reverse=True))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 9 (merge)
\n", "\n", "Suppose we have two lists `L1` and `L2` that contain integers which are sorted in ascending order.\n", "Create a function `merge` that gets these lists as parameters and returns a new sorted list `L` that has\n", "all the elements of `L1` and `L2`. So, `len(L)` should equal to `len(L1)+len(L2)`. Do this using the\n", "fact that both lists are already sorted. You can’t use the `sorted` function or the `sort` method in implementing the `merge` method. You can however use these functions in the main function for creating inputs to the `merge` function.\n", "Test with a couple of examples in the `main` function that your solution works correctly.\n", "\n", "Note: In Python argument lists are passed by reference to the function, they are not copied! Make sure you don't modify the original lists of the caller.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 10 (detect ranges)
\n", "\n", "Create a function named `detect_ranges` that gets a list of integers as a parameter. The function\n", "should then sort this list, and transform the list into another list where pairs are used for all the\n", "detected intervals. So `3,4,5,6` is replaced by the pair `(3,7)`. Numbers that are not part of any\n", "interval result just single numbers. The resulting list consists of these numbers and\n", "pairs, separated by commas.\n", "An example of how this function works:\n", "```python\n", "print(detect_ranges([2,5,4,8,12,6,7,10,13]))\n", "[2,(4,9),10,(12,14)]\n", "```\n", "\n", "Note that the second element of the pair does not belong to the range. This is consistent with the way Python's `range` function works. You may assume that no element in the input list appears multiple times.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Zipping sequences\n", "\n", "The `zip` function combines two (or more) sequences into one sequence. If, for example, two sequences are zipped together, the resulting sequence contains pairs. In general, if `n` sequences are zipped together, the elements of the resulting sequence contains `n`-tuples. An example of this:" ] }, { "cell_type": "code", "execution_count": 53, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n", "[(1, 'first'), (2, 'second'), (3, 'third')]\n" ] } ], "source": [ "L1=[1,2,3]\n", "L2=[\"first\", \"second\", \"third\"]\n", "print(zip(L1, L2)) # Note that zip does not return a list, like range\n", "print(list(zip(L1, L2))) # Convert to a list" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Here's another example of using the `zip` function." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2019-06-13T08:16:20.888496Z", "start_time": "2019-06-13T08:16:20.878238Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "On Monday it was rainy and the temperature was 10 degrees celsius.\n", "On Tuesday it was rainy and the temperature was 12 degrees celsius.\n", "On Wednesday it was sunny and the temperature was 12 degrees celsius.\n", "On Thursday it was cloudy and the temperature was 9 degrees celsius.\n", "On Friday it was rainy and the temperature was 9 degrees celsius.\n", "On Saturday it was sunny and the temperature was 11 degrees celsius.\n", "On Sunday it was sunny and the temperature was 11 degrees celsius.\n" ] } ], "source": [ "days=\"Monday Tuesday Wednesday Thursday Friday Saturday Sunday\".split()\n", "weathers=\"rainy rainy sunny cloudy rainy sunny sunny\".split()\n", "temperatures=[10,12,12,9,9,11,11]\n", "for day, weather, temperature in zip(days,weathers,temperatures):\n", " print(f\"On {day} it was {weather} and the temperature was {temperature} degrees celsius.\")\n", "\n", "# Or equivalently:\n", "#for t in zip(days,weathers,temperatures):\n", "# print(\"On {} it was {} and the temperature was {} degrees celsius.\".format(*t))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If the sequences are not of equal length, then the resulting sequence will be as long as the shortest input sequence is." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 11 (interleave)
\n", "\n", "Write function `interleave` that gets arbitrary number of lists as parameters. You may assume that all the lists have equal length. The function should return one list containing all the elements from the input lists interleaved.\n", "Test your function from the `main` function of the program.\n", "\n", "Example:\n", "`interleave([1,2,3], [20,30,40], ['a', 'b', 'c'])`\n", "should return\n", "`[1, 20, 'a', 2, 30, 'b', 3, 40, 'c']`.\n", "Use the `zip` function to implement `interleave`. Remember the `extend` method of list objects.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Enumerating sequences\n", "\n", "In some other programming languages one iterates through the elements using their indices (0,1, ...) in the sequence. In Python we normally don't need to think about indices when iterating, because the `for` loop allows simpler iteration through the elements. But sometimes you really need to know the index of the current element in the sequence. In this case one uses Python's `enumerate` function. In the next example we would like find the second occurrence of integer 5 in a list." ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "7\n" ] } ], "source": [ "L=[1,2,98,5,-1,2,0,5,10]\n", "counter = 0\n", "for i, x in enumerate(L):\n", " if x == 5:\n", " counter += 1\n", " if counter == 2:\n", " break\n", "print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `enumerate(L)` function call can be thought to be equivalent to `zip(range(len(L)), L)`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Dictionaries\n", "A *dictionary* is a dynamic, unordered container. Instead of using integers to access the elements of the container, the dictionary uses *keys* to access the stored *values*. The dictionary can be created by listing the comma separated key-value pairs in braces. Keys and values are separated by a colon. A tuple (key,value) is called an *item* of the dictionary.\n", "\n", "Let's demonstrate the dictionary creation and usage:" ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "value1\n", "value2\n" ] } ], "source": [ "d={\"key1\":\"value1\", \"key2\":\"value2\"}\n", "print(d[\"key1\"])\n", "print(d[\"key2\"])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Keys can have different types even in the same container. So the following code is legal:\n", "`d={1:\"a\", \"z\":1}`. The only restriction is that the keys must be *hashable*. That is, there has to be a mapping from keys to integers. Lists are *not* hashable, but tuples are!\n", "\n", "There are alternative syntaxes for dictionary creation:" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [], "source": [ "dict([(\"key1\", \"value1\"), (\"key2\", \"value2\"), (\"key3\", \"value3\")]) # list of items\n", "dict(key1=\"value1\", key2=\"value2\", key3=\"value3\");" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If a key is not found in a dictionary, the indexing `d[key]` results in an error (*exception* `KeyError`). But an assignment with a non-existing key causes the key to be added in the dictionary associated with the corresponding value:" ] }, { "cell_type": "code", "execution_count": 58, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{2: 'value'}\n" ] } ], "source": [ "d={}\n", "d[2]=\"value\"\n", "print(d)" ] }, { "cell_type": "code", "execution_count": 59, "metadata": {}, "outputs": [], "source": [ "# d[1] # This would cause an error" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Dictionary object contains several non-mutating methods:\n", "```\n", "d.copy()\n", "d.items()\n", "d.keys()\n", "d.values()\n", "d.get(k[,x])\n", "```\n", "\n", "Some methods mutate the dictionary:\n", "```\n", "d.clear()\n", "d.update(d1)\n", "d.setdefault(k[,x])\n", "d.pop(k[,x])\n", "d.popitem()\n", "```\n", "\n", "Try out some of these in the below cell. You can find more info with `help(dict)` or `help(dict.keys)`." ] }, { "cell_type": "code", "execution_count": 60, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "dict_values([1, 2, 3, 4, 5])" ] }, "execution_count": 60, "metadata": {}, "output_type": "execute_result" } ], "source": [ "d=dict(a=1, b=2, c=3, d=4, e=5)\n", "d.values()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Sets\n", "Set is a dynamic, unordered container. It works a bit like dictionary, but only the keys are stored. And each key can be stored only once. The set requires that the keys to be stored are hashable. Below are a few ways of creating a set:" ] }, { "cell_type": "code", "execution_count": 61, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{1}\n", "{1, 2, 'a'}\n", "set()\n", "{7}\n" ] } ], "source": [ "s={1,1,1}\n", "print(s)\n", "s=set([1,2,2,'a'])\n", "print(s)\n", "s=set() # empty set\n", "print(s)\n", "s.add(7) # add one element\n", "print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A more useful example:" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2019-06-13T08:21:16.770094Z", "start_time": "2019-06-13T08:21:16.765594Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "There are 4 distinct characters in mississippi\n" ] } ], "source": [ "s=\"mississippi\"\n", "print(f\"There are {len(set(s))} distinct characters in {s}\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `set` provides the following non-mutating methods:" ] }, { "cell_type": "code", "execution_count": 63, "metadata": {}, "outputs": [], "source": [ "s=set()\n", "s1=set()\n", "s.copy()\n", "s.issubset(s1)\n", "s.issuperset(s1)\n", "s.union(s1)\n", "s.intersection(s1)\n", "s.difference(s1)\n", "s.symmetric_difference(s1);" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The last four operation can be tedious to write to create a more complicated expression. The alternative is to use the corresponding operator forms: `|`, `&`, `-`, and `^`. An example of these:" ] }, { "cell_type": "code", "execution_count": 64, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Union: {1, 2, 7, 8, 9}\n", "Intersection: {2}\n", "Difference: {1, 7}\n", "Symmetric difference {1, 7, 8, 9}\n" ] } ], "source": [ "s=set([1,2,7])\n", "t=set([2,8,9])\n", "print(\"Union:\", s|t)\n", "print(\"Intersection:\", s&t)\n", "print(\"Difference:\", s-t)\n", "print(\"Symmetric difference\", s^t)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are also the following mutating methods:\n", "```\n", "s.add(x)\n", "s.clear()\n", "s.discard()\n", "s.pop()\n", "s.remove(x)\n", "```\n", "\n", "And the set operators `|`, `&`, `-`, and `^` have the corresponding mutating, augmented assignment forms: `|=`, `&=`, `-=`, and `^=`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 12 (distinct characters)
\n", "\n", "Write function `distinct_characters` that gets a list of strings as a parameter. It should return a dictionary whose keys are the strings of the input list and the corresponding values are the numbers of distinct characters in the key.\n", "\n", "Use the `set` container to temporarily store the distinct characters in a string.\n", "Example of usage:\n", "`distinct_characters([\"check\", \"look\", \"try\", \"pop\"])`\n", "should return\n", "`{ \"check\" : 4, \"look\" : 3, \"try\" : 3, \"pop\" : 2}`.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Miscellaneous stuff\n", "\n", "To find out whether a container includes an element, the `in` operator can be used. The operator returns a truth value. Some examples of the usage:" ] }, { "cell_type": "code", "execution_count": 65, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "True\n", "False\n", "True\n" ] } ], "source": [ "print(1 in [1,2])\n", "d=dict(a=1, b=3)\n", "print(\"b\" in d)\n", "s=set()\n", "print(1 in s)\n", "print(\"x\" in \"text\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As a special case, for strings the `in` operator can be used to check whether a string is part of another string:" ] }, { "cell_type": "code", "execution_count": 66, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n" ] } ], "source": [ "print(\"issi\" in \"mississippi\")\n", "print(\"issp\" in \"mississippi\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Elements of a container can be unpacked into variables:" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2019-06-13T08:37:47.009974Z", "start_time": "2019-06-13T08:37:47.001871Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "e\n", "a b\n" ] } ], "source": [ "first, second = [4,5]\n", "a,b,c = \"bye\"\n", "print(c)\n", "d=dict(a=1, b=3)\n", "key1, key2 = d\n", "print(key1, key2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In membership testing and unpacking only the keys of a dictionary are used, unless either values or items (like below) are explicitly asked." ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2019-06-13T08:37:48.885038Z", "start_time": "2019-06-13T08:37:48.880368Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "For key 'a' value 1 was stored\n", "For key 'b' value 3 was stored\n" ] } ], "source": [ "for key, value in d.items():\n", " print(f\"For key '{key}' value {value} was stored\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To remove the binding of a variable, use the `del` statement. For example:" ] }, { "cell_type": "code", "execution_count": 69, "metadata": {}, "outputs": [], "source": [ "s=\"hello\"\n", "del s\n", "# print(s) # This would cause an error" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To delete an item from a container, the `del` statement can again be applied:" ] }, { "cell_type": "code", "execution_count": 70, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[13, 40, 100]\n" ] } ], "source": [ "L=[13,23,40,100]\n", "del L[1]\n", "print(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In similar fashion `del` can be used to delete a slice. Later we will see that `del` can delete attributes from an object." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 13 (reverse dictionary)
\n", "\n", "Let `d` be a dictionary that has English words as keys and a list of Finnish words as values. So, the\n", "dictionary can be used to find out the Finnish equivalents of an English word in the following way:\n", "\n", "```\n", "d[\"move\"]\n", "[\"liikuttaa\"]\n", "d[\"hide\"]\n", "[\"piilottaa\", \"salata\"]\n", "```\n", "\n", "Make a function `reverse_dictionary` that creates a Finnish to English dictionary based on a English to Finnish dictionary given as a parameter. The values of the created dictionary should be lists of words. It should work like this:\n", "```\n", "d={'move': ['liikuttaa'], 'hide': ['piilottaa', 'salata'], 'six': ['kuusi'], 'fir': ['kuusi']}\n", "reverse_dictionary(d)\n", "{'liikuttaa': ['move'], 'piilottaa': ['hide'], 'salata': ['hide'], 'kuusi': ['six', 'fir']}\n", "```\n", "\n", "Be careful with synonyms and homonyms!\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 14 (find matching)
\n", "\n", "Write function `find_matching` that gets a list of strings and a search string as parameters. The function should return the indices to those elements in the input list that contain the search string. Use the function `enumerate`.\n", "\n", "An example:\n", "`find_matching([\"sensitive\", \"engine\", \"rubbish\", \"comment\"], \"en\")`\n", "should return the list\n", "`[0, 1, 3]`.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Compact way of creating data structures\n", "We can now easily create complicated data structures using `for` loops:" ] }, { "cell_type": "code", "execution_count": 71, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\n" ] } ], "source": [ "L=[]\n", "for i in range(10):\n", " L.append(i**2)\n", "print(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because this kind of pattern is often used, Python offers a short-hand for this. A *list comprehension* is an expression that allows creating complicated lists on one line. The notation is familiar from mathematics:" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "$\\{a^3 : a \\in \\{1,2, \\ldots, 10\\}\\}$" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The same written in Python as a list comprehension:" ] }, { "cell_type": "code", "execution_count": 72, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 8, 27, 64, 125, 216, 343, 512, 729, 1000]\n" ] } ], "source": [ "L=[ a**3 for a in range(1,11)]\n", "print(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The generic form of a list comprehension is:\n", "`[ expression for element in iterable lc-clauses ]`.\n", "Let's break this syntax into pieces. The iterable can be any sequence (or something more general). The lc-clauses consists of zero or more of the following clauses:\n", "\n", "* for elem in iterable\n", "* if expression\n", "\n", "A more complicated example. How would you describe these numbers?" ] }, { "cell_type": "code", "execution_count": 73, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 12, 13, 14, 15, 16, 17, 18, 19, 22, 23, 24, 25, 26, 27, 28, 29, 33, 34, 35, 36, 37, 38, 39, 44, 45, 46, 47, 48, 49, 55, 56, 57, 58, 59, 66, 67, 68, 69, 77, 78, 79, 88, 89, 99, 111, 112, 113, 114, 115, 116, 117, 118, 119, 122, 123, 124, 125, 126, 127, 128, 129, 133, 134, 135, 136, 137, 138, 139, 144, 145, 146, 147, 148, 149, 155, 156, 157, 158, 159, 166, 167, 168, 169, 177, 178, 179, 188, 189, 199, 222, 223, 224, 225, 226, 227, 228, 229, 233, 234, 235, 236, 237, 238, 239, 244, 245, 246, 247, 248, 249, 255, 256, 257, 258, 259, 266, 267, 268, 269, 277, 278, 279, 288, 289, 299, 333, 334, 335, 336, 337, 338, 339, 344, 345, 346, 347, 348, 349, 355, 356, 357, 358, 359, 366, 367, 368, 369, 377, 378, 379, 388, 389, 399, 444, 445, 446, 447, 448, 449, 455, 456, 457, 458, 459, 466, 467, 468, 469, 477, 478, 479, 488, 489, 499, 555, 556, 557, 558, 559, 566, 567, 568, 569, 577, 578, 579, 588, 589, 599, 666, 667, 668, 669, 677, 678, 679, 688, 689, 699, 777, 778, 779, 788, 789, 799, 888, 889, 899, 999]\n" ] } ], "source": [ "L=[ 100*a + 10*b +c for a in range(0,10)\n", " for b in range(0,10)\n", " for c in range(0,10) \n", " if a <= b <= c]\n", "print(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If one needs only to iterate through the list once, it is more memory efficient to use a *generator expression* instead. The only thing that changes syntactically is that the surrounding brackets are replaced by parentheses:" ] }, { "cell_type": "code", "execution_count": 74, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "60885\n", "0\n" ] } ], "source": [ "G = ( 100*a + 10*b + c for a in range(0,10)\n", " for b in range(0,10)\n", " for c in range(0,10) \n", " if a <= b <= c )\n", "print(sum(G)) # This iterates through all the elements from the generator\n", "print(sum(G)) # It doesn't restart from the beginning, so all elements are already consumed" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Note above that one can only iterate through the generator once.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Similary a *dictionary comprehension* creates a dictionary:" ] }, { "cell_type": "code", "execution_count": 75, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25, 6: 36, 7: 49, 8: 64, 9: 81}\n" ] } ], "source": [ "d={ k : k**2 for k in range(10)}\n", "print(d)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "And a *set comprehension* creates a set:" ] }, { "cell_type": "code", "execution_count": 76, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 15, 16, 18, 20, 21, 24, 25, 27, 28, 30, 32, 35, 36, 40, 42, 45, 48, 49, 54, 56, 63, 64, 72, 81}\n" ] } ], "source": [ "s={ i*j for i in range(10) for j in range(10)}\n", "print(s)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 15 (two dice comprehension)
\n", "\n", "Redo the earlier exercise which printed all the pairs of two dice results that sum to 5. But this time use a list comprehension. Print one pair per line.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Processing sequences\n", "In this section we will go through some useful tools, that are maybe familiar to you from some functional programming language like *lisp* or *haskell*. These functions rely on functions being first-class objects in Python, that is, you can\n", "\n", "* pass a function as a parameter to another function\n", "* return a function as a return value from some function\n", "* store a function in a data structure or a variable\n", "\n", "We will talk about `map`, `filter`, and `reduce` functions. We will also cover how to create functions with no name using the *lambda* expressions." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Map and lambda functions\n", "The `map` function gets a list and a function as parameters, and it returns a new list whose\n", "elements are elements of the original list transformed by the parameter function. For this to work the parameter function must take exactly one value in and return a value out. An example will clarify this concept:" ] }, { "cell_type": "code", "execution_count": 77, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "\n" ] } ], "source": [ "def double(x):\n", " return 2*x\n", "L=[12,4,-1]\n", "print(map(double, L))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The map function returns a map object for efficiency reasons. However, since we only want print the contents, we first convert it to a list and then print it:" ] }, { "cell_type": "code", "execution_count": 78, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[24, 8, -2]\n" ] } ], "source": [ "print(list(map(double,L)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "When one reads numeric data from a file or from the internet, the numbers are usually in string form. Before they can be used in computations, they must first be converted to ints or floats.\n", "A simple example will showcase this." ] }, { "cell_type": "code", "execution_count": 79, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['12', '43', '64', '6']\n", "125\n" ] } ], "source": [ "s=\"12 43 64 6\"\n", "L=s.split() # The split method of the string class, breaks the string at whitespaces\n", " # to a list of strings.\n", "print(L)\n", "print(sum(map(int, L))) # The int function converts a string to an integer" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sometimes it feels unnecessary to write a function is you are only going to use it in one `map` function call. For example the function" ] }, { "cell_type": "code", "execution_count": 80, "metadata": {}, "outputs": [], "source": [ "def add_double_and_square(x):\n", " return 2*x+x**2 " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "It is not likely that you will need it elsewhere in your program. The solution is to use an *expression* called *lambda* to define a function with no name. Because it is an expression, we can put it, for instance, in an argument list of a function call. The lambda expression has the form `lambda param1,param2, ... : expression`, where after the lambda keyword you list the parameters of the function, and after the colon is the expression that uses the parameters to compute the return value of the function. Let's replace the above `add_double_and_square` function with a lambda function and apply it to a list using the `map` function." ] }, { "cell_type": "code", "execution_count": 81, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[8, 15, 35]\n" ] } ], "source": [ "L=[2,3,5]\n", "print(list(map(lambda x : 2*x+x**2, L)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 16 (transform)
\n", "\n", "Write a function `transform` that gets two strings as parameters and returns a list of integers. The function should split the strings into words, and convert these words to integers. This should give two lists of integers. Then the function should return a list whose elements are multiplication of two integers in the respective positions in the lists.\n", "For example\n", "`transform(\"1 5 3\", \"2 6 -1\")`\n", "should return the list of integers\n", "`[2, 30, -3]`.\n", "\n", "You **have** to use `split`, `map`, and `zip` functions/methods. You may assume that the two input strings are in correct format.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Filter function\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `filter` function takes a function and a list as parameters. But unlike with the map construct, now the parameter function must take exactly one parameter and return a truth value (True or False). The `filter` function then creates a new list with only those elements from the original list for which the parameter function returns True. The elements for which the parameter function returns False are filtered out. An example will demonstrate the `filter` function:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2019-06-18T08:51:04.876219Z", "start_time": "2019-06-18T08:51:04.868956Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 5, 9]\n" ] } ], "source": [ "def is_odd(x):\n", " \"\"\"Returns True if x is odd and False if x is even\"\"\"\n", " return x % 2 == 1 # The % operator returns the remainder of integer division\n", "L=[1, 4, 5, 9, 10]\n", "print(list(filter(is_odd, L)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The even elements of the list were filtered out.\n", "\n", "Note that the `filter` function is rarely used in modern python since list comprehensions can do the same thing while also doing whatever we want to do with the filtered values." ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2019-06-18T08:54:12.503567Z", "start_time": "2019-06-18T08:54:12.496414Z" } }, "outputs": [ { "data": { "text/plain": [ "[1, 25, 81]" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "[l**2 for l in L if is_odd(l)] # squares of odd values" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "That said, `filter` is a useful function to know." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 17 (positive list)
\n", "\n", "Write a function `positive_list` that gets a list of numbers as a parameter, and returns a list with the negative numbers and zero filtered out using the `filter` function.\n", "\n", "The function call `positive_list([2,-2,0,1,-7])` should return the list `[2,1]`. Test your function in the `main` function.\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### The reduce function\n", "The `sum` function that returns the sum of a numeric list, can be though to reduce a list to a single element. It does this reduction by repeatedly applying the `+` operator until all the list elements are consumed. For instance, the list `[1,2,3,4]` is reduced by the expression `(((0+1)+2)+3)+4` of repeated applications of the `+` operator. We could implement this with the following function:" ] }, { "cell_type": "code", "execution_count": 83, "metadata": {}, "outputs": [], "source": [ "def sumreduce(L):\n", " s=0\n", " for x in L:\n", " s = s+x\n", " return s" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because this is a common pattern, the `reduce` function is a common inclusion in functional programming languages. In Python `reduce` is included in the `functools` modlue. You give the operator you want to use as a parameter to reduce (addition in the above example). You may also give a starting value of the computation (starting value 0 was used above). \n", "\n", "If no starting value is used, the first element of the iterable is used as the starting value. \n", "\n", "We can now get rid of the separate function `sumreduce` by using the reduce function:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2019-06-14T10:34:47.938617Z", "start_time": "2019-06-14T10:34:47.918796Z" } }, "outputs": [ { "data": { "text/plain": [ "10" ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "L=[1,2,3,4]\n", "from functools import reduce # import the reduce function from the functools module\n", "reduce(lambda x,y:x+y, L, 0)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we wanted to get a product of all numbers in a sequence, we would use" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2019-06-14T10:34:50.226139Z", "start_time": "2019-06-14T10:34:50.220525Z" } }, "outputs": [ { "data": { "text/plain": [ "24" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "reduce(lambda x,y:x*y, L, 1)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This corresponds to the sequence `(((1*1)*2)*3)*4` of application of operator `*`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
Note that use of the starting value is necessary, because we want to be able to reduce lists of length 0 as well. If no starting value is specified when run on an empty list, reduce will raise an exception.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## String handling\n", "We have already seen how to index, slice, concatenate, and repeat strings. Let's now look into what methods the `str` class offers. In Python strings are immutable. This means that for instance the following assignment is not legal:" ] }, { "cell_type": "code", "execution_count": 86, "metadata": {}, "outputs": [], "source": [ "s=\"text\"\n", "# s[0] = \"a\" # This is not legal in Python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Because of the immutability of the strings, the string methods work by returning a value; they don't have any side-effects. In the rest of this section we briefly describe several of these methods. The methods are here divided into five groups." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Classification of strings\n", "All the following methods will take no parameters and return a truth value. An empty string will always result in `False`.\n", "\n", "* `s.isalnum()` True if all characters are letters or digits\n", "* `s.isalpha()` True if all characters are letters\n", "* `s.isdigit()` True if all characters are digits\n", "* `s.islower()` True if contains letters, and all are lowercase\n", "* `s.isupper()` True if contains letters, and all are uppercase\n", "* `s.isspace()` True if all characters are whitespace\n", "* `s.istitle()` True if uppercase in the beginning of word, elsewhere lowercase" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### String transformations\n", "The following methods do conversions between lower and uppercase characters in the string. All these methods return a new string.\n", "\n", "* `s.lower()` Change all letters to lowercase\n", "* `s.upper()` Change all letters to uppercase\n", "* `s.capitalize()` Change all letters to capitalcase\n", "* `s.title()` Change to titlecase\n", "* `s.swapcase()` Change all uppercase letters to lowercase, and vice versa\n", "\n", "\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Searching for substrings\n", "All the following methods get the wanted substring as the\n", "parameter, except the replace method, which also gets the\n", "replacing string as a parameter\n", "\n", "* `s.count(substr)` Counts the number of occurences of a substring\n", "* `s.find(substr)` Finds index of the first occurence of a substring, or -1\n", "* `s.rfind(substr)` Finds index of the last occurence of a substring, or -1\n", "* `s.index(substr)` Like find, except ValueError is raised if not found\n", "* `s.rindex(substr)` Like rfind, except ValueError is raised if not found\n", "* `s.startswith(substr)` Returns True if string starts with a given substring\n", "* `s.endswith(substr)` Returns True if string ends with a given substring\n", "* `s.replace(substr, replacement)` Returns a string where occurences of one string\n", "are replaced by another\n", "\n", "Keep also in mind that the expression `\"issi\" in \"mississippi\"` returns a truth value of whether the first string occurs in the second string.\n", "\n", "\n", "\n", "\n", "\n", "\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Trimming and adjusting\n", "* `s.strip(x)` Removes leading and trailing whitespace by default, or characters found in string x\n", "* `s.lstrip(x)` Same as strip but only leading characters are removed\n", "* `s.rstrip(x)` Same as strip but only trailing characters are removed\n", "* `s.ljust(n)` Left justifies string inside a field of length n\n", "* `s.rjust(n)` Right justifies string inside a field of length n\n", "* `s.center(n)` Centers string inside a field of length n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "An example of using the `center` method and string repetition:" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2019-06-13T10:43:02.880507Z", "start_time": "2019-06-13T10:43:02.873128Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-----------\n", "| * |\n", "| *** |\n", "| ***** |\n", "| ******* |\n", "|*********|\n", "| * |\n", "| * |\n", "-----------\n" ] } ], "source": [ "L=[1,3,5,7,9,1,1]\n", "print(\"-\"*11)\n", "for i in L:\n", " s=\"*\"*i \n", " print(f\"|{s.center(9)}|\")\n", "print(\"-\"*11)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Joining and splitting\n", "The `join(seq)` method joins the strings of the sequence `seq`. The string itself is used as a delimitter. An example:" ] }, { "cell_type": "code", "execution_count": 88, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "'abc--def--ghi'" ] }, "execution_count": 88, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\"--\".join([\"abc\", \"def\", \"ghi\"])" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2019-06-18T09:03:51.182630Z", "start_time": "2019-06-18T09:03:51.176643Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ " 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99\n", "0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99\n" ] } ], "source": [ "L=[str(x) for x in range(100)]\n", "s=\"\"\n", "for x in L:\n", " s += \" \" + x # Avoid doing this, it creates a new string at every iteration\n", "print(s) # Note the redundant initial space\n", "print(\" \".join(L)) # This is the correct way of building a string out of smaller strings" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "
If you want to build a string out of smaller strings, then\n", "first put the small strings into a list, and then use the `join` method to catenate the pieces together. It is much more efficient this way. Use the + catenation operator only if you have very few short strings that you want to catenate.
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Below we can see that for our small (100 element) list, execution is an order of magnitude faster using the `join` method." ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2019-06-18T09:04:03.371833Z", "start_time": "2019-06-18T09:03:53.717431Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "11.8 µs ± 114 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n" ] } ], "source": [ "%%timeit\n", "s=\"\"\n", "for x in L:\n", " s += \" \" + x" ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2019-06-18T09:04:35.670357Z", "start_time": "2019-06-18T09:04:25.471086Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.25 µs ± 6.42 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n" ] } ], "source": [ "%%timeit\n", "s = \" \".join(L)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`%%timeit` is an IPython [cell magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html) command, that is useful for timing execution in notebooks." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The method `split(sep=None)` divides a string into pieces that are separated by the string `sep`. The pieces are returned in a list. For instance, the call `'abc--def--ghi'.split(\"--\")` will result in" ] }, { "cell_type": "code", "execution_count": 90, "metadata": {}, "outputs": [ { "data": { "text/plain": [ "['abc', 'def', 'ghi']" ] }, "execution_count": 90, "metadata": {}, "output_type": "execute_result" } ], "source": [ "'abc--def--ghi'.split(\"--\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If no parameters are given to the `split` method, then it splits at any sequence of white space." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 18 (acronyms)
\n", "\n", "Write function `acronyms` which takes a string as a parameter and returns a list of acronyms. A word is an acronym if it has length at least two, and all its characters are in uppercase. Before acronym detection, delete punctuation with the `strip` method.\n", "\n", "Test this function in the `main` function with the following call:\n", "```python\n", "print(acronyms(\"\"\"For the purposes of the EU General Data Protection Regulation (GDPR), the controller of your personal information is International Business Machines Corporation (IBM Corp.), 1 New Orchard Road, Armonk, New York, United States, unless indicated otherwise. Where IBM Corp. or a subsidiary it controls (not established in the European Economic Area (EEA)) is required to appoint a legal representative in the EEA, the representative for all such cases is IBM United Kingdom Limited, PO Box 41, North Harbour, Portsmouth, Hampshire, United Kingdom PO6 3AU.\"\"\"))\n", "```\n", "\n", "This should return\n", "```['EU', 'GDPR', 'IBM', 'IBM', 'EEA', 'EEA', 'IBM', 'PO', 'PO6', '3AU']```\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 19 (sum equation)
\n", "\n", "Write a function `sum_equation` which takes a list of positive integers as parameters and returns a string with an equation of the sum of the elements.\n", "\n", "Example:\n", "`sum_equation([1,5,7])`\n", "returns\n", "`\"1 + 5 + 7 = 13\"`\n", "Observe, the spaces should be exactly as shown above. For an empty list the function should return the string \"0 = 0\".\n", "
" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Modules" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To ease management of large programs, software is divided\n", "into smaller pieces. In Python these pieces are called *modules*.\n", "A module should be a unit that is as independent from other\n", "modules as possible.\n", "Each file in Python corresponds to a module.\n", "Modules can contain classes, objects, functions, ...\n", "For example, functions to handle regular expressions are in\n", "module `re`\n", "\n", "The standard library of Python consists of hundreds of\n", "modules. Some of the most common standard modules include\n", "\n", "* `re`\n", "* `math`\n", "* `random`\n", "* `os`\n", "* `sys`\n", "\n", "Any file with extension `.py` that contains Python source code\n", "is a module. So, no special notation is needed to create a module." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Using modules\n", "\n", "Let’s say that we need to use the cosine function.\n", "This function, and many other mathematical functions are\n", "located in the `math` module.\n", "To tell Python that we want to access the features offered by\n", "this module, we can give the statement `import math`.\n", "Now the module is loaded into memory.\n", "We can now call the function like this:\n", "```python\n", "math.cos(0)\n", "1.0\n", "```\n", "\n", "Note that we need to include the module name where the `cos`\n", "function is found.\n", "This is because other modules may have a function (or other\n", "attribute of a module) with the same name.\n", "This usage of different namespace for each module prevents\n", "name clashes. For example, functions `gzip.open`, `os.open` are not to be confused\n", "with the builtin `open` function." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Breaking the namespace\n", "\n", "If the cosine is needed a lot, then it might be tedious to\n", "always specify the namespace, especially if the name of the\n", "namespace/module is long.\n", "For these cases there is another way of importing modules.\n", "Bring a name to the current scope with\n", "`from math import cos` statement.\n", "Now we can use it without the namespace specifier: `cos(1)`.\n", "\n", "Several names can be imported to the current scope with\n", "`from math import name1, name2, ...`\n", "Or even all names of the module with `from math import *`\n", "The last form is sensible only in few cases, normally it just\n", "confuses things since the user may have no idea what names\n", "will be imported." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Module lookup\n", "\n", "When we try to import a module `mod` with the import\n", "statement, the lookup proceeds in the following order:\n", "\n", "* Check if it is a builtin module\n", "* Check if the file `mod.py` is found in any of the folders in\n", "the list `sys.path`. The first item in this list is the current\n", "folder\n", "\n", "When Python is started, the `sys.path` list is initialised with\n", "the contents of the `PYTHONPATH` environment variable" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Module hierarchy\n", "\n", "The standard library contains hundreds of modules.\n", "Hence, it is hard to comprehend what the library includes.\n", "The modules therefore need to be organised somehow.\n", "In Python the modules can be organised into hierarchies using\n", "*packages*.\n", "A package is a module that can contain other packages and\n", "modules.\n", "For example, the `numpy` package contains subpackages `core`,\n", "`distutils`, `f2py`, `fft`, `lib`, `linalg`, `ma`, `numarray`, `oldnumeric`,\n", "`random`, and `testing`.\n", "And package `numpy.linalg` in turn contains modules `linalg`,\n", "`lapack_lite` and `info`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Importing from packages\n", "\n", "The statement `import numpy` imports the top-level package `numpy`\n", "and its subpackages. \n", "\n", "* `import numpy.linalg` imports the subpackage only, and\n", "* `import numpy.linalg.linalg` imports the module only\n", "\n", "If we want to skip the long namespace specification, we can\n", "use the form\n", "\n", "```python\n", "from numpy.linalg import linalg\n", "```\n", "\n", "or\n", "\n", "```python\n", "from numpy.linalg import linalg as lin\n", "```\n", "\n", "if we want to use a different name for the module. The following command imports the function `det` (computes the determinant of a matrix) from the module linalg, which is contained in a subpackage linalg, which belongs to package numpy:\n", "```python\n", "from numpy.linalg.linalg import det\n", "```\n", "\n", "Had we only imported the top-level package `numpy` we would have to refer to the `det` function with the full name `numpy.linalg.linalg.det`.\n", "\n", "Here's a recap of the module hierarchy:\n", "\n", "```\n", "numpy package\n", " .\n", "linalg subpackage\n", " .\n", "linalg module\n", " .\n", " det function\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Correspondence between folder and module hierarchies\n", "\n", "The packages are represented by folders in the filesystem.\n", "The folder should contain a file named `__init__.py` that\n", "makes up the package body. This handles the initialisation of\n", "the package.\n", "The folder may contain also further folders\n", "(subpackages) or Python files (normal modules).\n", "\n", "```\n", "a/\n", " __init__.py\n", " b.py\n", " c/\n", " __init__.py\n", " d.py\n", " e.py\n", "```\n", "![package.svg](package.svg)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Contents of a module\n", "\n", "Suppose we have a module named `mod.py`.\n", "All the assignments, class definitions with the `class` statement,\n", "and function definitions with `def` statement will create new\n", "attributes to this module.\n", "Let’s import this module from another Python file using the\n", "`import mod` statement.\n", "After the import we can access the attributes of the module\n", "object using the normal dot notation: `mod.f()`,\n", "`mod.myclass()`, `mod.a`, etc.\n", "Note that Python doesn’t really have global variables that are\n", "visible to all modules. All variables belong to some module\n", "namespace.\n", "\n", "One can query the attributes of an object using the `dir` function. With no\n", "parameters, it shows the attributes of the current module. Try executing `dir()` in\n", "an IPython shell or in a Jupyter notebook! After that, define the following attributes, and try running `dir()`\n", "again:\n", "\n", "```python\n", "a=5\n", "def f(i):\n", " return i + 1\n", "```\n", "\n", "The above definitions created a *data attribute* called `a` and a *function attribute* called `f`.\n", "We will talk more about attributes next week when we will talk about objects.\n", "\n", "Just like other objects, the module object contains its\n", "attributes in the dictionary `modulename.__dict__`\n", "Usually a module contains at least the attributes `__name__` and\n", "`__file__`. Other common attributes are `__version__`,\n", "`__author__` and `__doc__` , which contains the docstring of the\n", "module.\n", "If the first statement of a file is a string, this is taken as the\n", "docstring for that module. Note that the docstring of the module really must be the first non-empty non-comment line.\n", "The attribute `__file__` is always the filename of the module.\n", "\n", "The module attribute `__name__` has value `“__main__”` if we in are the main program,\n", "otherwise some other module has imported us and name\n", "equals `__file__`." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In Python it is possible to put statements on the top-level of our module `mod` so that they don't belong to any function. For instance like this:\n", "\n", "```python\n", "for _ in range(3):\n", " print(\"Hello\")\n", "```\n", "\n", "But if somebody imports our module with `import mod`, then all the statements at the top-level will be executed. This may be surprising to the user who imported the module. The user will usually say, explicitly when he/she wants to execute some code from the imported module.\n", "\n", "It is better style to put these statements inside some function. If they don't fit in any other function, then you can use, for example, the function named `main`, like this:\n", "\n", "```python\n", "def main():\n", " for _ in range(3):\n", " print(\"Hello\")\n", "\n", "if __name__ == \"__main__\": # We call main only when this module is not being imported, but directly executed\n", " main() # for example with 'python3 mod.py'\n", "```\n", "\n", "You probably have seen this mechanism used in the exercise stubs.\n", "Note that in Python the `main` has no special meaning, it is just our convention to use it here.\n", "Now if somebody imports `mod`, the `for` loop won't be automatically executed. If we want, we can call it explicitly with `mod.main()`. " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```python\n", "for _ in range(3):\n", " print(\"Hello\")\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "####
Exercise 20 (usemodule)
\n", "\n", "Create your own module as file `triangle.py` in the `src` folder. The module should contain two functions:\n", "\n", "* `hypothenuse` which returns the length of the hypothenuse when given the lengths of two other sides of a right-angled triangle\n", "* `area` which returns the area of the right-angled triangle, when two sides, perpendicular to each other, are given as parameters.\n", "\n", "Make sure both the functions and the module have descriptive docstrings. Add also the `__version__` and `__author__` attributes to the module. Call both your functions from the main function (which is in file `usemodule.py`)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Summary\n", "\n", "* We have learned that Python's code blocks are denoted by consistent indenting, with spaces or tabs, unlike in many other languages\n", "* Python's `for` loops goes through all the elements of a container without the need of worrying about the positions (indices) of the elements in the container\n", "* More generally, an iterable is an object whose elements can be gone through one by one using a `for` loop. Such as `range(1,7)`\n", "* Python has dynamic typing: the type of a name is known only when we run the program. The type might not be fixed, that is, if a name is created, for example, in a loop, then its type might change at each iteration.\n", "* Visibility of a name: a name that refers to a variable can disappear in the middle of a code block, if a `del` statement is issued!\n", "* Python is good at string handling, but remember that if you want to concatenate large number of strings, use the `join` method. Concatenating by the `+` operator multiple times is very inefficient\n", "* Several useful tools exist to process sequences: `map`, `reduce`, `filter`, `zip`, `enumerate`, and `range`. The unnamed lambda function can be helpful with these tools. Note that these tools (except the `reduce`) don't return lists, but iterables, for efficiency reasons: Most often we don't want to store the result from these tools to a container (such as a list), we may only want to iterate through the result!" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "\n", "\n", "\"Open\n" ] } ], "metadata": { "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.6.8" }, "varInspector": { "cols": { "lenName": 16, "lenType": 16, "lenVar": 40 }, "kernels_config": { "python": { "delete_cmd_postfix": "", "delete_cmd_prefix": "del ", "library": "var_list.py", "varRefreshCmd": "print(var_dic_list())" }, "r": { "delete_cmd_postfix": ") ", "delete_cmd_prefix": "rm(", "library": "var_list.r", "varRefreshCmd": "cat(var_dic_list()) " } }, "types_to_exclude": [ "module", "function", "builtin_function_or_method", "instance", "_Feature" ], "window_display": false } }, "nbformat": 4, "nbformat_minor": 2 }