{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kFXKBXcHhro6"
      },
      "source": [
        "# CS 124 Tutorial: `Python` Review\n",
        "\n",
        "__Authors(s):__ `Dilara Soylu (Winter '21)`"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "kon_YiKko6tH"
      },
      "source": [
        "<a id='overview'></a>\n",
        "## Overview\n",
        "\n",
        "This tutorial assumes that you have completed the following from the \n",
        "[PA 0 repository](https://github.com/cs124/pa0-python-jupyter-tutorial):\n",
        "* Setup instructions for your machine\n",
        "* [Jupyter Notebook Tutorial](https://github.com/cs124/pa0-python-jupyter-tutorial/blob/main/jupyter_tutorial.ipynb)\n",
        "\n",
        "We use `Python` for all of our programming assignments in `CS 124`. \n",
        "In this tutorial, we will cover all the things you need to know in `Python` to \n",
        "be able to work on our assignments.\n",
        "We recommend quickly skimming through all parts of this tutorial to ensure that \n",
        "you are familiar with all `Python` tips that can be useful when working on the \n",
        "assignments, even if you are already comfortable with `Python`.\n",
        "Feel free to adjust the amount of time you spend on each section based on your \n",
        "familiarity level!\n",
        "Try to get yourself familiar with the contents of this tutorial, but don't fret \n",
        "if some concepts aren't clear or if you can't remember some of the syntax.\n",
        "We have prepared this tutorial to be a reference for you throughout the quarter,\n",
        "so feel free to come back whenever you need a refresher.\n",
        "\n",
        "This tutorial was adapted from the\n",
        "[CS 221 Python Tutorial (Spring 2021)](https://colab.research.google.com/drive/1-9Z_dLRJBWZdKaMNLqBMF9TrXc1553IK?usp=sharing) by `Dilara Soylu`. \n",
        "Original version largely based on the \n",
        "[CS 224N Python Tutorial (Winter 2021)](http://web.stanford.edu/class/cs224n/readings/cs224n-python-review-code-updated.zip) by `Angelica Sun`, as well as the \n",
        "[W3Schools Python Tutorial](https://www.w3schools.com/python/)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Q4AmK8urNZ7t"
      },
      "source": [
        "<a id='contents'></a>\n",
        "## Contents\n",
        "\n",
        "1. [Running Python](#running_python)\n",
        "    * [Python Interpreter](#python_interpreter)\n",
        "    * [Running `.py` Files](#running_py_files)\n",
        "    * [Troubleshooting Version Errors](#troubleshooting_version_errors)\n",
        "2. [Syntax](#syntax)\n",
        "3. [Variables](#variables)\n",
        "4. [Basic Data Types and Operations](#basic_data_types_and_operations)\n",
        "    * [Numbers](#numbers)\n",
        "    * [Booleans](#booleans)\n",
        "    * [Strings](#strings)\n",
        "5. [Iterables](#iterables)\n",
        "    * [List](#list)\n",
        "    * [Tuple](#tuple)\n",
        "    * [Dictionary](#dictionary), [DefaultDict](#defaultdict), \n",
        "      [Counter](#counter), [Set](#set)\n",
        "    * [Sorting](#sorting)\n",
        "    * [List Comprehensions](#list_comprehensions), \n",
        "      [Dictionary and Set Comprehensions](#dictionary_and_set_comrehensions)\n",
        "    * [Copying Data Structures](#copying_data_structures)\n",
        "6. [Control Flow](#control_flow)\n",
        "    * [If Condition](if_condition)\n",
        "    * [For Loop](#for_loop)\n",
        "    * [While Loop](#while_loop)\n",
        "7. [Functions](#functions)\n",
        "8. [Classes](#classes)\n",
        "9. [Next Steps](#next_steps)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "g5MyzBMeo6tW"
      },
      "source": [
        "<a id='running_python'></a>\n",
        "## Running `Python`\n",
        "\n",
        "In `CS 124`, all of the coding work you need to do will be in `Jupyter Notebook`\n",
        "except for the last assignment.\n",
        "That is, you will run `Python` code by running notebook cells in the \n",
        "assignments.\n",
        "`Jupyter Notebook Tutorial` linked at the top of this notebook explains \n",
        "notebooks in further detail.\n",
        "In this section, we touch on the other ways you may run `Python`. "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0QN6t9zwOmBg"
      },
      "source": [
        "<a id='python_interpreter'></a>\n",
        "### `Python` Interpreter\n",
        "\n",
        "Just like any other programming language, we can also run `Python` through the \n",
        "terminal.\n",
        "You do not need to work with this until the very last assignment, but we are \n",
        "sharing it here for completeness."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DPrd-lN6UVqK"
      },
      "source": [
        "You can start the `Python` interpreter by typing the following command in your \n",
        "terminal:\n",
        "```\n",
        "python\n",
        "```\n",
        "\n",
        "Once you run this command, you will see an output similar to the one shared \n",
        "below:\n",
        "```\n",
        "Python 3.8.5 (default, Sep  4 2020, 02:22:02) \n",
        "[Clang 10.0.0 ] :: Anaconda, Inc. on darwin\n",
        "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n",
        ">>> \n",
        "```\n",
        "\n",
        "You can use this interactive terminal to run `Python` code, which is useful if \n",
        "you want to quickly test things out. \n",
        "Here is an example of how we could use this interactive terminal:\n",
        "```\n",
        "Python 3.8.5 (default, Sep  4 2020, 02:22:02) \n",
        "[Clang 10.0.0 ] :: Anaconda, Inc. on darwin\n",
        "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n",
        ">>> a = 5\n",
        ">>> a\n",
        "5\n",
        "```\n",
        "\n",
        "To exit this interactive terminal, you can type `exit()`! Pay attention to the \n",
        "paranthesis!"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "runUgO8YRZq8"
      },
      "source": [
        "<a id='running_py_files'></a>\n",
        "### Running `.py` Files\n",
        "\n",
        "You can also run files containing `Python` code.\n",
        "This is what we will do in the last assignment!\n",
        "These files usually end with the `.py` extension, but this is not a strict \n",
        "requirement, `python` will run whatever file you tell it to run, regardless of \n",
        "the file extension."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pz5eTebzUZnE"
      },
      "source": [
        "Assume that we have a file named `example.py`, which contains the following:\n",
        "```\n",
        "print(\"Hello World!\")\n",
        "```\n",
        "We can run this file using the following command:\n",
        "```\n",
        "python example.py\n",
        "```\n",
        "which will print the following in our terminal:\n",
        "```\n",
        "Hello World!\n",
        "```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Td5D2VALUNmC"
      },
      "source": [
        "<a id='troubleshooting_version_errors'></a>\n",
        "### Troubleshooting Version Errors\n",
        "\n",
        "One common error you may run into when running `Python` files this way is using \n",
        "the wrong `Python` installation on your machine!\n",
        "This is likely the underlying problem if you ever find yourself getting \n",
        "`Import Error` errors (e.g. `Import Error: No module named numpy`)."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2IfxO_KgqcGM"
      },
      "source": [
        "For our assignments, we always want to run the `Python` in the `cs124` `conda` \n",
        "environment."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "n-ZvqbwZOgEQ"
      },
      "source": [
        "The following command lets you figure out which `Python` is called when you run \n",
        "the `python` command in your terminal:\n",
        "```\n",
        "which python\n",
        "```\n",
        "If you are in the `cs124` `conda` environment, you will see an output similar to\n",
        "the following, which will vary based on your machine:\n",
        "```\n",
        "/Users/username/.miniconda3/miniconda3/envs/cs124/bin/python\n",
        "```\n",
        "If you instead get an output that looks like the following:\n",
        "```\n",
        "/usr/bin/python\n",
        "```\n",
        "It likely means that you have not activated our `conda` environment!\n",
        "\n",
        "`which python` command only runs in the terminal.\n",
        "To figure out which version of `Python` your notebook is running, you can create\n",
        "a code cell, and run the following:\n",
        "```\n",
        "!which python\n",
        "```\n",
        "The `!` mark at the beginning of the line tells `Jupyter Notebook` to run this\n",
        "command in the terminal.\n",
        "Try it in the cell below!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "4Yw6ZFfiSrZx",
        "outputId": "68f1b292-99fb-43a7-a9fe-0015baf2aeea"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "/usr/local/bin/python\n"
          ]
        }
      ],
      "source": [
        "!which python"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BWPzE4fvUdDh"
      },
      "source": [
        "<a id='syntax'></a>\n",
        "## Syntax\n",
        "\n",
        "Let's start coding in `Python` with the famous `Hello World` exercise. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "bS-2lFSmRicu",
        "outputId": "0b32097b-ef9f-4067-9513-32456d000ca0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Hello World!\n"
          ]
        }
      ],
      "source": [
        "# Printing Hello World!\n",
        "print(\"Hello World!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SKPRPmIJTWD0"
      },
      "source": [
        "You have succesfully printed out `Hello World`, which means you are now a \n",
        "`Python` programmer!\n",
        "Let's learn about a few other important syntax tidbits in `Python`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vjn8VQNnWJC7"
      },
      "source": [
        "Unlike the other programming languages that you may be familiar with, \n",
        "indentation matters in `Python`.\n",
        "Lines of code that are in the same block of code should be indented with the \n",
        "same number of spaces."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 134
        },
        "id": "Ly6ZxRUCTVbd",
        "outputId": "b6be53b0-b078-4b8b-89c2-9e347668107b"
      },
      "outputs": [
        {
          "ename": "IndentationError",
          "evalue": "ignored",
          "output_type": "error",
          "traceback": [
            "\u001b[0;36m  File \u001b[0;32m\"<ipython-input-5-de16869d016e>\"\u001b[0;36m, line \u001b[0;32m3\u001b[0m\n\u001b[0;31m    print(\"Hello World!\")\u001b[0m\n\u001b[0m    ^\u001b[0m\n\u001b[0;31mIndentationError\u001b[0m\u001b[0;31m:\u001b[0m unexpected indent\n"
          ]
        }
      ],
      "source": [
        "# Example of an Indentation Error\n",
        "print(\"Hello\")\n",
        "    print(\"Hello World!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9FsiH-Z4Ul3c"
      },
      "source": [
        "You can use line comments or block comments to comment code in `Python`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "xbl9Q9ECUlTW",
        "outputId": "10b545c1-6ef8-4168-a142-9d006dd7d9c5"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Hi!\n"
          ]
        }
      ],
      "source": [
        "# Line comment\n",
        "\n",
        "\"\"\"\n",
        "Block comment\n",
        "\"\"\"\n",
        "\n",
        "print(\"Hi!\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_OjFuFSXSf4M"
      },
      "source": [
        "As you may remember from the `Jupyter Notebook Tutorial`, `Jupyter Notebook` \n",
        "automatically prints the value of the variable in the last line of a code cell,\n",
        "so we don't need to call `print`. \n",
        "We will stick to using `print` for some of our examples in the remaining of this\n",
        "notebook to make our intent clear."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 36
        },
        "id": "3TdgBOQ5SfSi",
        "outputId": "f959a60a-da30-48b1-926c-4e50a6e0c16e"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            },
            "text/plain": [
              "'Hi'"
            ]
          },
          "execution_count": 2,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "\"Hi\""
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0ObB8VtCUEsP"
      },
      "source": [
        "<a id='variables'></a>\n",
        "## Variables\n",
        "\n",
        "In `Python`, variables are defined by assigning value to them.\n",
        "There is no need to explicitly declare the type of a variable.\n",
        "Function `type()` below returns the type of the passed in variable.\n",
        "When we print the output of the `type()` function, we get a string \n",
        "representation of an object's type.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "wZFgDcM4o6te",
        "outputId": "2ab24612-fa6b-44af-8fa3-832972fe75eb"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<class 'str'>\n",
            "<class 'int'>\n",
            "<class 'float'>\n",
            "<class 'bool'>\n",
            "<class 'bool'>\n",
            "<class 'tuple'>\n",
            "<class 'list'>\n",
            "<class 'NoneType'>\n"
          ]
        }
      ],
      "source": [
        "var1 = 'hello' # str, immutable\n",
        "var2 = 10      # int, immutable\n",
        "var3 = 10.0    # float, immutable\n",
        "var4 = True    # bool, immutable\n",
        "var5 = False   # bool, immutable\n",
        "var6 = (8,9)   # tuple, immutable\n",
        "var7 = [1,2,3] # list, mutable     \n",
        "var8 = None    # None     \n",
        "\n",
        "print(type(var1)) \n",
        "print(type(var2)) \n",
        "print(type(var3)) \n",
        "print(type(var4)) \n",
        "print(type(var5)) \n",
        "print(type(var6))\n",
        "print(type(var7))\n",
        "print(type(var8)) "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9No4YfGQXiNd"
      },
      "source": [
        "Similar to other programming languages, the values of the `immutable` types \n",
        "cannot be changed after initialization in `Python`. \n",
        "For example, while we can change the values of the individual elements in a \n",
        "`list` in `Python`, we can't change an element of a `tuple`, which are \n",
        "`immutable`.\n",
        "We will cover each of these types in more detail in the following sections, \n",
        "so no need to fully understand them now."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b5bFUVlGV2IH"
      },
      "source": [
        "We can re-assign a variable name to a different type."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "zYyhlcEJV6RK",
        "outputId": "2014fbda-62fd-4ab8-bf44-b1c5d2a98a05"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<class 'str'>\n",
            "<class 'int'>\n"
          ]
        }
      ],
      "source": [
        "var = \"Hi CS 124!\"\n",
        "print(type(var)) \n",
        "\n",
        "var = 10\n",
        "print(type(var))  "
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pXsTTdxhXczT"
      },
      "source": [
        "We can cast variables to different types."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "sDtG68Vqo6tf",
        "outputId": "7d368cbe-c1ce-480f-d8c5-167adda016ef"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "10 <class 'int'>\n",
            "10 <class 'str'>\n",
            "10 <class 'int'>\n",
            "10.0 <class 'float'>\n"
          ]
        }
      ],
      "source": [
        "a = 10       # int\n",
        "b = str(a)   # int to str\n",
        "c = int(b)   # str to int\n",
        "d = float(c) # int to float\n",
        "\n",
        "print(a, type(a))\n",
        "print(b, type(b))\n",
        "print(c, type(c))\n",
        "print(d, type(d))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "d88q8KFiYkU5"
      },
      "source": [
        "Variable names are sensitive to case. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Z35h7buwYnkK",
        "outputId": "75648494-f1e1-4ef7-c5b5-87367779dbd7"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "False\n"
          ]
        }
      ],
      "source": [
        "a = 10\n",
        "A = \"CS 124\"\n",
        "print(a == A)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EQ9WzOLpY7D5"
      },
      "source": [
        "We can assign values to multiple variables in one line."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "CgTUIBXKY-K8",
        "outputId": "c7618f9a-036e-44e2-a532-06328a2145e3"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "I\n",
            "love\n",
            "CS 124\n"
          ]
        }
      ],
      "source": [
        "a, b, c = \"I\", \"love\", \"CS 124\"\n",
        "print(a)\n",
        "print(b)\n",
        "print(c)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AJjUP9Laac2E"
      },
      "source": [
        "We can also print multiple variables in one `print` statement by seperating \n",
        "them with a comma.\n",
        "The `print()` function combines the variables we passed in with a `space` in \n",
        "between."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "_GZ7VQXEaelm",
        "outputId": "37357775-22fc-4670-8196-632bbf164e06"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "I love CS124\n"
          ]
        }
      ],
      "source": [
        "a, b, c = \"I\", \"love\", \"CS124\"\n",
        "print(a, b, c)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-0VvJlmoTktD"
      },
      "source": [
        "In `Python`, the conventional wisdom is to name variables using numbers and \n",
        "lowercase letters, using `_` for variable names containing multiple parts.\n",
        "`Python` variable names cannot start with numbers."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 36
        },
        "id": "XyN6RwZHaq07",
        "outputId": "7f80c028-96e6-499a-ac44-c424c9e59bfb"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            },
            "text/plain": [
              "'February 21, 2021'"
            ]
          },
          "execution_count": 44,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "important_date1 = 'February 21, 2021'\n",
        "important_date1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Qe-XMYLVb2Wn"
      },
      "source": [
        "Some words in `Python` refer to special built-in functions or classes.\n",
        "Although `Python` lets you use these as variable names, we recommend avoiding \n",
        "doing so to prevent errors and make your program more readible to others!\n",
        "Common ones you may want to avoid are as follows, though a complete list can be \n",
        "found in the \n",
        "[Built-in Functions](https://docs.python.org/3/library/functions.html) page of \n",
        "the official `Python` documentation (navigate to your version of `Python`):\n",
        "```\n",
        "bool, chr, dict, id, list, map, object, str, vars\n",
        "```\n",
        "\n",
        "We show what happens when we override a built-in class below."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "K5Vyjv-vTxo7",
        "outputId": "0f50f3f0-ee8a-4bf6-9efa-0985978036b7"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<built-in function abs>\n",
            "1.0\n"
          ]
        }
      ],
      "source": [
        "# abs is a built-in function returning the absolute value of a number\n",
        "print(abs)\n",
        "print(abs(-1.0))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "JXX5X758Tndf",
        "outputId": "62282dcb-4c36-43a2-953f-e47f3e058e41"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<class 'float'>\n",
            "1.0\n"
          ]
        }
      ],
      "source": [
        "# Let's see what happens when we use abs as a variable name\n",
        "num = -1.0\n",
        "abs = 1.0\n",
        "print(type(abs))\n",
        "print(abs)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 189
        },
        "id": "aQdTppowVYzL",
        "outputId": "3f205370-2db5-4848-d9ed-0d9c223cf054"
      },
      "outputs": [
        {
          "ename": "TypeError",
          "evalue": "ignored",
          "output_type": "error",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-30-0d192fa8a76c>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0;31m# Let's try to use the abs function again!\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0mabs\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m-\u001b[0m\u001b[0;36m1.0\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# TypeError\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mTypeError\u001b[0m: 'float' object is not callable"
          ]
        }
      ],
      "source": [
        "# Let's try using the abs function again!\n",
        "abs(-1.0) # TypeError"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v-rp6VjPVl_3"
      },
      "source": [
        "We have got a `TypeError` when we tried to use `abs` as a function after using \n",
        "it as a variable name earlier.\n",
        "We can use the `del` statement in `Python` to delete our newly created variable\n",
        "from `Python's` memory, which will let `Python` to re-bind `abs` to the \n",
        "built-in function.\n",
        "You will get an error if you run the below cell for a second time, as at that \n",
        "point `Python` will hopelessly try to find a variable named `abs`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "woEtXaW7Vli-",
        "outputId": "26ca5892-5ddb-4881-9e9d-456e4f46a4fd"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "1.0"
            ]
          },
          "execution_count": 31,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "del abs\n",
        "abs(-1.0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TvWykyl2TCcs"
      },
      "source": [
        "Overriding the built in functions is especially tempting when you want to \n",
        "create the list variable you define as `list`.\n",
        "The `id` function is another common example that can be a tempting variable \n",
        "name.\n",
        "We recommend being more descriptive when coming up with variable names, or \n",
        "using generic ones such as `alist`, `atuple`, and `adict` if the variable is \n",
        "defined as an intermediary step."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "OMnKTXY5Xgpc"
      },
      "source": [
        "**Fun Fact:** `Python` stores the value of the last assigned variable in a variable named `_`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "MP9lwAXjTB7J",
        "outputId": "94063412-4ccc-4a03-df07-e7b823861f55"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "1.0"
            ]
          },
          "execution_count": 33,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "_"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "vFdv2IzgYKmE"
      },
      "source": [
        "You will also see people using `_` as a placeholder for unimportant values.\n",
        "This part will become clearer in the `Loops` and `Tuples` sections."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Oe-gc16RYpUt",
        "outputId": "73ba6574-76ef-4cb2-8c2c-86b8493dfcf8"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "('important', 'also important')"
            ]
          },
          "execution_count": 34,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "_, a, b = \"not important\", \"important\", \"also important\"\n",
        "a, b"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rbz2BTcprK6q"
      },
      "source": [
        "<a id='basic_data_types_and_operations'></a>\n",
        "## Basic Data Types and Operations\n",
        "\n",
        "In this section, we cover basic data types and operations defined on them."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GeHeASLcZpcu"
      },
      "source": [
        "<a id='numbers'></a>\n",
        "### Numbers\n",
        "\n",
        "In `Python`, numbers can be integers or floats.\n",
        "Following operations are defined on numbers."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "V5sP_1QQba1U",
        "outputId": "f4e1c53b-b821-4793-e417-38bb590fde3e"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "14\n",
            "6\n",
            "40\n",
            "10000\n",
            "2.5\n",
            "2\n",
            "2\n"
          ]
        }
      ],
      "source": [
        "num = 10\n",
        "print(num + 4)      # Add with +\n",
        "print(num - 4)      # Subtract with -\n",
        "print(num * 4)      # Multiply with *\n",
        "print(num ** 4)     # Exponentiate with **\n",
        "print(num / 4)      # Float division with / \n",
        "print(num // 4)     # Integer division with //\n",
        "print(int(num / 4)) # Integer division is the same as dividing then casting"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wjSXnKMtcS1I"
      },
      "source": [
        "We can convert an operator to a compounding operator by appending `=` to it."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "l304SQEdcSIn",
        "outputId": "5d067a0d-c9b6-42c2-89c1-1cdfa7a5b865"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "10000"
            ]
          },
          "execution_count": 174,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "num **= 4\n",
        "num"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QdRPxxY2sd_g"
      },
      "source": [
        "You may be used to seeing increment (`++`) and decrement (`--`) operators in \n",
        "other languages.\n",
        "In `Python`, we use the compounding operators to increment or decrement."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "4_d5vlWNiBke",
        "outputId": "6d1f5898-93ea-462f-968c-47b2354cc9a2"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "10001\n",
            "10000\n"
          ]
        }
      ],
      "source": [
        "num += 1\n",
        "print(num)\n",
        "\n",
        "num -= 1\n",
        "print(num)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3lAn5GMjvGsM"
      },
      "source": [
        "If called without arguments, `int` and `float` constructors are passed `0` \n",
        "as the default argument."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "biMxQftGvFsS",
        "outputId": "8c787835-69df-45e5-8cce-d883322417d2"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(0, 0.0)"
            ]
          },
          "execution_count": 56,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "int(), float()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NTSog3DUco7f"
      },
      "source": [
        "<a id='booleans'></a>\n",
        "### Booleans\n",
        "\n",
        "Boolean literals in `Python` are `True` and `False`.\n",
        "Logical operations in `Python` use plain English: `not`, `and`, and `or`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "aP6-LpBIo6tj",
        "outputId": "420acdab-3d09-4328-bda7-c0d9f3bfd21c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "False\n",
            "False\n",
            "True\n"
          ]
        }
      ],
      "source": [
        "print(True)           # True\n",
        "print(False)          # False\n",
        "print(not True)       # False\n",
        "print(True and False) # False\n",
        "print(True or False)  # True"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DjDQFW7bdclb"
      },
      "source": [
        "To check for value equality or inequality, we use `==` or `!=`, respectively."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "iHCGui23difG",
        "outputId": "60c806d2-86c4-4665-a9d2-fbb6cf2c063c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "True\n"
          ]
        }
      ],
      "source": [
        "a, b = \"124\", \"124\"\n",
        "print(a == b)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "gAuI_ZY2wu57"
      },
      "source": [
        "You can also use `is` to check whether two variables are pointing to the same \n",
        "`Python` object.\n",
        "Even though they are initialized to be the same text, two long enough string \n",
        "variables often times don't point to the same object in `Python`.\n",
        "Variables that have primitive values, such as `True`, `None` or `1`, point to \n",
        "the same `Python` object, so comparing them using `is` will return `True`.\n",
        "If your intent is to check value equality for generic `Python` objects, use \n",
        "`==`.\n",
        "You can use `is` or `is not` when checking if a variable's value is `None`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "jXQuViRhxg-s",
        "outputId": "78df1921-a390-4ed2-b278-e4b6d9b31772"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "False\n",
            "True\n",
            "True\n"
          ]
        }
      ],
      "source": [
        "a1, b1 = 'Hello!', 'Hello!'\n",
        "a2, b2 = 1, 1\n",
        "a3, b3 = None, None\n",
        "\n",
        "print(a1 is b1) # False\n",
        "print(a2 is b2) # True\n",
        "print(a3 is b3) # True"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "9z0wa6SweCIO"
      },
      "source": [
        "Operations `>=` and `<=` can be used to compare `Python` variables, when the \n",
        "order is defined for the classes that are being compared.\n",
        "If you are extra curious, you can refer to this \n",
        "[link](https://www.geeksforgeeks.org/sorting-objects-of-user-defined-class-in-python/)\n",
        "to learn how to define order for user defined classes."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "2LJGhoBQeHd0",
        "outputId": "4213331a-be5c-452f-c7ec-5b8a168b9ed4"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "True\n"
          ]
        }
      ],
      "source": [
        "a, b = 6, 8\n",
        "print(b >= a)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hwzjLcqTzEhQ"
      },
      "source": [
        "We can use the `bool()` constructor to cast variables or literals to their \n",
        "boolean values.\n",
        "Let's look into __truthiness__ and __falseness__ of different values using the \n",
        "`bool()` function."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "IVSjqN-HztfP",
        "outputId": "efc9dafe-24b3-4232-e13c-52983fea6da5"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "True\n",
            "False\n",
            "True\n",
            "True\n",
            "True\n",
            "True\n",
            "False\n"
          ]
        }
      ],
      "source": [
        "b1 = bool(True)  # Boolean value of True is True\n",
        "b2 = bool(False) # Boolean value of False is False\n",
        "b3 = True == 1   # True is equivalent to 1 in Python\n",
        "b4 = False == 0  # False is equivalent to 0 in Python\n",
        "b5 = bool(8)     # Boolean value of any non-zero number is True\n",
        "b6 = bool(-1)    # ^\n",
        "b7 = bool(None)  # Boolean value of None is False\n",
        "\n",
        "print(b1)\n",
        "print(b2)\n",
        "print(b3) \n",
        "print(b4)\n",
        "print(b5)   \n",
        "print(b6)\n",
        "print(b7)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "p8Ae6E2g2Yyq"
      },
      "source": [
        "Knowing the truth values of variables will be important when we cover `lists` \n",
        "and `conditionals` in the following sections.\n",
        "The properties shared in the following cell will be especially important and we \n",
        "will revisit them."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "19JYbNtw2V2N",
        "outputId": "87d8eed4-9cca-4082-ae39-95faf55e0f60"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "False\n",
            "True\n"
          ]
        }
      ],
      "source": [
        "b8 = bool([])    # Boolean value of empty objects (e.g. empty list) are False\n",
        "b9 = bool([1,2]) # Boolean value of non-empty objects are True\n",
        "\n",
        "print(b8)   \n",
        "print(b9)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "SZ6GfhgOdQz5"
      },
      "source": [
        "<a id='strings'></a>\n",
        "### Strings\n",
        "\n",
        "We have seen examples of using equality operators with strings in the `Booleans`\n",
        "section.\n",
        "We can check if a string comes after another one alphabetically."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "PcOTYaQw7CqW",
        "outputId": "0b689af2-4266-416f-ee34-3cc81a330ac8"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "True"
            ]
          },
          "execution_count": 152,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "a, b = 'a', 'b'\n",
        "a < b"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WL3TFqR5e-ux"
      },
      "source": [
        "Listed below are some other important operations we can do on strings."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "1W1ORPaLfDul",
        "outputId": "d503d086-3494-4da9-9049-14d0c8284fa2"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "14\n",
            "i\n",
            "love\n",
            "i love CS124! How about you?\n",
            "i love CS124! i love CS124! i love CS124! i love CS124! \n",
            "i love cs124! \n",
            "I LOVE CS124! \n",
            "I love cs124! \n",
            "i love CS124!!\n"
          ]
        }
      ],
      "source": [
        "a = \"i love CS124! \"\n",
        "b = \"How about you?\"\n",
        "\n",
        "print(len(a))         # get length of a string\n",
        "print(a[0])           # index a string\n",
        "print(a[2:6])         # get a substring from a string: [start_index, end_index)\n",
        "                      # other indexing conventions covered in the lists section\n",
        "print(a + b)          # concatenate string\n",
        "print(a * 4)          # concatenate a string n times\n",
        "print(a.lower())      # lower characters in a string\n",
        "print(a.upper())      # capitalize characters in a string\n",
        "print(a.capitalize()) # capitalize the first character a string\n",
        "print(a.strip()+'!')  # strip leading and trailing whitespace in a string\n",
        "# a[0] = 'I'          # we can't re-assign to a string: strings are immutable"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "xJ70cyhEB7YK",
        "outputId": "c4a9a603-62bb-41f4-e2d5-cce13d60baba"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "True\n",
            "False\n",
            "2\n"
          ]
        }
      ],
      "source": [
        "print('love' in a)     # check if a substring exists in a string\n",
        "print('love' not in a) # check if a substring exists in a string\n",
        "print(a.index('love')) # get the start index of the 1st occurence of a substring"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lGD4FEI7iMM7"
      },
      "source": [
        "We can split a string and combine it back again using a delimiter."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "IlmNdwM1iN04",
        "outputId": "0861409e-1a71-446d-fa1f-ac686267b89f"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "['I', 'love', 'CS124!']\n",
            "['I love CS1', '4!']\n",
            "I-love-CS124!\n"
          ]
        }
      ],
      "source": [
        "a_splitted  = a.split()            # split on the default delimiter space\n",
        "a_splitted2 = a.split('2')         # split on '2'\n",
        "a_joined    = '-'.join(a_splitted) # join on '-'\n",
        "\n",
        "print(a_splitted)\n",
        "print(a_splitted2)\n",
        "print(a_joined)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "5BJLa8X-Dnnn"
      },
      "source": [
        "Sometimes we need to tell `Python` to interpret a character in a string in a \n",
        "special way.\n",
        "We use the the escape character, `\\`, for this purpose.\n",
        "We can also use `\\` to print special characters, such as a new line.\n",
        "What should we do to tell `Python` that `\\` should be a part of the string as \n",
        "well?\n",
        "We can use raw strings (`r-strings`), which are string literals starting with \n",
        "an `r`.\n",
        "\n",
        "**Fun Fact:** `print` function always adds a new line character at the end!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "OPa6Po4ZDnCD",
        "outputId": "6fb2d489-4095-4d97-d52c-25154f14112a"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This string contains a \" character!\n",
            "First line.\n",
            "Second line.\n",
            "C:\\users\\user1\\Documents\n"
          ]
        }
      ],
      "source": [
        "s1 = \"This string contains a \\\" character!\" # Escape \"\n",
        "s2 = \"First line.\\nSecond line.\"            # Add new line \\n\n",
        "s3 = r'C:\\users\\user1\\Documents'            # Create a raw string\n",
        "\n",
        "print(s1)\n",
        "print(s2)\n",
        "print(s3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "_eZIL5U6jJUj"
      },
      "source": [
        "We can put values of variables into strings using format strings (`f-strings`), \n",
        "which are string literals prepended with an `f`.\n",
        "This becomes especially handy when printing!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "VVZolJWRkJjR",
        "outputId": "17a3d22b-e5ca-4ea6-f7f0-b6df82fd3759"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Pi is 3.14159!\n"
          ]
        }
      ],
      "source": [
        "pi        = 3.14159\n",
        "pi_string = f\"Pi is {pi}!\"\n",
        "\n",
        "print(pi_string)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 36
        },
        "id": "ftkUo2kho6tk",
        "outputId": "3f8f655b-f2e2-410f-abaa-f53f7c929c3f"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            },
            "text/plain": [
              "'Pi is 3.14! If we round pi, we get 3.'"
            ]
          },
          "execution_count": 162,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# We can also use the % operator to format strings\n",
        "# (pi, pi) creates a tuple, which is covered in detail later\n",
        "pi_string = \"Pi is %.2f! If we round pi, we get %d.\" % (pi, pi)\n",
        "pi_string"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "62hiuhTe3pFe"
      },
      "source": [
        "Before we end our discussion on strings, let's take a second look at how \n",
        "trings are created in `Python`. \n",
        "In `Python` strings can be created by encapsulating text in `'`, or `\"`. \n",
        "We can also create strings by encapsulating text in triple single or double \n",
        "quotes (`'''` or `\"\"\"`).\n",
        "The triple versions let's us have strings spanning multiple lines unlike the \n",
        "others. \n",
        "You are free to use any of these when creating a string, but the conventional \n",
        "usage is as follows:\n",
        "* Use `'` when defining functional strings, such as `RegExes`, string literals, \n",
        "  etc.\n",
        "* Use `\"` when defining string variables that will be shown to an end user. \n",
        "* Use `\"\"\"` for strings spanning multiple lines."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "i-EFzJA7XhKg",
        "outputId": "30477b87-ff21-4edc-9423-181e068705de"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "a\n",
            "Hello user!\n"
          ]
        }
      ],
      "source": [
        "c = 'a'\n",
        "text = \"Hello user!\"\n",
        "\n",
        "print(c)\n",
        "print(text)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "nJ8OPh5G5Hq9",
        "outputId": "b43e1e68-30f2-47ad-9247-18f172563f97"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This is a multi line string.\n",
            "You will see new line characters in the output,\n",
            "corresponding to the line breaks here.\n"
          ]
        }
      ],
      "source": [
        "# We can define multi-line strings\n",
        "multi_line = \"\"\"This is a multi line string.\n",
        "You will see new line characters in the output,\n",
        "corresponding to the line breaks here.\"\"\"\n",
        "\n",
        "print(multi_line)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "okYSk1as6F4T",
        "outputId": "a62c36b9-57a5-4ebe-f589-50d336dd09b8"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This is a multi line string. You won't see new line characters in the output, because we have escaped them.\n"
          ]
        }
      ],
      "source": [
        "# We can escape line breaks with \\\n",
        "multi_line = \"\"\"This is a multi line string. \\\n",
        "You won't see new line characters in the output, \\\n",
        "because we have escaped them.\\\n",
        "\"\"\"\n",
        "\n",
        "print(multi_line)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cHNf9ssW6beI"
      },
      "source": [
        "It is also possible to write multi line strings using `'` or `\"`, using the `\\` \n",
        "character."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Qx7hqK-Co6tq"
      },
      "source": [
        "<a id='iterables'></a>\n",
        "## Iterables\n",
        "\n",
        "There are several different built-in iterable objects in `Python`. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "V3gtHrbdzkJD"
      },
      "outputs": [],
      "source": [
        "# immutable iterables, with fixed size\n",
        "astring = str()\n",
        "atuple = tuple()\n",
        "\n",
        "# mutable iterables, not fixed size\n",
        "alist = list()  # linear\n",
        "adict = dict()  # hash table, stores (key, value) pairs\n",
        "aset = set()    # hash table, like dict but only stores keys"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8DMKgRW_z6Vr"
      },
      "source": [
        "Size of any iterable can be obtained with `len`. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "JTJu6az0o6tq",
        "outputId": "771e1f1e-b717-4e31-ea2e-c7cca396db87"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "0\n"
          ]
        }
      ],
      "source": [
        "print(len(alist))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WfWoqlvG2rpR"
      },
      "source": [
        "<a id='list'></a>\n",
        "### List\n",
        "\n",
        "Lists store an ordered list of elements. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "1BVNv_Clo6tr"
      },
      "outputs": [],
      "source": [
        "\"\"\"\n",
        "List: \n",
        "\n",
        "  mutable - not hashable: can't be used as dictionary keys\n",
        "  dynamic size\n",
        "  allows duplicates and inconsistent element types\n",
        "  dynamic array implementation\n",
        "\"\"\"\n",
        "alist = []          # equivalent to list()\n",
        "alist = [1,2,3,4,5] # initialize a list"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Drqeatru3clX"
      },
      "source": [
        "Strings are immutable lists.\n",
        "Following list operations also apply to strings.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "YzP2qig73aip",
        "outputId": "2c8b9546-a8e5-4d25-8f08-175d1db6077d"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "5\n",
            "4\n",
            "[4, 5]\n",
            "[5, 2, 3]\n",
            "[3, 4]\n",
            "[]\n",
            "[5, 2, 3, 4, 5]\n",
            "[5, 4, 3, 2, 5]\n"
          ]
        }
      ],
      "source": [
        "print(alist[0])    # get first element (at index 0)\n",
        "print(alist[-2])   # get 2nd to last element (at index len-1)\n",
        "print(alist[3:])   # get elements starting from index 3 (inclusive)\n",
        "print(alist[:3])   # get elements stopping at index 3 (exclusive)\n",
        "print(alist[2:4])  # get elements within index range [2,4)\n",
        "print(alist[6:])   # prints [] because index is out of range\n",
        "print(alist[:])    # copy the list\n",
        "print(alist[::-1]) # reverse a list"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "W58aR0p6R6rQ"
      },
      "source": [
        "Unlike strings, we can re-assign values in a list."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "dWiVy07DR6HE",
        "outputId": "2c5557fc-1d8d-4f10-c669-1ed828a97e3a"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1\n",
            "5\n"
          ]
        }
      ],
      "source": [
        "print(alist[0])\n",
        "alist[0] = 5\n",
        "print(alist[0])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QzpmPx0j32R-"
      },
      "source": [
        "We can call methods on a list. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "dyaIpKgW36bI",
        "outputId": "653230a9-b8ed-4102-bd8a-7c7a66b4fef7"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[2, 3, 4, 5, 'new item', 2, 3, 4]\n",
            "5\n"
          ]
        }
      ],
      "source": [
        "alist.append('new item')    # insert at end\n",
        "alist.insert(0, 'new item') # insert at index 0\n",
        "alist.extend([2,3,4])       # concatenate lists (same as +=)\n",
        "alist += [2,3,4]            # concatenate lists (same as .extend())\n",
        "alist.index('new item')     # search by content\n",
        "alist.remove('new item')    # remove by content\n",
        "popped = alist.pop(0)       # remove by index\n",
        "\n",
        "print(alist)\n",
        "print(popped)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0c8id4IG4jpB"
      },
      "source": [
        "We can check if an element is contained in a list. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "9IJJhB1y3s_r",
        "outputId": "3cd7e583-4fbc-4f56-f865-6b404abb469a"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "found\n"
          ]
        }
      ],
      "source": [
        "if 'new item' in alist:\n",
        "    print(\"found\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6pinHv3t0B5B"
      },
      "source": [
        "<a id='tuple'></a>\n",
        "### Tuple\n",
        "\n",
        "Tuples allow us to store immutable lists."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "_ec4BTva0eqw",
        "outputId": "9c4f1ffe-10ac-4bb6-8aaf-be4a18f3e423"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "(1, 2, 3, 4, 5)"
            ]
          },
          "execution_count": 199,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "\"\"\"\n",
        "Tuple: \n",
        "\n",
        "  immutable - hashable: can be used as a dictionary key\n",
        "  fixed size: no insertion or deletion\n",
        "\"\"\"\n",
        "atuple = (1,2,3,4,5)\n",
        "atuple"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "mOv1HOqlq00b",
        "outputId": "115b8b44-9c12-4849-a678-98f22300a42e"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<class 'int'>\n",
            "<class 'tuple'>\n"
          ]
        }
      ],
      "source": [
        "not_tuple = (1)  # enclosing a variable in paranthesis doesn't make a tuple\n",
        "atuple = (1,)    # syntax to make a 1-tuple\n",
        "\n",
        "print(type(not_tuple))\n",
        "print(type(atuple))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6ZOInlx72J1Z"
      },
      "source": [
        "Indexing or traversal of a `tuple` is the same as that of a `list`. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "6AaRSa-82JMN"
      },
      "outputs": [],
      "source": [
        "# Defining tuple from a list\n",
        "atuple = tuple([1,2,3])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xsscT5XJ2Jci"
      },
      "source": [
        "We can use tuples as dictionary keys. \n",
        "Dictionaries are covered in detail in the next section.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "4d0__BN6o6tq"
      },
      "outputs": [],
      "source": [
        "ngram = ('a', 'cat')\n",
        "d = dict()\n",
        "d[ngram] = 10\n",
        "d[ngram] += 1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "U-a6t5xc4rG6"
      },
      "source": [
        "We can use named tuples to improve readability. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "rdRo7jvio6t4",
        "outputId": "f47d9aa0-3c66-48cc-9449-ee00b9466f6a"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1.0 5.0\n"
          ]
        }
      ],
      "source": [
        "from collections import namedtuple\n",
        "\n",
        "Point = namedtuple('Point', 'x y')\n",
        "pt1 = Point(1.0, 5.0)\n",
        "pt2 = Point(2.5, 1.5)\n",
        "print(pt1.x, pt1.y)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2MeHbcuu493p"
      },
      "source": [
        "<a id='dictionary'></a>\n",
        "### Dictionary\n",
        "\n",
        "Dictionaries are useful for storing key - value pairs."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "FgjMce7lo6t6",
        "outputId": "49a0b15a-169c-4432-f290-de8db35776db"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{'dog': 10, 'bird': 5, 'lion': 8}\n"
          ]
        }
      ],
      "source": [
        "\"\"\"\n",
        "Dict: \n",
        "\n",
        "  not hashable \n",
        "  dynamic size\n",
        "  no duplicates allowed\n",
        "  hash table implementation which is fast for searching\n",
        "\n",
        "\"\"\"\n",
        "adict = {} # same as dict()\n",
        "adict = {'dog': 10, 'bird': 5, 'lion': 8}\n",
        "print(adict)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "qDbczIwk5Y_6"
      },
      "source": [
        "We can get keys, values or items in a dictionary. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "uaLYZomJ5f6s",
        "outputId": "f702aab0-e35d-4a8c-f4e6-1be8a86483a5"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "dict_keys(['dog', 'bird', 'lion'])\n",
            "dict_values([10, 5, 8])\n",
            "dict_items([('dog', 10), ('bird', 5), ('lion', 8)])\n"
          ]
        }
      ],
      "source": [
        "print(adict.keys())\n",
        "print(adict.values())\n",
        "print(adict.items())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3lw132jntxB-"
      },
      "source": [
        "Let's try indexing into the key list!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 189
        },
        "id": "YO2TjfaDtwIc",
        "outputId": "569913f3-368c-48f0-e152-dda0018b97d9"
      },
      "outputs": [
        {
          "ename": "TypeError",
          "evalue": "ignored",
          "output_type": "error",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-73-1296c58f53ef>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      1\u001b[0m \u001b[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0madict\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mkeys\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 2\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mTypeError\u001b[0m: 'dict_keys' object is not subscriptable"
          ]
        }
      ],
      "source": [
        "a = adict.keys()\n",
        "a[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "M_VplrFkuSGt"
      },
      "source": [
        "We have gotten a `TypeError`!\n",
        "Dictionary methods such as `.keys()`, `.values()`, and `.items()` do not\n",
        "return lists.\n",
        "They return an `iterable` object, such as `dict_keys`. \n",
        "If you want to convert an `iterable` object to a list or a set, you should\n",
        "pass it to the appropriate initializers."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 36
        },
        "id": "JxgqUX9StrfL",
        "outputId": "1e037884-042d-41f0-dde9-7a166b6ce3cd"
      },
      "outputs": [
        {
          "data": {
            "application/vnd.google.colaboratory.intrinsic+json": {
              "type": "string"
            },
            "text/plain": [
              "'dog'"
            ]
          },
          "execution_count": 74,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "a = list(adict.keys())\n",
        "a[0]"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oAB5_hCwvKwf"
      },
      "source": [
        "This may sound confusing at first.\n",
        "Think about the general use cases for `.keys()` or `.values()`.\n",
        "They are usually used as part of loops, and they simply provide an interface\n",
        "for programmers to iterate over a list of items. \n",
        "Instead of allocating all the memory required for a pre-computed list, \n",
        "`Python` evaluates the loops in a lazy way and only returns the next item as \n",
        "needed in the loop."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bSvTjzwa5za7"
      },
      "source": [
        "We can access an item with a specific key. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "1DAetNu452bQ",
        "outputId": "7df7eb6b-ff2e-4773-e4ac-17d9e881ec8e"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "8\n"
          ]
        }
      ],
      "source": [
        "print(adict['lion'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YYc3kd4L6NWA"
      },
      "source": [
        "We can check if a key exists in a dictionary. \n",
        "This is needed since accessing non-existent keys throws an error."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 167
        },
        "id": "FHM5P_3Q6aSr",
        "outputId": "2db8e3ce-7aff-462b-e60e-ca8ba41b3566"
      },
      "outputs": [
        {
          "ename": "KeyError",
          "evalue": "ignored",
          "output_type": "error",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mKeyError\u001b[0m                                  Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-98-52009ea6fcff>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0madict\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;34m'tiger'\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mKeyError\u001b[0m: 'tiger'"
          ]
        }
      ],
      "source": [
        "adict['tiger']"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "tsgXho126QD5",
        "outputId": "da00a688-d2e6-40c0-b1ad-f338a019b47d"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Key not found.\n"
          ]
        }
      ],
      "source": [
        "if 'tiger' in adict:\n",
        "  print(adict[key])\n",
        "else:\n",
        "  print('Key not found.')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UGE08yH96mp7"
      },
      "source": [
        "The syntax to insert new keys is the same as modifying existing keys, and shown \n",
        "in the following cell."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "JicEI5sj6oFb"
      },
      "outputs": [],
      "source": [
        "adict['tiger'] = 1 # add a new key since 'tiger' isn't in our keys list\n",
        "adict['lion'] = 20 # modify existing key since 'lion' is already a key"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "79kmfD1L6tvR"
      },
      "source": [
        "Traversing dictionaries. \n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0mShrqZI5Rco",
        "outputId": "924011d9-192e-4bb2-b6b0-71db73585535"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "dog 10\n",
            "bird 5\n",
            "lion 8\n"
          ]
        }
      ],
      "source": [
        "for key in adict:\n",
        "    print(key, adict[key])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "0Oarhwm87Bsf"
      },
      "source": [
        "Traversing key, value pairs together. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "asfYaluB7Ebn",
        "outputId": "978f1123-93ed-48e3-d8b8-57f8bebb31ee"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "dog 10\n",
            "bird 5\n",
            "lion 20\n",
            "tiger 1\n"
          ]
        }
      ],
      "source": [
        "for key, val in adict.items():\n",
        "  print(key, val)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "f6wWiDFs7aPU"
      },
      "source": [
        "<a id='defaultdict'></a>\n",
        "#### DefaultDict\n",
        "\n",
        "`DefaultDict` is a special dictionary that returns a default value when a key \n",
        "queried isn't found. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "wm4eqxU67xJY",
        "outputId": "b739fdc0-8a73-4263-d588-f7f6c3e6f1fe"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "5\n",
            "0\n"
          ]
        }
      ],
      "source": [
        "from collections import defaultdict\n",
        "\n",
        "adict = defaultdict(int)\n",
        "adict['cat'] = 5\n",
        "print(adict['cat'])\n",
        "print(adict['dog'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PlHxXbUg77XJ"
      },
      "source": [
        "It is also possible to pass a custom function. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "iPEZbjpn7ney",
        "outputId": "63deabcc-acad-4ede-d2dc-85461013ffa0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "feline\n",
            "unknown\n"
          ]
        }
      ],
      "source": [
        "from collections import defaultdict\n",
        "adict = defaultdict(lambda: 'unknown')\n",
        "adict['cat'] = 'feline'\n",
        "print(adict['cat'])\n",
        "print(adict['dog'])"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "lYQI1E858MF2"
      },
      "source": [
        "<a id='counter'></a>\n",
        "#### Counter\n",
        "\n",
        "`Counter` is a dictionary with default value of 0. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Z14YHrWyo6t8",
        "outputId": "4fa122e0-6d45-4968-ff1e-ca4348bd68cb"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Counter({'t': 11, 'e': 1})\n"
          ]
        }
      ],
      "source": [
        "from collections import Counter\n",
        "\n",
        "# initialize and modify empty counter\n",
        "counter1 = Counter()\n",
        "counter1['t'] = 10\n",
        "counter1['t'] += 1\n",
        "counter1['e'] += 1\n",
        "print(counter1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "94SMZI9y8W_I"
      },
      "source": [
        "We can initialize counters from other iterables. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7GltlZgl8acL",
        "outputId": "c699aede-d9bd-4a61-9e0e-7e1fe3ee72be"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Counter({'e': 4, 't': 4, ' ': 3, 'o': 2, 'l': 1, 'r': 1, 's': 1, 'b': 1, 'c': 1, 'u': 1, 'n': 1, 'd': 1})\n"
          ]
        }
      ],
      "source": [
        "counter2 = Counter(\"letters to be counted\")\n",
        "print(counter2)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TCajDMH98hIZ"
      },
      "source": [
        "We can perform operations between counters. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "HxGq9Ex18f3l",
        "outputId": "9540d335-9645-4bae-bf90-2f1896298ffa"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1 Counter({'t': 15, 'e': 5, ' ': 3, 'o': 2, 'l': 1, 'r': 1, 's': 1, 'b': 1, 'c': 1, 'u': 1, 'n': 1, 'd': 1})\n",
            "2 Counter({'t': 7})\n",
            "3 Counter({'t': 11, 'e': 1})\n"
          ]
        }
      ],
      "source": [
        "print(\"1\", counter1 + counter2)\n",
        "print(\"2\", counter1 - counter2)\n",
        "print(\"3\", counter1 or counter2) # or for intersection, and for union"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "mdlqrgDF81yr"
      },
      "source": [
        "We can use other special methods on counters.\n",
        "Check out the docs for more!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Fxgl9n7N86ic",
        "outputId": "61e41917-25ab-44bd-bdc2-964bd137e49a"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[('e', 4), ('t', 4), (' ', 3), ('o', 2), ('l', 1)]"
            ]
          },
          "execution_count": 107,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "counter2.most_common(5)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "2s8_am1J9PwW"
      },
      "source": [
        "We can iterate list of tuples."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "xWANB8hj9UY0",
        "outputId": "2fbd266e-1c26-495b-87b1-d39301c14f0b"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "e 4\n",
            "t 4\n",
            "  3\n",
            "o 2\n",
            "l 1\n"
          ]
        }
      ],
      "source": [
        "for k,v in counter2.most_common(5):\n",
        "  print(k, v)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YTgf-Qwj7Kpw"
      },
      "source": [
        "<a id='set'></a>\n",
        "#### Set\n",
        "\n",
        "Set is a special dictionary without values. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "wmhE3Zmeo6t7",
        "outputId": "42b54c03-c921-439f-fcb9-e70cc932c742"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{'a'}"
            ]
          },
          "execution_count": 109,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "aset = set()\n",
        "aset.add('a')\n",
        "aset"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oAVaGb2g7SLC"
      },
      "source": [
        "We can use sets to remove duplicates from a list. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "5qyT88U37VWR",
        "outputId": "697c6108-614f-455e-8245-040f388bb87f"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[2, 3, 4, 5]\n"
          ]
        }
      ],
      "source": [
        "alist = [5,2,3,3,3,4,3]\n",
        "alist = list(set(alist))\n",
        "print(alist)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "mWuYLCwutwPN",
        "outputId": "e0dd8d5a-f04e-444f-f5cd-b16e3458ec71"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{2, 3, 4, 5}"
            ]
          },
          "execution_count": 116,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "set(alist)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Sh6-iKkUtcv4",
        "outputId": "fe3824bc-5d83-494b-bd9c-824e7b0a0f0e"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[2, 3, 4, 5]"
            ]
          },
          "execution_count": 115,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "list(set(alist))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IEG17z-39dkT"
      },
      "source": [
        "<a id='sorting'></a>\n",
        "### Sorting\n",
        "\n",
        "We can sort iterables."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "yr0Npa5do6t8",
        "outputId": "72da5b12-d851-49c5-be0b-fd7cd6385a7c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0, 1, 1, 4, 5, 6, 7, 8, 9]\n",
            "[9, 8, 7, 6, 5, 4, 1, 1, 0]\n"
          ]
        }
      ],
      "source": [
        "a = [4,6,1,7,0,5,1,8,9]\n",
        "a = sorted(a)\n",
        "print(a)\n",
        "a = sorted(a, reverse=True)\n",
        "print(a)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N6sPZZUV9k-X"
      },
      "source": [
        "We can sort iterables containing tuples."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "fvdUq_7Lo6t8",
        "outputId": "91e3ad57-3dce-4fac-e49c-55d03d88f81f"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[('bird', 2), ('cat', 1), ('dog', 3)]\n",
            "[('cat', 1), ('bird', 2), ('dog', 3)]\n"
          ]
        }
      ],
      "source": [
        "# sorting\n",
        "a = [(\"cat\",1), (\"dog\", 3), (\"bird\", 2)]\n",
        "a = sorted(a)\n",
        "print(a)\n",
        "b = sorted(a, key=lambda item: item[1])\n",
        "print(b)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Z88BCni79v-Q"
      },
      "source": [
        "We can pass a function we define outside instead of a lambda function. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "jCM6jPbv91xH",
        "outputId": "117216f7-2c49-412b-f866-269d3ef76e47"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "[('cat', 1), ('bird', 2), ('dog', 3)]"
            ]
          },
          "execution_count": 167,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "def sorting_key(item):\n",
        "  return item[1]\n",
        "\n",
        "sorted(a, key=sorting_key)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "HDG7xi4M-U_t"
      },
      "source": [
        "We can sort dictionaries the same way. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "19oDadMwo6t-",
        "outputId": "14abc53b-d069-4a3c-dc41-9b0a9235c2ab"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[('bird', 1), ('cat', 3)]\n"
          ]
        }
      ],
      "source": [
        "adict = {'cat':3, 'bird':1}\n",
        "print(sorted(adict.items(), key=lambda x:x[1]))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "aQywFVev-ZzH"
      },
      "source": [
        "<a id='list_comprehension'></a>\n",
        "### List Comprehension\n",
        "\n",
        "Instead of using `for` loops every time, we can use list comprehensions to \n",
        "create new lists or other iterables. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "8eGjNjf2o6t_",
        "outputId": "9f6d77c2-937d-4f4d-878b-cca745c49918"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[['i', 'am', 'good'], ['a', 'beautiful', 'day'], ['hello', 'friend']]\n"
          ]
        }
      ],
      "source": [
        "\"\"\"\n",
        "sentences1 = []\n",
        "for s in sentences:\n",
        "    sentences1.append(s.lower().split(\" \"))\n",
        "\"\"\" \n",
        "\n",
        "sentences = [\"i am good\", \"a beautiful day\", \"HELLO FRIEND\"]\n",
        "sentences1 = [s.lower().split(\" \") for s in sentences]\n",
        "print(sentences1)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "JL9NYWLg-1nx"
      },
      "source": [
        "We can have conditions."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "dNedRQmK-uG0",
        "outputId": "a1dfab90-c565-4115-f51e-46a59cf5a035"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[['a', 'beautiful', 'day'], ['hello', 'friend']]\n"
          ]
        }
      ],
      "source": [
        "sent1 = [s.lower().split(\" \") for s in sentences if len(s) > 10]\n",
        "print(sent2)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "-Cp7fyYMQoSW"
      },
      "source": [
        "We can use double `for` loops too!\n",
        "The same logic works for any number of nested loops and can be combined\n",
        "with conditionals.\n",
        "We can achieve this by just combining the regular loop expression from the\n",
        "most outer one to the inner one: \n",
        "`[outer] for s in sentences [inner] for c in s`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "NOyRlBg9Qnuh",
        "outputId": "0fda4edd-28b2-4e65-d6e3-0707e0ba02cd"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "['a', 'a', 'a', 'a']"
            ]
          },
          "execution_count": 54,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "\"\"\"\n",
        "chars = []\n",
        "for s in sentences:\n",
        "  for c in s:\n",
        "    chars.append(c)\n",
        "\"\"\"\n",
        "\n",
        "chars = [c for s in sentences for c in s if c == 'a'] \n",
        "chars"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Yio2kKK5_SQi"
      },
      "source": [
        "A useful function we can use on lists is `zip`. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "_u3k-7Xr_eH0",
        "outputId": "9270494d-c9f2-4fc5-fa39-53fca8351bd6"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "<zip object at 0x7fc747a65640>\n",
            "[('a', 10), ('b', 5), ('c', 30)]\n",
            "a 10\n",
            "b 5\n",
            "c 30\n"
          ]
        }
      ],
      "source": [
        "keys = ['a', 'b', 'c']\n",
        "values = [10, 5, 30]\n",
        "zipped = zip(keys, values)\n",
        "print(zipped)              # zip object\n",
        "print(list(zipped))        # pass to list to unzip\n",
        "\n",
        "for k, v in zip(keys, values):\n",
        "  print(k, v)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RxCokssUrVTm"
      },
      "source": [
        "<a id='dictionary_and_set_comprehensions'></a>\n",
        "### Dictionary and Set Comprehensions\n",
        "\n",
        "We can use comprehension techniques for other `Python` structures, such as \n",
        "dictionaries and sets.\n",
        "Nested loops and conditionals apply similarly.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0LMW-AFv_GPy",
        "outputId": "bb1da3f4-2e21-488e-a712-efa6c2896dde"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{'a': 0, 'b': 1, 'c': 2}\n"
          ]
        }
      ],
      "source": [
        "keys = ['a', 'b', 'c']\n",
        "adict = {k: i for i, k in enumerate(keys)}\n",
        "print(adict)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "GMQBQQYvrT9A",
        "outputId": "450dafaa-e895-49fd-921b-4b75652970fd"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{1: 'a', 2: 'b', 3: 'c'}"
            ]
          },
          "execution_count": 60,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "adict = {'a': 1, 'b': 2, 'c': 3}\n",
        "adict_reverse = {v: k for k, v in adict.items()}\n",
        "adict_reverse"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Ix9iGTOhrTJx",
        "outputId": "3272f9a0-a8fa-4e1a-dd0c-2c4916aa3fd3"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "{2, 4, 6}"
            ]
          },
          "execution_count": 62,
          "metadata": {},
          "output_type": "execute_result"
        }
      ],
      "source": [
        "aset = {1, 2, 3}\n",
        "aset_double = {2*n for n in aset}\n",
        "aset_double"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "BTbq4Rd0YUyu"
      },
      "source": [
        "<a id='copying_data_structures'></a>\n",
        "### Copying Data Structures\n",
        "\n",
        "Copying data structures can be confusing."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "whU2CIdzYgNw"
      },
      "source": [
        "Run the following code to determine how data structures are copied in `Python`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "2zTDclsOYfiN",
        "outputId": "20fcbd72-9270-4a80-fe47-a81ee77981c8"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{'one': 1, 'two': 2, 'three': 3}\n",
            "{'one': 1, 'two': 2, 'three': 3}\n"
          ]
        }
      ],
      "source": [
        "d = {'one': 1, 'two': 2} # Create a dictionary\n",
        "dcopy = d\n",
        "dcopy['three'] = 3 \n",
        "\n",
        "print(d)     # d is changed!\n",
        "print(dcopy)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "EhvpxEbvY6Ul"
      },
      "source": [
        "__Copying vs. Aliasing__ When we assign a variable containing a data structure \n",
        "(`d`) to a new variable (`dcopy`), `Python` simply makes the latter an alias of \n",
        "the former. \n",
        "Therefore, changing the copy changes the original data structure.\n",
        "Below is an example avoiding this problem."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "LL3qEzB5ZBss",
        "outputId": "1af9a71e-c063-4b7c-9a09-adfd9cf1085c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "{'one': 1, 'two': 2, 'three': 3}\n",
            "{'one': 1, 'two': 2, 'three': 3, 'four': 4}\n"
          ]
        }
      ],
      "source": [
        "dcopy = {k:v for k, v in d.items()}\n",
        "dcopy['four'] = 4\n",
        "\n",
        "print(d)     # d is not changed!\n",
        "print(dcopy)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3FLxftaCZLgw"
      },
      "source": [
        "__Copying through Slicing__ We have seen a method to copy a `list` in the \n",
        "previous sections!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "gSLwdKqJZQYE",
        "outputId": "2b5235a5-3e91-4a53-d279-ef64ab03af5e"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "copy is [1, 2, 3, 10]\n",
            "nums is [1, 2, 3, 4]\n"
          ]
        }
      ],
      "source": [
        "# One way to properly copy list is through slicing\n",
        "nums = [1, 2, 3, 4]\n",
        "ncopy = nums[:] \n",
        "\n",
        "# Another alternative, similar to the dictionary example from before\n",
        "ncopy = [i for i in nums]\n",
        "\n",
        "# Modify the copy\n",
        "ncopy[3] = 10\n",
        "\n",
        "# Observe that nums didn't change\n",
        "print(f\"copy is {ncopy}\")\n",
        "print(f\"nums is {nums}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "krydJwaqZlIi"
      },
      "source": [
        "We can also use list, dictionary or set comprehensions to copy iterables \n",
        "properly."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RMivqfyxkBVj"
      },
      "source": [
        "<a id='control_flow'></a>\n",
        "## Control Flow\n",
        "\n",
        "Like other programming languages, `Python` lets us control the flow of our \n",
        "program using conditionals and loops.\n",
        "We have seen examples of these in the previous sections, but this section \n",
        "presents them in more detail."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "z05_SKqQnPms"
      },
      "source": [
        "<a id='if_condition'></a>\n",
        "### If Condition\n",
        "\n",
        "We can execute a portion of code based on a condition."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0SfNb2HJHLgn",
        "outputId": "1e96f8ad-1797-4ff7-979c-f964920135f2"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Adding:  12\n"
          ]
        }
      ],
      "source": [
        "operation = \"add\"\n",
        "num = 6\n",
        "\n",
        "if operation == \"add\":\n",
        "    print(\"Adding: \", num + num)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "QTWKTVfbHUly"
      },
      "source": [
        "We can extend our example to include alternative cases."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "WCqQE7_To6tk",
        "outputId": "3ebbbdba-4c5d-4cc2-e36f-90253ba0b4fa"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Multiplying:  36\n"
          ]
        }
      ],
      "source": [
        "operation = \"multiply\"\n",
        "num = 6\n",
        "\n",
        "if operation == \"add\":\n",
        "    print(\"Adding: \", num + num)\n",
        "elif operation == \"multiply\":\n",
        "    print(\"Multiplying: \", num * num)\n",
        "else:\n",
        "    print(\"Operation is not defined.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "xeDkzJBXoTZD"
      },
      "source": [
        "Boolean value of a variable which has a `None` value is `False`.\n",
        "Similarly, empty arrays or strings og length 0 also have a boolean value of \n",
        "`False.\n",
        "We can check for these with an `if` statement. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "blav1CAeoZfS",
        "outputId": "2845afb6-f251-459d-a034-979400c0b1f0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "None or an empty list\n"
          ]
        }
      ],
      "source": [
        "a = None # or an empty list\n",
        "if a:\n",
        "  print(\"List containing at least one element\")\n",
        "else:\n",
        "  print(\"None or an empty list\")"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "1e29DwZ1leiE",
        "outputId": "20171e12-2ac9-4383-ffe5-ecc83809c2a5"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "yes\n"
          ]
        }
      ],
      "source": [
        "# Check for `None` directly\n",
        "if a is None:\n",
        "  print('yes')"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "IFQJHs5PGAw-"
      },
      "source": [
        "<a id='for_loop'></a>\n",
        "### For Loop\n",
        "\n",
        "We can use loops to iterate over iterables, such as strings or lists."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "cHziqbEQkWab",
        "outputId": "cfbdd8d2-5c79-4113-89fd-20e7f31d5da4"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "I\n",
            " \n",
            "l\n",
            "o\n",
            "v\n",
            "e\n",
            " \n",
            "C\n",
            "S\n",
            "1\n",
            "2\n",
            "4\n",
            "!\n"
          ]
        }
      ],
      "source": [
        "s = \"I love CS124!\"\n",
        "for character in s:\n",
        "  print(character)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "bbuQrxDQkuaK",
        "outputId": "4f2ac720-adc5-4816-d4a5-3adc06c106ad"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "a\n",
            "b\n",
            "c\n",
            "d\n",
            "e\n",
            "f\n"
          ]
        }
      ],
      "source": [
        "arr = ['a','b','c','d','e','f']\n",
        "index = 0\n",
        "for char in arr:\n",
        "  print(char)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1BmvK_0Nlmhr"
      },
      "source": [
        "If we also want to keep track of the iteration number, we can use the \n",
        "`enumerate` function. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "77WtGYRDlr4x",
        "outputId": "ab1c9cbc-9cec-411f-f1b1-ec2df312f96d"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "0 I\n",
            "1  \n",
            "2 l\n",
            "3 o\n",
            "4 v\n",
            "5 e\n",
            "6  \n",
            "7 C\n",
            "8 S\n",
            "9 1\n",
            "10 2\n",
            "11 4\n",
            "12 !\n"
          ]
        }
      ],
      "source": [
        "for i, char in enumerate(a):\n",
        "  print(i, char)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "l8C5T16Pk2sJ"
      },
      "source": [
        "We can iterate a set number of times using the `range` function. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "_m_pGCQfkdyZ",
        "outputId": "d9b03708-ab30-4e09-c4bc-24d88d37c4a0"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "0\n",
            "1\n",
            "2\n",
            "3\n"
          ]
        }
      ],
      "source": [
        "# Same as for (int i = 0; i < 4; i++)\n",
        "for i in range(4):\n",
        "  print(i)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b4GtKTHnmKoF"
      },
      "source": [
        "We can use different ranges as well. `range` function can take 3 parameters: \n",
        "`range(start-inclusive, stop-exclusive, step)`."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "hm4pCCORmOR4"
      },
      "outputs": [],
      "source": [
        "# Same as for (int = 2; i > -3, i =- 2)\n",
        "for i in range(2, -3, -2): \n",
        "    print(i)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N9w2GNvtm7VA"
      },
      "source": [
        "<a id='while_loop'></a>\n",
        "### While Loop\n",
        "\n",
        "We can also use `while` loops.\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "LnHP2aTYo6tm",
        "outputId": "648429b9-343d-43d3-a3c1-3949c3ff6c07"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "0\n",
            "1\n",
            "2\n",
            "3\n",
            "4\n"
          ]
        }
      ],
      "source": [
        "ind = 0\n",
        "while ind < 5:\n",
        "    print(ind)\n",
        "    ind +=1"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "bK0ZAv6rVei-"
      },
      "source": [
        "Special keywords, `break` and `continue` let's us control `for` and `while` \n",
        "loops."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "mndyJDYgVeBB",
        "outputId": "b9a309a4-01e9-41df-fe55-584d18c393db"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "0\n",
            "1\n",
            "2\n",
            "3\n"
          ]
        }
      ],
      "source": [
        "ind = 0\n",
        "while ind < 5:\n",
        "    if ind > 2: \n",
        "      break\n",
        "    print(ind)\n",
        "    ind += 1"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "30ybue7pV5tr",
        "outputId": "a40b84ba-84c7-4eee-e6b0-9fb21bb64458"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1\n",
            "3\n",
            "4\n",
            "5\n"
          ]
        }
      ],
      "source": [
        "ind = 0\n",
        "while ind < 5:\n",
        "    ind += 1\n",
        "    if ind == 2:\n",
        "      continue\n",
        "    print(ind)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RfoTaJIrjqCa"
      },
      "source": [
        "Sometimes it is useful to tell `Python` not to do anything.\n",
        "In these cases, we use the `pass` keyword."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Kr6ULBwSjV79",
        "outputId": "4a55e45d-81dc-499d-9f83-9fa1c958e4fb"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "1\n",
            "3\n",
            "4\n",
            "5\n"
          ]
        }
      ],
      "source": [
        "# Rewriting the above example using pass\n",
        "ind = 0\n",
        "while ind < 5:\n",
        "    ind += 1\n",
        "    if ind == 2:\n",
        "      pass\n",
        "    else:\n",
        "      print(ind)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pInFzEjRXijN"
      },
      "source": [
        "### Looping Issues\n",
        "\n",
        "One of the most common errors in looping is modifying the object while looping \n",
        "it."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "tP095phyXqoy"
      },
      "source": [
        "Explore the following code to see why modifying the object you are looping over \n",
        "is dangerous."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "Y42WFMVJXpTo",
        "outputId": "20ad3f07-8b48-436b-fc15-02d70254485c"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "hello\n",
            "Current state of greetings: ['hi', 'salve', 'ciao', 'bonjour', 'hola', 'merhaba', 'hallo']\n",
            "salve\n",
            "Current state of greetings: ['salve', 'ciao', 'bonjour', 'hola', 'merhaba', 'hallo']\n",
            "bonjour\n",
            "Current state of greetings: ['ciao', 'bonjour', 'hola', 'merhaba', 'hallo']\n",
            "merhaba\n",
            "Current state of greetings: ['bonjour', 'hola', 'merhaba', 'hallo']\n",
            "Final state of greetings: ['bonjour', 'hola', 'merhaba', 'hallo']\n"
          ]
        }
      ],
      "source": [
        "# This code attempts to print the list element by element\n",
        "# while deleting each element after it is printed \n",
        "\n",
        "greetings = ['hello', 'hi', 'salve', 'ciao', 'bonjour', 'hola', 'merhaba', 'hallo']\n",
        "\n",
        "for elem in greetings:                         \n",
        "    print(elem) \n",
        "    # Remove first element           \n",
        "    greetings.pop(0)\n",
        "    print(\"Current state of greetings: \" + str(greetings))\n",
        "  \n",
        "print(\"Final state of greetings: \" + str(greetings))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "TukPtGOppEhE"
      },
      "source": [
        "<a id='functions'></a>\n",
        "## Functions\n",
        "\n",
        "We can define functions in `Python`, similar to other programming languages."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "NenoZlIMW-gv"
      },
      "source": [
        "Make sure to define your functions before calling them!"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "l4LLGV4po6to"
      },
      "outputs": [],
      "source": [
        "# Define the function\n",
        "def example_func(a, b):\n",
        "    pass\n",
        "\n",
        "# Call the function\n",
        "example_func(5, 10)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "8M_JaXHupamx"
      },
      "source": [
        "Functions may have optional parameters."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "0IdV7JXdo6to",
        "outputId": "3d6f610f-8172-4705-9f48-ef1d2fd1a569"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "False"
            ]
          },
          "execution_count": 60,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "# Function checking whether the variable is withing a range\n",
        "def check_range(a, min_val = 0, max_val=10):\n",
        "    return min_val < a < max_val\n",
        "\n",
        "# Calling the function\n",
        "check_range(5, max_val=3)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "K3_NJKzJF813"
      },
      "source": [
        "Parameters of immutable types are passed by value. Mutable types are passed by \n",
        "reference. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "RFNeNP_cGGSt",
        "outputId": "5bb98afa-7b54-4f06-ff14-9cc96b79d5d3"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "15\n",
            "10\n",
            "15\n"
          ]
        }
      ],
      "source": [
        "def example_function(variable):\n",
        "  variable = 10\n",
        "  print(variable)\n",
        "\n",
        "a = 15\n",
        "print(a)\n",
        "example_function(a)\n",
        "print(a)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "duEddPKxGUBC",
        "outputId": "9ad4f58c-60eb-4203-d772-00b4b586b24a"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0, 1, 2, 3, 4]\n",
            "[10, 1, 2, 3, 4]\n",
            "[10, 1, 2, 3, 4]\n"
          ]
        }
      ],
      "source": [
        "def example_function(variable):\n",
        "  variable[0] = 10\n",
        "  print(variable)\n",
        "\n",
        "a = [0,1,2,3,4]\n",
        "print(a)\n",
        "example_function(a)\n",
        "print(a)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1V2GEx-4G8-j"
      },
      "source": [
        "If you want to prevent your function from changing the original values of the \n",
        "parameters passed in, you can make a deep copy inside your function before \n",
        "using your parameters. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "H8qXvx1zHJIV",
        "outputId": "5014ab82-4590-48ba-8d19-c18a67928b18"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "[0, 1, 2, 3, 4]\n",
            "[10, 1, 2, 3, 4]\n",
            "[0, 1, 2, 3, 4]\n"
          ]
        }
      ],
      "source": [
        "import copy\n",
        "\n",
        "def example_function(variable):\n",
        "  # Alternative 1\n",
        "  variable = variable[:]\n",
        "  \n",
        "  # Alternative 2\n",
        "  variable = copy.deepcopy(variable)\n",
        "\n",
        "  variable[0] = 10\n",
        "  print(variable)\n",
        "\n",
        "a = [0,1,2,3,4]\n",
        "print(a)\n",
        "example_function(a)\n",
        "print(a)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Au7--qehqJs-"
      },
      "source": [
        "Functions can access variables in their parent block's scope."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "A_ZbpCQYqQFO",
        "outputId": "f7c02e87-59d9-4e8c-8185-1048869c0582"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This is an outside variable!\n",
            "This is an outside variable!\n"
          ]
        }
      ],
      "source": [
        "outside_variable = \"This is an outside variable!\"\n",
        "\n",
        "def some_function():\n",
        "  print(outside_variable)\n",
        "\n",
        "print(outside_variable)\n",
        "some_function()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Cbl0hCogskjY"
      },
      "source": [
        "Functions can't change the values of the outside variables the same way. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 340
        },
        "id": "U7gZBMKgskCB",
        "outputId": "216999cf-c717-4c00-a3b6-96fce6a11d93"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This is an outside variable!\n"
          ]
        },
        {
          "ename": "UnboundLocalError",
          "evalue": "ignored",
          "output_type": "error",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mUnboundLocalError\u001b[0m                         Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-64-304d37abea01>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      7\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moutside_variable\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 8\u001b[0;31m \u001b[0msome_function\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;32m<ipython-input-64-304d37abea01>\u001b[0m in \u001b[0;36msome_function\u001b[0;34m()\u001b[0m\n\u001b[1;32m      2\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      3\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0msome_function\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 4\u001b[0;31m   \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0moutside_variable\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m      5\u001b[0m   \u001b[0moutside_variable\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m\"Function changed the outside variable\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n",
            "\u001b[0;31mUnboundLocalError\u001b[0m: local variable 'outside_variable' referenced before assignment"
          ]
        }
      ],
      "source": [
        "outside_variable = \"This is an outside variable!\"\n",
        "\n",
        "def some_function():\n",
        "  print(outside_variable)\n",
        "  outside_variable = \"Function changed the outside variable\"\n",
        "\n",
        "print(outside_variable)\n",
        "some_function()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ehsOEdqrs2jE"
      },
      "source": [
        "We can resolve this error using the `global` key."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "DYGLidivs9nC",
        "outputId": "d6096b55-3ade-4a53-fe8d-7dca850b3abc"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This is an outside variable!\n",
            "Function changed the outside variable!\n"
          ]
        }
      ],
      "source": [
        "outside_variable = \"This is an outside variable!\"\n",
        "\n",
        "def some_function():\n",
        "  global outside_variable\n",
        "  outside_variable = \"Function changed the outside variable!\"\n",
        "\n",
        "print(outside_variable)\n",
        "some_function()\n",
        "print(outside_variable)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ibT51hVsrhlj"
      },
      "source": [
        "If a variable of the same name is defined in a function, the later definition \n",
        "overwrites the former only in the function scope. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "JuZRURz4rgph",
        "outputId": "9fc8f387-55c4-410f-f75a-13af6486d1e8"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This is an outside variable!\n",
            "Function variable.\n",
            "This is an outside variable!\n"
          ]
        }
      ],
      "source": [
        "variable = \"This is an outside variable!\"\n",
        "\n",
        "def some_function(variable=\"Function variable.\"):\n",
        "  print(variable)\n",
        "\n",
        "print(variable)\n",
        "some_function()\n",
        "print(variable)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "AKxBN3tGrZut"
      },
      "source": [
        "Variables defined in a function can't be accessed outside. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/",
          "height": 219
        },
        "id": "xqNHhmaAr8qx",
        "outputId": "39811601-8c0c-4bb0-c6b2-6857b43fd3df"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This is a function variable!\n"
          ]
        },
        {
          "ename": "NameError",
          "evalue": "ignored",
          "output_type": "error",
          "traceback": [
            "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
            "\u001b[0;31mNameError\u001b[0m                                 Traceback (most recent call last)",
            "\u001b[0;32m<ipython-input-94-9c38147d2171>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[1;32m      4\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m      5\u001b[0m \u001b[0msome_function\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mfunction_variable\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
            "\u001b[0;31mNameError\u001b[0m: name 'function_variable' is not defined"
          ]
        }
      ],
      "source": [
        "def some_function():\n",
        "  function_variable = \"This is a function variable!\"\n",
        "  print(function_variable)\n",
        "\n",
        "some_function()\n",
        "function_variable"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Qw-hVhH2qm37"
      },
      "source": [
        "Functions can also define variables to be used in the global scope, using the \n",
        "`global` key. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "uOIZC5K-qrYO",
        "outputId": "a9766d22-09a1-4969-8d1c-080f3e9a22de"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "This is a global variable!\n",
            "This is a global variable!\n"
          ]
        }
      ],
      "source": [
        "def foo():\n",
        "  global global_variable\n",
        "  # If we try printing global_variable here, we would get a not defined error\n",
        "  global_variable = \"This is a global variable!\"\n",
        "  print(global_variable)\n",
        "\n",
        "def bar():\n",
        "  print(global_variable)\n",
        "\n",
        "foo()\n",
        "bar()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "YL4llM39tyT8"
      },
      "source": [
        "We can define functions within functions. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "D4B3iAjMtxkB",
        "outputId": "bf6907d2-d5da-4249-eed7-567fca62244d"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "2.0\n",
            "2\n"
          ]
        }
      ],
      "source": [
        "def main_function(a):\n",
        "\n",
        "  def helper_function(a):\n",
        "    return int(a)\n",
        "\n",
        "  print(a)\n",
        "  b = helper_function(a)\n",
        "  print(b)\n",
        "\n",
        "# Calling the main function\n",
        "main_function(2.0)\n",
        "helper"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "b-2jwYYrDfBk"
      },
      "source": [
        "Functions can take in functions as variables. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "i8spJVIcDh-q",
        "outputId": "62960e80-7965-485a-b33f-538e4cec4910"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "1"
            ]
          },
          "execution_count": 70,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "def function_taker(a, func):\n",
        "  return func(a)\n",
        "\n",
        "function_taker(1.0, int)\n",
        "\n",
        "int(1.0)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Esm5wFH7DtZY"
      },
      "source": [
        "We can seperately define the function we need to pass."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "bXQl4FYNDxkc",
        "outputId": "91215438-b79e-4292-9b20-5061e34a466a"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "6.0"
            ]
          },
          "execution_count": 71,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "def parameter_function(x):\n",
        "  return x + 5\n",
        "\n",
        "def function_taker(a, func):\n",
        "  return func(a)\n",
        "\n",
        "function_taker(1.0, parameter_function)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "c5Qy2L5MECoy"
      },
      "source": [
        "We can also use `lambda` functions. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "6fgwBmOPEExC",
        "outputId": "cc962a91-ed87-43bc-954d-acf91f100304"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "6.0"
            ]
          },
          "execution_count": 72,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "def function_taker(a, func):\n",
        "  return func(a)\n",
        "\n",
        "function_taker(1.0, lambda x: x + 5)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hQYjc2UOEPpX"
      },
      "source": [
        "`lambda` functions can use variables in their parent scope. "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "m18mroJjEVWW",
        "outputId": "134166b8-cf52-4875-a13c-dd022bfb344d"
      },
      "outputs": [
        {
          "data": {
            "text/plain": [
              "11.0"
            ]
          },
          "execution_count": 73,
          "metadata": {
            "tags": []
          },
          "output_type": "execute_result"
        }
      ],
      "source": [
        "num_to_add = 10\n",
        "\n",
        "def function_taker(a, func):\n",
        "  return func(a)\n",
        "\n",
        "function_taker(1.0, lambda x: x + num_to_add)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "z2XL4mZrE5fO"
      },
      "source": [
        "We can also have recursive functions."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "7exW7ny2E8x5",
        "outputId": "f5aefd16-d3ee-49f7-91ba-75e50195b3eb"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "10\n",
            "9\n",
            "8\n",
            "7\n",
            "6\n",
            "5\n",
            "4\n",
            "3\n",
            "2\n",
            "1\n",
            "Done!\n"
          ]
        }
      ],
      "source": [
        "def print_positive_numbers(num):\n",
        "  if num <= 0:\n",
        "    print(\"Done!\")\n",
        "  else:\n",
        "    print(num)\n",
        "    print_positive_numbers(num-1)\n",
        "\n",
        "print_positive_numbers(10)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "02E4_aVwAiAu"
      },
      "source": [
        "<a id='classes'></a>\n",
        "## Classes\n",
        "\n",
        "We have learned about built-in `Python` classes in the previous sections.\n",
        "You can also define your own custom classes in `Python`.\n",
        "In the homework assignments, your task will be to implement some methods of\n",
        "a partially complete class provided to you. \n",
        "For example, you will be given the boilterplate code for a `NaiveBayes`\n",
        "classifier, which is a type of a classifier we will cover in `Week 2`, and\n",
        "will be asked to implement its `train` method."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Z8rWQvZidODe"
      },
      "source": [
        "The code block below shows how to instantiate a `Python` class."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "colab": {
          "base_uri": "https://localhost:8080/"
        },
        "id": "KRAXXrytZ4zB",
        "outputId": "6cb64742-9af3-405c-cc5b-33307bad5fc1"
      },
      "outputs": [
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "Bark! Bark! I am Alfred\n"
          ]
        }
      ],
      "source": [
        "class Dog(object):\n",
        "\n",
        "  # Constructor\n",
        "  def __init__(self, name):\n",
        "    self.name = name  # Create an instance variable\n",
        "\n",
        "  # Instance method\n",
        "  def bark(self):\n",
        "    print(f\"Bark! Bark! I am {self.name}\")\n",
        "\n",
        "d = Dog('Alfred')  # construct an instance of the Dog class\n",
        "d.bark()           # call an instance method"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sHCbqgPRan0E"
      },
      "source": [
        "Let's observe the above example:\n",
        "* __object:__ The `Dog` class is extending the `object` class, which is the \n",
        "base class that all `Python` classes extend by default.\n",
        "We could also omit the `object` in the class definition (e.g. `class Dog()`), \n",
        "as `Python` automatically assumed a class extends the `object` class even if it \n",
        "is not written explicitly.\n",
        "To extend a custom class, we can simply provide the name of the parent class in \n",
        "the class definition `class Dog(Animal)`.\n",
        "If you are not sure what `extending` stands for, you can check out the short \n",
        "tutorial [here](https://www.w3schools.com/python/python_inheritance.asp) for \n",
        "your own learning, but understanding this isn't essential for our assignments.\n",
        "* ____init__:__ The constructor in `Python` classes is named as `__init__`.\n",
        "* __self:__ The first parameter of all the instance methods in `Python` is \n",
        "interpreted to be a reference to `self`.\n",
        "This allows similar to `this` in `Java`.\n",
        "On the other hand, name `self` isn't special in `Python`, the first parameter \n",
        "of an instance method is assumed to be a reference to self regardless of its \n",
        "name."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "s32yPWKvgtLx"
      },
      "source": [
        "To complement your understanding of `Python` classes, you may also want to \n",
        "learn the following, but we will not use these in our assignments.\n",
        "If we need you to understand the following in our assignments, we will make it \n",
        "clear.\n",
        "* class variables\n",
        "* @classmethod decorator\n",
        "* @staticmethod decorator\n",
        "* `super` call"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wugqn01Eo6uK"
      },
      "source": [
        "<a id='next_steps'></a>\n",
        "## Next Steps\n",
        "\n",
        "You can also cover the following topics in this \n",
        "[learnpython Python Tutorial](https://www.learnpython.org/en/Welcome) if you \n",
        "would like to learn more about `Python`. \n",
        "Following sections can be of your interest:\n",
        "\n",
        "* `Map, Filter, Reduce`: Very useful set of functional programming tools in \n",
        "`Python`.\n",
        "You are not required to know these for our class, but you will find that they \n",
        "are quite handy tools. \n",
        "The section is a quick one too, so we recommend checking it out!\n",
        "* `Generators`: Learning about `Generators` will help ground some of the\n",
        "looping behavior we discussed in the Dictionaries section.\n",
        "You don't have to know generators for our assignments. \n",
        "* `Decorators`: Decorators such as `@classmethod` and `@staticmethod` modify \n",
        "the functionality of the function they are attached to."
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [
        "g5MyzBMeo6tW",
        "0QN6t9zwOmBg",
        "runUgO8YRZq8",
        "Td5D2VALUNmC",
        "BWPzE4fvUdDh",
        "0ObB8VtCUEsP",
        "rbz2BTcprK6q",
        "GeHeASLcZpcu",
        "NTSog3DUco7f",
        "SZ6GfhgOdQz5",
        "WfWoqlvG2rpR",
        "6pinHv3t0B5B",
        "2MeHbcuu493p",
        "f6wWiDFs7aPU",
        "lYQI1E858MF2",
        "YTgf-Qwj7Kpw",
        "IEG17z-39dkT",
        "aQywFVev-ZzH",
        "BTbq4Rd0YUyu",
        "RMivqfyxkBVj",
        "z05_SKqQnPms",
        "IFQJHs5PGAw-",
        "TukPtGOppEhE"
      ],
      "name": "python_tutorial",
      "provenance": []
    },
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "codemirror_mode": {
        "name": "ipython",
        "version": 3
      },
      "file_extension": ".py",
      "mimetype": "text/x-python",
      "name": "python",
      "nbconvert_exporter": "python",
      "pygments_lexer": "ipython3",
      "version": "3.8.5"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
