{
  "nbformat": 4,
  "nbformat_minor": 0,
  "metadata": {
    "colab": {
      "provenance": []
    },
    "kernelspec": {
      "name": "python3",
      "display_name": "Python 3"
    },
    "language_info": {
      "name": "python"
    }
  },
  "cells": [
    {
      "cell_type": "markdown",
      "source": [
        "# Embedded Systems Laboratory\n",
        "\n",
        "## Lab 2: Introduction into Python programming\n",
        "\n",
        "### Project overview\n",
        "\n",
        "In this laboratory you will start writing Python programs. Python is the official language for RPi and it is pre-installed on the Raspberry OS. This laboratory content assumes that you have studied at least one programming languages (e.g. C/C++, Java, C#) earlier.\n",
        "\n",
        "\n",
        "This lab content is a special one because it does not require the use of a RPi. Any online Python interpreter is sufficient for testing the code examples and solving the exercises included in the lab material. If you have a Google account, I recommend using **Google Colab** to test and run these codes.\n",
        "\n",
        "The following topics will be covered in this lab:\n",
        "* Basic Python skills\n",
        "* Writing Python programs"
      ],
      "metadata": {
        "id": "xy8Xz9vsJVG0"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Technical requirements\n",
        "\n",
        "Any of the options listed below will be sufficient:\n",
        "* A computer with Internet access\n",
        "* Raspberry Pi mini-computer (MicroSD card, power supply, keyboard, mouse)"
      ],
      "metadata": {
        "id": "po8Gne131ECh"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Getting started\n",
        "\n",
        "Todays Python is the most popular programming language on RPi. It is a high-level, great general-purpose, dynamically typed multiparadigm programming language. The program code is often said to be almost like pseudocode, since it allows you to express very powerful ideas in very few lines of code while being very readable.\n",
        "\n",
        "In Janurary 1, 2020, Python has [officially dropped support](https://www.python.org/doc/sunset-python-2/) for Python2. You can check your Python version at the command line by running `python --version`.\n",
        "\n",
        "\n",
        "There are more IDEs available on the RPi such as VS Code, Thonny, etc. However, any text editor (e.g. nano) also can be used for Python programming. You need to note that Python is case-sensitive and <font color='red'>**code blocks are identified according to their indent!!**</font>\n"
      ],
      "metadata": {
        "id": "d_a-2anmzndT"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Basic data types\n",
        "\n",
        "While a statically typed language like C or Java requires each variable to be\n",
        "explicitly declared, a dynamically typed language like Python skips this specification. So we can assign any kind of data to any variable. Due to this flexibility, Python variables are more than just their values. They also contain extra information about the type of the value. Therefor, each data type is a complete **Python object**!\n"
      ],
      "metadata": {
        "id": "JOaBa3JypI0J"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Numbers\n",
        "Integers and floats work as you would expect from other languages:"
      ],
      "metadata": {
        "id": "bO3f8JuxpMiT"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "x = 6\n",
        "print(x, type(x))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ZBIjSyfnpOUT",
        "outputId": "c9f67cfa-fc26-466d-ed00-827278c284a3"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "6 <class 'int'>\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "print(x + 1)   # Addition\n",
        "print(x * 2)   # Multiplication\n",
        "print(x ** 2)  # Exponentiation"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7wVxELHxpS91",
        "outputId": "9719dc93-708c-44bd-86f0-bcf59466c433"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "7\n",
            "12\n",
            "36\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "x -= 1\n",
        "print(x)\n",
        "x *= 3\n",
        "print(x)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "E4XWb0_0pVny",
        "outputId": "488ea847-497b-4204-dd70-dd0f3ba5ec34"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "5\n",
            "15\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "y = 3.5\n",
        "print(type(y))\n",
        "print(y, y - 1, y / 2, y ** 2)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "P3lzVFoYpYJb",
        "outputId": "1540a5c0-71a0-4231-d9be-658777bf1407"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "<class 'float'>\n",
            "3.5 2.5 1.75 12.25\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Note that unlike many languages, Python does not have unary increment (`x++`) or decrement (`x--`) operators. Python also has built-in types for long integers and complex numbers. For mor information, take a look at the [documentation](https://docs.python.org/3.7/library/stdtypes.html#numeric-types-int-float-long-complex)."
      ],
      "metadata": {
        "id": "XlvLNUwgpcyJ"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Booleans\n",
        "Python implements all of the usual operators for Boolean logic, but uses English words rather than well known symbols (`&&`, `||`, etc.):"
      ],
      "metadata": {
        "id": "8jd4-R7Opl9A"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "T, F = True, False\n",
        "print(type(T))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "hEZCJ5kGpo71",
        "outputId": "8f180385-068d-4cf1-8193-e34a1e36e5bc"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "<class 'bool'>\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "print(T and F) # Logical AND;\n",
        "print(T or F)  # Logical OR;\n",
        "print(not T)   # Logical NOT;\n",
        "print(T != F)  # Logical XOR;"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "8hi7La5eqAbg",
        "outputId": "6bef6c6a-65e1-41fd-f987-79f7c0fe6948"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "False\n",
            "True\n",
            "False\n",
            "True\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Strings\n",
        "\n",
        "In Python, textual data is handled using *strings*. For instance, \"hello\" and 'hello' are strings. We can concatenate them using the addition `+` symbol."
      ],
      "metadata": {
        "id": "blsajUYctq8Y"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "hello = 'hello'   # String literals can use single quotes\n",
        "world = \"world\"   # or double quotes; it does not matter\n",
        "print(hello, len(hello))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "RW6nwSODt3yj",
        "outputId": "265cc70f-3ac4-4f3e-8d1d-49dffc08e1d4"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "hello 5\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "hw = hello + ' ' + world  # String concatenation\n",
        "print(hw)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "pjHRoeA-txcM",
        "outputId": "c83bf9e6-4e57-4309-d754-52ddefa9a4bd"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "hello world\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "hw12 = '{} {} {}'.format(hello, world, 12)  # string formatting\n",
        "print(hw12)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "EE1vKm0st_PN",
        "outputId": "f7357c61-377d-48eb-ea9f-e619ddd07e77"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "hello world 12\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "String objects have a lot of useful methods. You can find the whole list of string methods in the [documentation](https://docs.python.org/3.7/library/stdtypes.html#string-methods). Some examples:"
      ],
      "metadata": {
        "id": "7uJy4OYhuCXG"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "s = \"hello\"\n",
        "print(s.capitalize())  # Capitalize a string\n",
        "print(s.upper())       # Convert a string to uppercase; prints \"HELLO\"\n",
        "print(s.rjust(7))      # Right-justify a string, padding with spaces\n",
        "print(s.center(7))     # Center a string, padding with spaces\n",
        "print(s.replace('l', 'x'))  # Replace all instances of one substring with another\n",
        "print('  world '.strip())  # Strip leading and trailing whitespace"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "6TUDk9HRuWMD",
        "outputId": "a8b5ab4a-3f3f-4a3d-b340-b99da2865bab"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Hello\n",
            "HELLO\n",
            "  hello\n",
            " hello \n",
            "hexxo\n",
            "world\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Containers\n",
        "Python includes several built-in container types: **lists**, **dictionaries**, **sets**, and **tuples**.\n",
        "\n"
      ],
      "metadata": {
        "id": "Bcq34ZiEuhnz"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### Lists\n",
        "A list is the Python equivalent of an array, but is resizeable and we can even create heterogeneous lists due to Python’s dynamic typing.\n",
        "\n"
      ],
      "metadata": {
        "id": "N6Y7fC_rupYx"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "xs = []           # Empty list\n",
        "print(len(xs))    # len() - give back the length of the list\n",
        "\n",
        "xs = [3, 1, 2]    # Create a list\n",
        "print(xs, xs[2])\n",
        "print(xs[-1])     # Negative indices count from the end of the list; prints \"2\""
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "pCxpVYfhuvDW",
        "outputId": "722338af-505c-4e62-edf5-a5c9f06db09d"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "0\n",
            "[3, 1, 2] 2\n",
            "2\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "xs[2] = 'foo'    # Lists can contain elements of different types\n",
        "print(xs)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "xqcPYwV9uzN5",
        "outputId": "0fc35d95-4ff3-4771-f8c6-9e963ade97e7"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[3, 1, 'foo']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "xs.append('bar') # Add a new element to the end of the list\n",
        "print(xs)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "UPGHxttXu2YB",
        "outputId": "a2a6d9d1-f2c7-46f8-c69a-48d7fa1882b6"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[3, 1, 'foo', 'bar']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "x = xs.pop()     # Remove and return the last element of the list\n",
        "print(x, xs)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "QICxiqRru5Qo",
        "outputId": "ba457db4-06b1-49e6-8551-08e6e2a660a4"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "bar [3, 1, 'foo']\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "mylist = [True, \"2\", 3.0, 4]\n",
        "for i in mylist: print(type(i))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "DvrSJqqNu9kv",
        "outputId": "0e06720e-3bc2-4930-ff71-bd2ffd89977e"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "<class 'bool'>\n",
            "<class 'str'>\n",
            "<class 'float'>\n",
            "<class 'int'>\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "##### List slicing\n",
        "In addition to accessing list elements one at a time, Python provides concise syntax to access sublists; this is known as slicing:"
      ],
      "metadata": {
        "id": "g6X2A7vNvAtv"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "nums = list(range(5))    # range is a built-in function that creates a list of integers\n",
        "print(nums)         # Prints \"[0, 1, 2, 3, 4]\"\n",
        "print(nums[2:4])    # Get a slice from index 2 to 4 (exclusive); prints \"[2, 3]\"\n",
        "print(nums[2:])     # Get a slice from index 2 to the end; prints \"[2, 3, 4]\"\n",
        "print(nums[:2])     # Get a slice from the start to index 2 (exclusive); prints \"[0, 1]\"\n",
        "print(nums[:])      # Get a slice of the whole list; prints [\"0, 1, 2, 3, 4]\"\n",
        "print(nums[:-1])    # Slice indices can be negative; prints [\"0, 1, 2, 3]\"\n",
        "nums[2:4] = [8, 9] # Assign a new sublist to a slice\n",
        "print(nums)         # Prints \"[0, 1, 8, 9, 4]\""
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "-GPQkcvPvI-y",
        "outputId": "f69eda23-f487-4c35-c2e3-facef80249e7"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[0, 1, 2, 3, 4]\n",
            "[2, 3]\n",
            "[2, 3, 4]\n",
            "[0, 1]\n",
            "[0, 1, 2, 3, 4]\n",
            "[0, 1, 2, 3]\n",
            "[0, 1, 8, 9, 4]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "nums.sort()                 # Sort list\n",
        "print(nums)\n",
        "\n",
        "nums.sort(reverse=True)     # Sort in reversed order\n",
        "print(nums)\n",
        "\n",
        "del nums[2]                 # Delete list element\n",
        "print(nums)\n",
        "\n",
        "nums.remove(9)              # Remove item from list\n",
        "print(nums)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "j4R7Hr_e5Ghp",
        "outputId": "410da912-a91a-464f-de1a-7f15280f1a8d"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[0, 1, 4, 8, 9]\n",
            "[9, 8, 4, 1, 0]\n",
            "[9, 8, 1, 0]\n",
            "[8, 1, 0]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "A `for` loop is a standard tool in many languages that repeatedly evaluates some chunk of code while varying different values inside the code. You can loop over the elements of a list like this:"
      ],
      "metadata": {
        "id": "Hy8v3zWOvWd8"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "animals = ['cat', 'dog', 'monkey']\n",
        "for animal in animals:\n",
        "    print(animal)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9oTsz1edvalF",
        "outputId": "ca417f9c-348c-4f14-9668-5e331a968262"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "cat\n",
            "dog\n",
            "monkey\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "If you want access to the index of each element within the body of a loop, use the built-in `enumerate` function:"
      ],
      "metadata": {
        "id": "29wNOIR9verN"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "animals = ['cat', 'dog', 'monkey']\n",
        "for idx, animal in enumerate(animals):\n",
        "    print('{}: {}'.format(idx + 1, animal))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "X4BPj2Spviho",
        "outputId": "55858b95-fd37-4a74-ef1d-55fe1a0eda98"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "1: cat\n",
            "2: dog\n",
            "3: monkey\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "##### List comprehension\n",
        "\n",
        "During programming, we want to modify the data frequently. As a simple example, consider the following code that computes square numbers:"
      ],
      "metadata": {
        "id": "5PMwJjAOvoY-"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "nums = [0, 1, 2, 3, 4]\n",
        "squares = []\n",
        "for x in nums:\n",
        "    squares.append(x ** 2)\n",
        "print(squares)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "DI_l-OIyvpbF",
        "outputId": "d8b81909-2497-4fc4-d6df-f403f8145fd0"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[0, 1, 4, 9, 16]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "You can make this code simpler using a list comprehension:"
      ],
      "metadata": {
        "id": "GLH6U_Q8vwWC"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "nums = [0, 1, 2, 3, 4]\n",
        "squares = [x ** 2 for x in nums]\n",
        "print(squares)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "8lM09s46vxbE",
        "outputId": "0d282100-66b6-447d-a4c2-60cdb0a36f81"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[0, 1, 4, 9, 16]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "List comprehensions can also contain conditions:"
      ],
      "metadata": {
        "id": "yJOA2L9Xv3KY"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "nums = [0, 1, 2, 3, 4]\n",
        "even_squares = [x ** 2 for x in nums if x % 2 == 0]\n",
        "print(even_squares)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0GCcS80kv5iC",
        "outputId": "843fad13-e3c9-4e23-cddc-92b0f09097e8"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "[0, 4, 16]\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### Dictionaries\n",
        "Another fundamental data structure. A dictionary stores **(key, value) pairs**. You can access an item using its key. Dictionary elements definition inside curly brackets: *{key1: value1, key2: value2, …}*. Below there are some a simple examples about how to use it:"
      ],
      "metadata": {
        "id": "lr7FVbHIxRKe"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "d = {'cat': 'cute', 'dog': 'furry'}  # Create a new dictionary with some data\n",
        "print(d['cat'])       # Get an entry from a dictionary; prints \"cute\"\n",
        "print('cat' in d)     # Check if a dictionary has a given key; prints \"True\""
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "S8V2IREJxUXw",
        "outputId": "f93e9beb-a2cb-497c-f4f5-d11140003f40"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "cute\n",
            "True\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "d['fish'] = 'wet'    # Set an entry in a dictionary\n",
        "print(d['fish'])      # Prints \"wet\""
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "3D1kRNgHxk84",
        "outputId": "c433a43f-9c12-4a24-90d2-c9304f4ce3ba"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "wet\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "print(d.get('monkey', 'N/A'))  # Get an element with a default; prints \"N/A\"\n",
        "print(d.get('fish', 'N/A'))    # Get an element with a default; prints \"wet\""
      ],
      "metadata": {
        "id": "fO5AbWwPxnhx"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "It is easy to iterate over the keys in a dictionary:"
      ],
      "metadata": {
        "id": "7F0Cht9OxijS"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "d = {'person': 2, 'cat': 4, 'spider': 8}\n",
        "for animal, legs in d.items():\n",
        "    print('A {} has {} legs'.format(animal, legs))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ESWI2OLUyITA",
        "outputId": "63662221-f3c6-41b8-f1d2-2e03a3c35b46"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "A person has 2 legs\n",
            "A cat has 4 legs\n",
            "A spider has 8 legs\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Dictionary comprehensions: these are similar to list comprehensions, but allow you to easily construct dictionaries. For example:"
      ],
      "metadata": {
        "id": "-ycjUU_IyK5O"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "nums = [0, 1, 2, 3, 4]\n",
        "even_num_to_square = {x: x ** 2 for x in nums if x % 2 == 0}\n",
        "print(even_num_to_square)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "RSZTopMsyPB4",
        "outputId": "ef587b29-9eab-487d-bdf4-03b8430cc08d"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "{0: 0, 2: 4, 4: 16}\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "#### Tuples\n",
        "A tuple is an (**immutable**) ordered list of values. A tuple is in many ways similar to a list. One of the most important differences is that tuples can be used as keys in dictionaries and as elements of sets, while lists cannot. Here is a trivial example:"
      ],
      "metadata": {
        "id": "Rq3dypjUyjpk"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "d = {(x, x + 1): x for x in range(10)}  # Create a dictionary with tuple keys\n",
        "t = (5, 6)       # Create a tuple\n",
        "print(type(t))\n",
        "print(d[t])\n",
        "print(d[(1, 2)])"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "el9JHlQEynkq",
        "outputId": "a3770eff-e923-4506-bdcc-6c24a87d01a2"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "<class 'tuple'>\n",
            "5\n",
            "1\n"
          ]
        }
      ]
    },
    {
      "cell_type": "code",
      "source": [
        "t[0] = 1 # item assignment is not allowed"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 141
        },
        "id": "8Toya00Cysep",
        "outputId": "ff2dfc7c-282a-4f40-bcbe-146db33a16cb"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "error",
          "ename": "TypeError",
          "evalue": "'tuple' object does not support item assignment",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
            "\u001b[0;32m/tmp/ipykernel_480/444603787.py\u001b[0m in \u001b[0;36m<cell line: 0>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mt\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m1\u001b[0m \u001b[0;31m# item assignment is not allowed\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Functions\n",
        "\n",
        "As you know, functions enable you to reuse parts of your program. Like most programming languages, Python uses *functions* to perform operations. To run a function called fun, we type `fun(input1,input2)`, where the inputs (or *arguments*) *input1* and *input2* tell Python how to run the function.  A function can have any number of inputs and they may have a default value. Unlike other languages, an argument can be a function!\n",
        "\n",
        "For example, the `print()`  function outputs a text representation of all of its arguments to the console."
      ],
      "metadata": {
        "id": "Wy6Cvpn8pEkI"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "print('Embedded systems', 2026)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "SOYzEIo2JYUl",
        "outputId": "4eeb00ae-0415-439d-d7ad-40a1a176d079"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Embedded systems 2026\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        " The following command will provide information about the `print()` function."
      ],
      "metadata": {
        "id": "kj1uDh3-JxEe"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "print?"
      ],
      "metadata": {
        "id": "SHoTwlmQJp9l"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "markdown",
      "source": [
        "Python functions are defined using the `def` keyword. For example:"
      ],
      "metadata": {
        "id": "NZjSQBW2y9cJ"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "def sign(x):\n",
        "    if x > 0:\n",
        "        return 'positive'\n",
        "    elif x < 0:\n",
        "        return 'negative'\n",
        "    else:\n",
        "        return 'zero'\n",
        "\n",
        "for x in [-1, 0, 1]:\n",
        "    print(sign(x))"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ywKmT6O5y-uG",
        "outputId": "818fbe11-398a-451c-a022-c796439df9ef"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "negative\n",
            "zero\n",
            "positive\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "We will often define functions to take optional keyword arguments, like this:"
      ],
      "metadata": {
        "id": "qUhK0qJVzFKj"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "def hello(name, upper=False):\n",
        "    if upper:\n",
        "        print('HELLO, {}!'.format(name.upper()))\n",
        "    else:\n",
        "        print('Hello, {}!'.format(name))\n",
        "\n",
        "hello('Bob')\n",
        "hello('Fred', upper=True)"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "B79FjTKYzHlW",
        "outputId": "ca637ba9-a99d-4ea7-fc52-0413df758955"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Hello, Bob!\n",
            "HELLO, FRED!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Classes\n",
        "\n",
        "Python is an object-oriented language. To create a class, use the `class` keyword. All classes have a built-in `__init__()` function which is executed at the beginning when the class is initiated (**constructor**). By the `__init__()` function we can assign values to object properties. An object can contain **methods** (function that belong to the object).\n",
        "\n",
        "The `self` parameter is a reference to the current instance of the class. `self` can be used to access variables and methods that belong to the class. It has to be the first parameter of any instance’s method in the class. You can use any other word instead of self but it is the most commonly used. The syntax for defining classes in Python is straightforward:"
      ],
      "metadata": {
        "id": "2x34OZYuzdEK"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "class Greeter:\n",
        "    # Constructor\n",
        "    def __init__(self, name):\n",
        "        self.name = name  # Create an instance variable\n",
        "\n",
        "    # Instance method\n",
        "    def greet(self, upper=False):\n",
        "        if upper:\n",
        "          print('HELLO, {}'.format(self.name.upper()))\n",
        "        else:\n",
        "          print('Hello, {}!'.format(self.name))\n",
        "\n",
        "g = Greeter('Fred')  # Construct an instance of the Greeter class\n",
        "g.greet()            # Call an instance method; prints \"Hello, Fred\"\n",
        "g.greet(upper=True)   # Call an instance method; prints \"HELLO, FRED!\""
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "lcLrMjsHzgwp",
        "outputId": "964e84c8-1d72-4020-95c1-9972453783ed"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "Hello, Fred!\n",
            "HELLO, FRED\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "Let's look at how **inheritance** works in Python through a simple example:"
      ],
      "metadata": {
        "id": "lk3NQD1m2vpS"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Base class\n",
        "class Robot:\n",
        "  def __init__(self, name):\n",
        "    self.name = name\n",
        "\n",
        "  def introduce(self):\n",
        "    print(f\"I am {self.name}, a generic robot.\")\n",
        "\n",
        "# Derived class\n",
        "class DeliveryRobot(Robot):\n",
        "  def __init__(self, name, payload):\n",
        "    super().__init__(name)\n",
        "    self.payload = payload\n",
        "\n",
        "  def deliver_package(self):\n",
        "    print(f\"{self.name} is delivering a package of {self.payload} kg.\")\n",
        "\n",
        "  # Method overriding\n",
        "  def introduce(self):\n",
        "    print(f\"I am {self.name}, a delivery robot.\")\n",
        "\n",
        "# Main program\n",
        "robot1 = Robot(\"Robo-1\")\n",
        "robot2 = DeliveryRobot(\"CarryBot\", 5)\n",
        "robot1.introduce()\n",
        "robot2.introduce()\n",
        "robot2.deliver_package()"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "aMG33P5J1mgP",
        "outputId": "69e6577c-30ec-422c-e631-404b4db1d492"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "I am Robo-1, a generic robot.\n",
            "I am CarryBot, a delivery robot.\n",
            "CarryBot is delivering a package of 5 kg.\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "What does this example demonstrate? Robot is the base class (parent class).\n",
        "DeliveryRobot is a derived class (child class) that inherits attributes and methods from Robot.\n",
        "\n",
        "The `super().__init__(name)` call invokes the constructor of the base class, allowing the child class to reuse its initialization code.\n",
        "The `introduce()` method is overridden in DeliveryRobot, demonstrating method overriding in inheritance. The `deliver_package()` method is defined only in the derived class, showing how a child class can add new functionality.\n",
        "\n",
        "The example illustrates the \"is-a\" relationship: a DeliveryRobot is a Robot, but it also has additional capabilities specific to delivery tasks."
      ],
      "metadata": {
        "id": "7qX0lMyH1ktz"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Example codes\n",
        "\n",
        "### Multiplication table\n",
        "\n",
        "The goal of this exaple is to write a multiplication table program. The program asks the user which table to generate and show the appropriate table on the screen."
      ],
      "metadata": {
        "id": "hwdDWys8_5Mz"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "print(\"This program calculates times table\")\n",
        "\n",
        "# Read the table number from the user:\n",
        "tablenum = input(\"\\nWhich multiplication table shall I generate for you?\")\n",
        "\n",
        "# Convert tablenum to int:\n",
        "tablenum = int(tablenum)\n",
        "\n",
        "# Generate and print out the appropriate table in a for loop:\n",
        "print(\"\\nHere is your\", tablenum, \"times table:\\n\")\n",
        "\n",
        "for i in range(1, 11):\n",
        "\tprint(i, \"times\", tablenum, \"is\", i * tablenum)\n",
        "\tprint(\"------------------\")\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "SROBgNxPATsn",
        "outputId": "81c0ca51-e24c-4cba-cb2d-abfb7a57c815"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "This program calculates times table\n",
            "\n",
            "Which multiplication table shall I generate for you?3\n",
            "\n",
            "Here is your 3 times table:\n",
            "\n",
            "1 times 3 is 3\n",
            "------------------\n",
            "2 times 3 is 6\n",
            "------------------\n",
            "3 times 3 is 9\n",
            "------------------\n",
            "4 times 3 is 12\n",
            "------------------\n",
            "5 times 3 is 15\n",
            "------------------\n",
            "6 times 3 is 18\n",
            "------------------\n",
            "7 times 3 is 21\n",
            "------------------\n",
            "8 times 3 is 24\n",
            "------------------\n",
            "9 times 3 is 27\n",
            "------------------\n",
            "10 times 3 is 30\n",
            "------------------\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Oversimplified chatbot\n",
        "\n",
        "Now you will create an oversimplified chatbot program. The program reads sentences from the user and tries to respond *\"relevant\"* sentences."
      ],
      "metadata": {
        "id": "nsMXmRvkA-Sn"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Import the random module:\n",
        "import random\n",
        "\n",
        "# Create a list with random replies:\n",
        "random_replies = [\"Oh really?\", \"Are you sure about that?\", \"Perhaps…\", \"I don’t think so\"]\n",
        "\n",
        "# Create a chat dictionary:\n",
        "chat_dict = {\"happy\": \"I’am happy today too\", \"sad\": \"Be happy, life is good\", \"computer\": \"Computers will take over the world!\"}\n",
        "\n",
        "# Define a function which performs the following tasks:\n",
        "# Convert the message to lowercase\n",
        "# Spilt the message into words\n",
        "# If a word of the message is inside the keys of the dictionary, add the value (sentence) to the smart_replies list\n",
        "# If the replies list is not empty return with a randomly selected item, else return with an empty string\n",
        "\n",
        "def dictionary_check(message):\n",
        "  message = message.lower()\n",
        "  words = message.split()\n",
        "  smart_replies = []\n",
        "\n",
        "  for word in words:\n",
        "    if word in chat_dict:\n",
        "      answer = chat_dict[word]\n",
        "      smart_replies.append(answer)\n",
        "\n",
        "  if smart_replies:\n",
        "    selected_indx = random.randint(1, len(smart_replies)) - 1\n",
        "    return smart_replies[selected_indx]\n",
        "  else:\n",
        "    return \"\"\n",
        "\n",
        "# Implement the conversation cycle which is stay alive while the user is not saying “bye”.\n",
        "# In the cycle the software reads message from the user and it responds with a “smart”\n",
        "# or random response depending on the content of the message\n",
        "print(\"What would you like to talk about?\")\n",
        "user_says = \"\"\n",
        "\n",
        "while user_says != \"bye\":\n",
        "\tuser_says = \"\"\n",
        "\twhile user_says == \"\":\n",
        "\t\tuser_says = input(\"Talk to me: \")\n",
        "\tresponse = dictionary_check(user_says)\n",
        "\tif response:\n",
        "\t\tprint(response)\n",
        "\telse:\n",
        "\t\treply_chosen = random.randint (1, len(random_replies)) - 1\n",
        "\t\tprint(random_replies[reply_chosen])\n",
        "\t\trandom_replies[reply_chosen] = user_says\n",
        "print(\"Goodbye. Thanks for chatting today!\")\n"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "DRpHlPhmDPnT",
        "outputId": "43634662-277c-48a5-c391-86818f03916b"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "What would you like to talk about?\n",
            "Talk to me: i am happy\n",
            "I’am happy today too\n",
            "Talk to me: hello\n",
            "Perhaps…\n",
            "Talk to me: bye\n",
            "Are you sure about that?\n",
            "Goodbye. Thanks for chatting today!\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "### CurrentWeather class\n",
        "\n",
        "In this example you will create a class called *CurrentWeather* that holds information about the weather in different cities."
      ],
      "metadata": {
        "id": "jquwi6ifMAuE"
      }
    },
    {
      "cell_type": "code",
      "source": [
        "# Implement the CurrentWeather class\n",
        "class CurrentWeather:\n",
        "  weather_data={'Toronto':['13','partly sunny','8 km/h NW'],\n",
        "                'Montreal':['16','mostly sunny','22 km/h W'],\n",
        "                'Vancouver':['18','thunder showers','10 km/h NE'],\n",
        "                'New York':['17','mostly cloudy','5 km/h SE'],\n",
        "                'Los Angeles':['28','sunny','4 km/h SW'],\n",
        "                'London':['12','mostly cloudy','8 km/h NW'],\n",
        "                'Mumbai':['33','humid and foggy','2 km/h S'] }\n",
        "\n",
        "  def __init__(self, city):\n",
        "    self.city = city\n",
        "\n",
        "  def get_temperature(self):\n",
        "    return self.weather_data[self.city][0]\n",
        "\n",
        "  def get_weather_conditions(self):\n",
        "    return self.weather_data[self.city][1]\n",
        "\n",
        "  def get_wind_speed_and_dir(self):\n",
        "    return self.weather_data[self.city][2]\n",
        "\n",
        "  def get_city(self):\n",
        "    return self.city"
      ],
      "metadata": {
        "id": "BYKJlTRxMGXP"
      },
      "execution_count": null,
      "outputs": []
    },
    {
      "cell_type": "code",
      "source": [
        "# Create and object from the class\n",
        "weather = CurrentWeather('London')\n",
        "\n",
        "# Call all of the 3 methods of the object one by one\n",
        "print(weather.get_temperature())\n",
        "print(weather.get_weather_conditions())\n",
        "print(weather.get_wind_speed_and_dir())"
      ],
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "ld7Sy-PuMnMk",
        "outputId": "b65ab5b9-ae79-464f-8d4e-873737ca5d2c"
      },
      "execution_count": null,
      "outputs": [
        {
          "output_type": "stream",
          "name": "stdout",
          "text": [
            "12\n",
            "mostly cloudy\n",
            "8 km/h NW\n"
          ]
        }
      ]
    },
    {
      "cell_type": "markdown",
      "source": [
        "## Exercises\n",
        "\n",
        "### Exercise 1\n",
        "\n",
        "Modify the \"multiplication table\" program to show only the odd lines until line 13 in the table! (1p)"
      ],
      "metadata": {
        "id": "OwD6kFUfAvBA"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Exercise 2\n",
        "\n",
        "The sample code of the oversimplified chatbot contains an error. After you type the *bye* command, the programcode prints out a random respone. Fix this bug so that no response is displayed after the user enters the *bye* command. (1p)"
      ],
      "metadata": {
        "id": "ulpmlyNhA97z"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Exercise 3\n",
        "\n",
        "Extend the *CurrentWeather* class with an additional method (its name be: *get_wind_speed*) which prints out the wind speed of the city without the wind direction (e.g. 8 km/h without NW)! (1p)"
      ],
      "metadata": {
        "id": "tyDNxybLNj2A"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Exercise 4\n",
        "\n",
        "Write a Python function which uses a loop to print out the first 10 *Fibonacci numbers* (0, 1, 1, 2, 3, 5, 8, 13, 21, 34). In mathematical terms the sequence $f_n$ of *Fibonacci numbers* is defined by the recurrent relation (seed values are $f_0 = 0, f_1 = 1$):\n",
        "\n",
        "$$f_n = f_{n-1} + f_{n-2}$$\n",
        "(1p)\n"
      ],
      "metadata": {
        "id": "Il3oRiPwInJt"
      }
    },
    {
      "cell_type": "markdown",
      "source": [
        "### Exercise 5\n",
        "Suppose that you have a silly robot which can communicate with *Morse codes* and you received the following message. <br>\n",
        ". -- -... . -.. -.. . -.. / ... -.-- ... - . -- ...  \n",
        "\n",
        "Write a function to decode the message into human readable format. (2p)"
      ],
      "metadata": {
        "id": "px8VPSYj3ner"
      }
    }
  ]
}