{ "cells": [ { "cell_type": "markdown", "metadata": { "id": "sJCptL9sXc-P" }, "source": [ "# Procedural Python: Lists, Dictionaries, Flow Control, Oh My!**\n" ] }, { "cell_type": "markdown", "metadata": { "id": "kmxb6vN4Xc-a" }, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": { "id": "HowE4X21Xc-a" }, "source": [ "We will review basic variables and introduce lists and dictionaries as new variable types, or data structures. We will close with seeing conditional execution and functions. Hang on for the ride!\n", "\n", "Normally, a notebook begins with `import` statements that _import_ packages or libraries that do a lot of heavy lifting for us. We'll get to that later." ] }, { "cell_type": "markdown", "metadata": { "id": "PGefTrjCXc-b" }, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": { "id": "Xzga45pFXc-b" }, "source": [ "## 1 A quick review of **_variables_** and **_comments_**." ] }, { "cell_type": "markdown", "metadata": { "id": "dVEKBrlFXc-c" }, "source": [ "### 1.1 A quick review of variables\n", "\n", "Variables are human names we give data objects in our code. Variables in Python should be named using appropriately descriptions of their purpose. By convention, most variable names are `lower case` and may optionally contain the underscore character ('`_`').\n", "\n", "Some names you might want to use are off-limits because they are **_reserved words_**, meaning they are words in Python that have special meaning. \n", "\n", "Examples of _reserved words_ that you should not use as variable names are in the table below. The ones in __bold__ are ones we will use in the tutorial today. Remember, these can't be used as variable names!\n", "\n", "| | | | | | | |\n", "|:---:|:---:|:---:|:---:|:---:|:---:|:---:|\n", "| __import__ | __True__ | __False__ | __if__ | __else__ | __def__ | __in__ |\n", "| __not__ | __and__ | __or__ | __None__ | from | continue | pass |\n", "| class | await | raise | del | lambda | return | elif |\n", "| with | as | finally | nonlocal | while | assert | except | \n", "| global | yield | break | try | global | \n" ] }, { "cell_type": "markdown", "metadata": { "id": "gpkC6GqhXc-c" }, "source": [ "Let's see an example of a decimal point containing number, known to computers as a **_floating point_** number. Let's use $\\pi$ as the number. (Pro tip: you can write equations in Markdown. See this [reference](https://medium.com/analytics-vidhya/writing-math-equations-in-jupyter-notebook-a-naive-introduction-a5ce87b9a214).)\n", "\n", "```\n", "pickles = 3.14\n", "print(pickles)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "uLYdHhj1Xc-c" }, "outputs": [], "source": [ "pickles = 3.14\n", "print(pickles)" ] }, { "cell_type": "markdown", "metadata": { "id": "hL4YTLJTXc-d" }, "source": [ "Cool. We defined a variable named pickles containing a poor estimate of $\\pi$. Now every place the word `pickles` appears, it will have the value `3.14`, at least until we change it. \n", "\n", "Is `pickles` a good variable name for the value $\\pi$? If not, what would be a better name? Is it in the **_reserved word_** list above? Use the `code` cell below to create a new variable with your preferred name in it." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "SVOLb5uUXc-e" }, "outputs": [], "source": [ "pi = 3.14" ] }, { "cell_type": "markdown", "metadata": { "id": "XGOmnoxjXc-e" }, "source": [ "Variables in Python have different data types. The simple ones, we've already discussed such as an integer or `int`, a string or `str`, a decimal point containing number called a **_floating point_** number. **_Floating point_** numbers are special and are stored in a computer's memory using [internal representations](http://steve.hollasch.net/cgindex/coding/ieeefloat.html). One important thing to know about **_floating point_** numbers is that to a computer, the statement below may not always be true. For now, just think about **_floating point_** numbers as approximately representing the decimal number you see.\n", "\n", "```\n", "10.0 * 0.1 = 1.0\n", "```\n", "\n", "Variables can change their value in Python so we can change the value of `pickles` to something else. For example, a definition of what pickles are.\n", "\n", "```\n", "pickles = \"A cucumber preserved in vinegar or brine.\"\n", "print(pickles)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "lkSMDooKWYkb" }, "outputs": [], "source": [ "10.0 * 0.1" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "gI8plkK0WdRr" }, "outputs": [], "source": [ "\n", "0.9999999999999999999999999" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "r1AS_ZUPXc-e" }, "outputs": [], "source": [ "pickles = \"A cucumber preserved in vinegar or brine.\"\n", "print(pickles)" ] }, { "cell_type": "markdown", "metadata": { "id": "wRsekXtWXc-f" }, "source": [ "### 1.2 A quick review of comments\n", "\n", "Just like we should use good naming conventions for variables so they make sense, we should have good comments to help readers follow our code. Good comments can turn a speck of coding gold into a valuable nugget of knowledge. Bad or wrong comments are bugs. If you want to learn more about why we call computer coding problems bugs, read about [Grace Hopper](https://en.wikipedia.org/wiki/Grace_Hopper) and see [her photo of a `bug` in her notebook](https://en.wikipedia.org/wiki/Grace_Hopper#/media/File:First_Computer_Bug,_1945.jpg).\n", "\n", "To comment out some text, use the `#` or hashtag or sometimes called the pound character. By the way, is the `#` a **_reserved word_**?\n", "\n", "```\n", "print(pickles)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "BU41NSMdXc-f" }, "outputs": [], "source": [ "print(pickles)" ] }, { "cell_type": "markdown", "metadata": { "id": "H2Rit9gKXc-g" }, "source": [ "```\n", "# This is an example comment. Notice it is in english and full sentences. That is good style.\n", "\n", "# two_pi = 6.28\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "UT22cA27Xc-g" }, "outputs": [], "source": [ "# This is an example comment. Notice it is in english and full sentences. That is good style.\n", "\n", "# two_pi = 6.28" ] }, { "cell_type": "markdown", "metadata": { "id": "z_paxka7Xc-h" }, "source": [ "If I tried to execute a cell with the following contents, what would it output?\n", "\n", "```\n", "print(two_pi)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ysB1nYiKXBrk" }, "outputs": [], "source": [ "print(two_pi)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ht0yp4gEXXbZ" }, "outputs": [], "source": [ "0 \n", "0.0" ] }, { "cell_type": "markdown", "metadata": { "id": "ac0bu1_3Xc-i" }, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": { "id": "1_hGBvV6Xc-i" }, "source": [ "## 2 Data Structures: Variables that organize data\n", "\n", "Many variables you will encounter are more than the above simple **_data types_** (integers, strings, floating point numbers). In fact, they may contain a few to many pieces of data rolled into one thing or **_data structure_**. Next, we'll discuss two important _data structures_: **lists** and **dictionaries**. There are many advanced **_data structures_** in Python that behave like **lists** and **dictionaries**, in different settings but their concepts are often similar. Thus, understanding them here will help us [grok](https://en.wikipedia.org/wiki/Grok) or understand more advanced concepts. Let's start with the venerable **list**.\n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "uyddGdBqXc-j" }, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": { "id": "RhFEDkT8Xc-j" }, "source": [ "### 2.1 Lists\n", "\n", "_For more than just shopping._\n", "A list is an **_ordered_ _collection_** of data. By **_collection_**, we mean that it contains multiple data. By **_ordered_**, we mean that the data are arranged so that they appear first to last like words in a sentence. The order is important for the meaning of the sentence.\n", "\n", "Let's begin by creating a list variable named `my_list` that contains three pieces of information.\n", "\n", "```\n", "my_list = ['I', 'like', 'pie']\n", "my_list\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "5PmKqdOwXc-j" }, "outputs": [], "source": [ "my_list = ['I', 'like', 'pie']\n", "my_list" ] }, { "cell_type": "markdown", "metadata": { "id": "F2-0hv9hXc-k" }, "source": [ "Now the value of the variable `my_list` points to a list of three strings. The use of `[`, `]`, and `,` are used to denote the begining, end and separator of the list. Like a sentence, this list of words is ordered. I like cake.\n", "\n", "**Notice, we didn't use a `print()` on the variable. The last variable _expression_ in a cell is shown in the notebook by default.**" ] }, { "cell_type": "markdown", "metadata": { "id": "t4u3TYmOXc-k" }, "source": [ "The elements in a list have indices. That is, to access an element in the list, you can refer to it by its index. Think of a list like a very simple table.\n", "\n", "| index | value |\n", "|:---:|:---|\n", "| 0 | `'I'` |\n", "| 1 | `'like'` |\n", "| 2 | `'pie'` |" ] }, { "cell_type": "markdown", "metadata": { "id": "DYNcFx18Xc-k" }, "source": [ "**People might start counting at `1`, but computers start counting at `0`. The first element in a list has the index `0`, the last element in a list has the index of the length of the list minus 1. For our list which is three elements long, the first index will be 0 and the last index will be `2`.**\n", "\n", "**Some programming languages also start counting at 1. These include [Fortran](https://en.wikipedia.org/wiki/Fortran), [Matlab](https://en.wikipedia.org/wiki/MATLAB), and the abominable [R](https://en.wikipedia.org/wiki/R). This is unfortunate. Be extra careful if you try to [port code](https://en.wikipedia.org/wiki/Porting) from those languages to Python.**\n", "\n", "If you want to access a list element you can use its index. The index value is designated by appending `[` and `]` to the variable name with the index between. Examples are always easier than words:\n", "\n", "```\n", "my_list[0]\n", "\n", "```\n", "\n", "Given what you know... What will this output?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "IyJH2n_bXc-l" }, "outputs": [], "source": [ "my_list[0]" ] }, { "cell_type": "markdown", "metadata": { "id": "zSJIsVnAXc-l" }, "source": [ "If you try to use an index that is larger than the length of the list minus 1, you will get an error. Try it!\n", "\n", "The different colors means you made a boo boo!\n", "\n", "```\n", "my_list[3]\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "WLp8WXRDXc-l" }, "outputs": [], "source": [ "my_list[3]" ] }, { "cell_type": "markdown", "metadata": { "id": "6lWutF9MXc-l" }, "source": [ "The last line of the error report is the most informative for us now. It should read:\n", "\n", "```\n", "IndexError: list index out of range\n", "```\n", "\n", "It is trying to tell you that an `IndexError` occured because the the index you tried to access is out of the range of `0` to `2`, inclusive. Translation: stay in your lane, programmer!" ] }, { "cell_type": "markdown", "metadata": { "id": "pv_NujECXc-m" }, "source": [ "In addition to being able to recall or access a value of a list by the element's index in the list, we can change the value of the element. We will also use the `[`, index, `]` notation but like when we set the value of a variable, we will use the `=` character. Let's do it!\n", "\n", "```\n", "my_list[2] = 'cake'\n", "my_list\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "7XLlkS8HXc-m" }, "outputs": [], "source": [ "my_list[2] = 'cake'\n", "my_list" ] }, { "cell_type": "markdown", "metadata": { "id": "v4csTD07Xc-m" }, "source": [ "Sweet. Now, change the third element to your favorite food item. Is it really better than cake? Remember, don't change the number, just the string. The string is what appears between the `'` characters.\n", "\n", "```\n", "my_list[2] = 'toenails'\n", "my_list\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "43sMYun3Xc-n" }, "outputs": [], "source": [ "my_list[2] = 'toenails'\n", "my_list" ] }, { "cell_type": "markdown", "metadata": { "id": "gNXBysgzXc-n" }, "source": [ "Finally, let's talk about empty lists and appending items to a list. An empty list is created by setting a variable to `[]`. This means the variable's **_data type_** is a list, but it contains no elements.\n", "\n", "```\n", "a_new_list = []\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "4T4KoaEOXc-r" }, "outputs": [], "source": [ "a_new_list = []\n", "a_new_list" ] }, { "cell_type": "markdown", "metadata": { "id": "oeybIDG-Xc-w" }, "source": [ "We can append items to a list by using the `.append()` **_function_**. We'll talk more about functions later, but when this **_function_** or **_method_** is used on a variable whose **_data type_** is list, it well append the value in between the `()` to the end of the list.\n", "\n", "```\n", "a_new_list.append(\"1st element\")\n", "print(a_new_list)\n", "a_new_list.append(\"2nd element\")\n", "print(a_new_list)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "9iGw1714Xc-y" }, "outputs": [], "source": [ "a_new_list.append(\"1st element\")\n", "print(a_new_list)\n", "a_new_list.append(\"2nd element\")\n", "print(a_new_list)" ] }, { "cell_type": "markdown", "metadata": { "id": "PKgSxW2ZXc-z" }, "source": [ "Finally, in addition to the `.append()` **_function_**, there are a lot of **_functions_** (or **_methods_**) available for **_lists_**. See a complete list of them [here](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists).\n", "\n", "One more we'll touch on quickly is the `len()` **_function_**. It returns the length of a **_list_**. Here is an example:\n", "\n", "```\n", "len(a_new_list)\n", "```\n", "\n", "Before you run this cell. What do you think it will output?" ] }, { "cell_type": "markdown", "metadata": { "id": "FpuehbeFXc-z" }, "source": [ "---" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Wlm4EU45Xc-z" }, "outputs": [], "source": [ "len(my_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "qCrktzgrcDiA" }, "outputs": [], "source": [ "a_tmp_list = [1, 2, 3, 4]\n", "b_tmp_list = [5, 6, 7, 8]\n", "a_tmp_list.extend(b_tmp_list)\n", "print(a_tmp_list)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ne_Ti2gycWmG" }, "outputs": [], "source": [ "a_tmp_list + b_tmp_list" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "32G6TJrdc5XB" }, "outputs": [], "source": [ "\n", "my_list" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "aXM6SfP_c8CG" }, "outputs": [], "source": [ "\n", "my_list[3]" ] }, { "cell_type": "markdown", "metadata": { "id": "69hpUJVXXc-z" }, "source": [ "#### 2.1.1 Slicing\n", "\n", "Sometimes you want to make a list from consecutive elements of a list. This is called **_slicing_** where you cut up a list and get just the consecutive values you want. **_Slicing_** is done with the `:` character in the index area between the `[` and the `]`. Here is an example to pull just the last two items out of `my_list`. We use the first index, then a `:`, then the last index plus 1. Like this:\n", "\n", "```\n", "my_list[1:3]\n", "```\n", "\n", "You might be asking... **WHY +1??** This is because with _slices_ or _ranges_ in Python are known as **[_half-open intervals_](https://en.wikipedia.org/wiki/Interval_(mathematics))** where the lower bound is inclusive and the upper bound is the non-inclusive limit. **TL;DR**: add one the the upper end of a _slice_ or a _range_ in Python.\n", "\n", "```\n", "my_list[1:3]\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "4eKeqATwXc-0" }, "outputs": [], "source": [ "my_list[1:3]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "5f7OaTqDdgAZ" }, "outputs": [], "source": [ "my_list[1:4]" ] }, { "cell_type": "markdown", "metadata": { "id": "ifSjinFpXc-2" }, "source": [ "Just for giggles, try it with `my_list[1:2]`. You will see the _range_ of the _slice_ is only `1`. That's because `2 - 1 = 1`.\n", "\n", "```\n", "my_list[1:2]\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "cotYNd0QXc-3" }, "outputs": [], "source": [ "my_list[1:2]" ] }, { "cell_type": "markdown", "metadata": { "id": "f24cRovsXc-4" }, "source": [ "You don't even need to use the upper bound if all you really mean is _the end of the list_. For that, you can leave the index empty. Hot dog! Let's see an example...\n", "\n", "```\n", "my_list[1:]\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "JJ00WXqXXc-4" }, "outputs": [], "source": [ "my_list[1:]" ] }, { "cell_type": "markdown", "metadata": { "id": "3sKpTeV6Xc-4" }, "source": [ "**But wait, there's more!** You can set multiple elements of a list **at the same time** by _slicing_. **Dig this!**\n", "\n", "```\n", "my_list[1:] = ['love', 'puppies']\n", "my_list\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "4CDiDI5AXc-4" }, "outputs": [], "source": [ "my_list[1:] = ['love', 'puppies']\n", "my_list" ] }, { "cell_type": "markdown", "metadata": { "id": "02k9ZAM5Xc-5" }, "source": [ "And who doesn't love puppies? Recap... Lists are _ordered_ _collections_ of information that you can recognize by their use of `[` and `]`. To access or _address_ elements in the list, you can use _indices_. They start at `0` in Python. The last element of a list has the index of the length of the list minus 1. When _slicing_ a list, use two indices separated by `:`. If you leave one off, it means everying up to or beyond that element. \n", "\n", "So, for example, the first two elements of our list could be accessed by?\n", "\n", "```\n", "my_list[:2]\n", "```\n", "**Why `2`? Why no number before the `:`?**" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "KZTUT0aaXc-5" }, "outputs": [], "source": [ "my_list[:2]" ] }, { "cell_type": "markdown", "metadata": { "id": "xKTvGQDhXc-5" }, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": { "id": "s18dpgwXXc-5" }, "source": [ "#### 2.1.2 Negative indices?!?!\n", "\n", "A brief note for folks who want to learn more. You can use negative index numbers to access from the end of the list towards the front. That is, a negative 1 (`-1`) is the last element in the list. A negative 2 (`-2`) is the second to last. The same rules apply for slicing with the `:` character. For more information on this serious cool thing that you probably won't use soon, read up [here](https://googlethatforyou.com?q=negative%20indexing%20in%20python). \n", "\n", "A quick demo example... Let's get last element in the list using negative indexing. That will be `-1`. Here goes...\n", "\n", "```\n", "my_list[-1]\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "CeKdz8jTXc-5" }, "outputs": [], "source": [ "my_list[-1]" ] }, { "cell_type": "markdown", "metadata": { "id": "SWDSRIMCXc-6" }, "source": [ "We can also use _slicing_ with _negative indices_. Remember, that _slicing_ works the same way with _negative indices_, i.e. the the upper bound is non-inclusive. Here is an example using upper and lower bounds. Were you surprised by the results?\n", "\n", "```\n", "my_list[-3:-1]\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "G4e2gNwoXc-6" }, "outputs": [], "source": [ "my_list[-3:-1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "R5nLcfDlfBL4" }, "outputs": [], "source": [ "\n", "my_list[-3:]" ] }, { "cell_type": "markdown", "metadata": { "id": "oHkGmi8eXc-6" }, "source": [ "---" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "StusavxafHb4" }, "outputs": [], "source": [ "\n", "my_list[::-1]" ] }, { "cell_type": "markdown", "metadata": { "id": "KSkW8MdzXc-6" }, "source": [ "#### 2.1.3 Lists can contain most anything\n", "\n", "So far, we've seen a list containing some strings. That made our sentence analogy about the _ordering_ of _objects_ or strings in a list make sense. But lists can contain a mixture of _data types_ and _data structures_. As a quick example, let's make a list that contains a integer, a string and a floating point number. This will be a four element list.\n", "\n", "```\n", "zoo = [ 42, 'Elephants', 'ate', 3.14 ]\n", "```\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "-srjPmTeXc-6" }, "outputs": [], "source": [ "zoo = [ 42, 'Elephants', 'ate', 3.14 ]\n", "zoo" ] }, { "cell_type": "markdown", "metadata": { "id": "D0saF_4XXc-6" }, "source": [ "We can even make a list of lists. **OH. MY. GOSH! SO META!**\n", "\n", "```\n", "list_of_lists = [\n", " [ 42, 43, 44, 44 ],\n", " [ 'a', 'b', 'c', 'd' ]\n", "]\n", "\n", "list_of_lists[0]\n", "\n", "list_of_lists[0][1]\n", "\n", "a_list = list_of_lists[0]\n", "a_list[1]\n", "```\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "1kDSmo4BXc-6" }, "outputs": [], "source": [ "list_of_lists = [\n", " [ 42, 43, 44, 44 ],\n", " [ 'a', 'b', 'c', 'd' ]\n", "]" ] }, { "cell_type": "markdown", "metadata": { "id": "g31xJBp-Xc-6" }, "source": [ "The important thing here is to have the right number of `[` and `]` to embed a list in a list separated between `,`. Yeah, this **is** super meta." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "eeEJM5f2Xc-7" }, "outputs": [], "source": [ "\n", "list_of_lists[0]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "BG5NrV1AXc-7" }, "outputs": [], "source": [ "list_of_lists[0][1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "rKZUUGNOXc-7" }, "outputs": [], "source": [ "list_of_lists[1][1]" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "HiXDrLAXXc-7" }, "outputs": [], "source": [ "a_list = list_of_lists[0]\n", "a_list[1]" ] }, { "cell_type": "markdown", "metadata": { "id": "P35MtlkWXc-8" }, "source": [ "Make sure you understand why the above works. Take a minute and play with the first and last indices." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "GMYUPaTGXc-8" }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "id": "LziUNB3CXc-9" }, "source": [ "---" ] }, { "cell_type": "markdown", "metadata": { "id": "_6aMAlB4Xc-9" }, "source": [ "### 2.2 Dictionaries\n", "\n", "_For more than just reading on a Friday night._\n", "Sometimes we want to _access_ elements in a _data structure_ by something other than an index. Consider a [dictionary on the internet](dictionary.com). You look up the word on a seach engine and go to the web page of the entry for the word. Python has a similar concept where the index for an element in a **_collection_** is not a number, as it is in a list above, but a `key` that, may be a string like `'pickles'`. \n", "\n", "In the case of a Python **_dictionary_**, we call the definition a **_value_** and the way we look up the definition is a **_key_**. This results in **_key_** and **_value_** pairs. One **_key_** maps to one **_value_**. In our analogy of a internet dictionary, this is the same as the word to definition pairs.\n", "\n", "Let's create a simple dictionary with a definition we have alread seen in the tutorials... Pickles. \n", "\n", "```\n", "my_dict = {} # create an empty dictionary\n", "my_dict['pickles'] = \"A cucumber preserved in vinegar or brine.\"\n", "my_dict\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "KdPhThnoXc-9" }, "outputs": [], "source": [ "my_dict = {} # create an empty dictionary\n", "my_dict['pickles'] = \"A cucumber preserved in vinegar or brine.\"\n", "my_dict" ] }, { "cell_type": "markdown", "metadata": { "id": "_q0ZvWIBXc--" }, "source": [ "Notice the use of the `#` comment. Nice. Unlike the list, for dictionaries, some of their operations use the `{` and `}` brackets. Using a key to access or retrieve a value from the dictionary still uses the `[` and `]` brackets. Stick with it, for realz.\n", "\n", "Case matters in a dictionary because the `key` is a _data type_ itself.\n", "\n", "```\n", "my_dict['Pickles']\n", "```\n", "\n", "returns an error (`KeyError: 'Pickles'`) and the following does not\n", "\n", "```\n", "my_dict['pickles']\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "vHcWwc1hhKIm" }, "outputs": [], "source": [ "\n", "my_dict['pickles']" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "2r3cqm6rXc--" }, "outputs": [], "source": [ "my_dict['pickles']" ] }, { "cell_type": "markdown", "metadata": { "id": "ugkEsXyLXc--" }, "source": [ " This is a lot like the `IndexError` from the list case.\n", " \n", " Moving on... You can change the value of a dictionary **_key_** by **_reassigning_** it. For example below, we use the same key `'pickles'` to change the definition of the word in our dictionary. Notice we still use the `[` and `]` brackets but we use the **_key_** instead of the **_index_** like we did with lists. The change we made in the string is that the cucumbers in pickles are usually small.\n", " \n", " ```\n", " my_dict['pickles'] = \"A small cucumber preserved in vinegar or brine.\"\n", " ```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "jYQ2cJFGXc--" }, "outputs": [], "source": [ "my_dict['pickles'] = \"A small cucumber preserved in vinegar or brine.\"\n", "my_dict" ] }, { "cell_type": "markdown", "metadata": { "id": "pDGy_DJsXc--" }, "source": [ "Let's add two `key` and `value` pairs to our dictionary which are in the table below:\n", "\n", "| key | value |\n", "|-----|-------|\n", "| list | An ordered collection. |\n", "| dictionary | A collection with _unique indices_. |\n", "\n", "Something like:\n", "```\n", "my_dict['list'] = \"An ordered collection\"\n", "print(my_dict)\n", "```\n", "Is probably where we want to begin." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "PYl5pwVQXc--" }, "outputs": [], "source": [ "my_dict['list'] = \"An ordered collection\"\n", "my_dict['dictionary'] = \"a collection with unique keys\"\n", "my_dict" ] }, { "cell_type": "markdown", "metadata": { "id": "w5Yi3mX3Xc--" }, "source": [ "Finally, like the **_list's_** `.append()` **_function_**, there are a lot of **_functions_** (or **_methods_**) available for dictionaries. See a complete list of them [here](https://docs.python.org/3/tutorial/datastructures.html#dictionaries)." ] }, { "cell_type": "markdown", "metadata": { "id": "2Y76AgRyXc-_" }, "source": [ "## 3 Flow control: If this, then that...\n", "\n", "**_Flow control_** is a fancy phrase meaning to execute some code statements under certain conditions. The simplist case, is an `if` statement (figure right below): If a variable is `True` then do something. If it is `False` then do something else, or do nothing at all. \n", "\n" ] }, { "cell_type": "markdown", "metadata": { "id": "0PXCfEuKXc-_" }, "source": [ "\n", "\n", "Flow control figure\n", "\n", "In the above figure, the `selection` refers to `if` statements. `Iteration` refers to loops or repeating some statements over and over while changing a small number of variable values. `Sequence` roughly corresponds to blocks of statements in **_functions_**.\n", "\n", "Flow control refers how to programs do loops, conditional execution, and order of functional operations. Let's start with conditionals, or the venerable ``if`` statement.\n", "\n", "Let's start with a simple list of instructors for these sessions.\n", "\n", "```\n", "instructors = ['Evan', 'Dave', 'Nels', 'Orion', 'Bozzo']\n", "instructors\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "PEpoT1ueXc-_" }, "outputs": [], "source": [ "instructors = ['Shachi', 'Dave', 'Evan', 'Stephanie', 'Bozzo']\n", "instructors" ] }, { "cell_type": "markdown", "metadata": { "id": "LEivN1GcXc-_" }, "source": [ "### 3.1 If\n", "If statements can be use to execute some lines or block of code if a particular condition is satisfied. E.g. Let's print something based on the entries in the list.\n", "\n", "```\n", "if 'Bozzo' in instructors:\n", " print('#fakeinstructor')\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Uyh6JoPLXc-_" }, "outputs": [], "source": [ "if 'Bozzo' in instructors:\n", " print('#fakeinstructor')\n", " " ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "w3beeMPDjscR" }, "outputs": [], "source": [ "False is True" ] }, { "cell_type": "markdown", "metadata": { "id": "toV3zJiRXc-_" }, "source": [ "Notice the use the special **_reserved word_** **in**. This returns the value `True` when a value appears in a **_list_** and `False` when it does not. Notice how it reads like English. Readability is a key feature of Python and is part of the language design philosophy." ] }, { "cell_type": "markdown", "metadata": { "id": "2LSAN8ShXc_A" }, "source": [ "Usually we want conditional logic on both sides of a binary condition, e.g. some action when ``True`` and some when ``False``\n", "\n", "```\n", "if 'Bozzo' in instructors:\n", " print('There are fake names for class instructors in your list!')\n", "else:\n", " print(\"Nothing to see here\")\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "NLKMAqAqXc_A" }, "outputs": [], "source": [ "if 'Bozzo' in instructors:\n", " print('There are fake names for class instructors in your list!')\n", "else:\n", " print(\"Nothing to see here\")" ] }, { "cell_type": "markdown", "metadata": { "id": "BtrXNfRPXc_A" }, "source": [ "There is a special do nothing word: `pass` that skips over some arm of a conditional, e.g.\n", "\n", "```\n", "if 'Evan' in instructors:\n", " print(\"Congratulations! Evan is part of your tutorial, it will be grand!\")\n", "else:\n", " pass\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "En5A0fNQXc_A" }, "outputs": [], "source": [ "if 'Evan' in instructors:\n", " print(\"Congratulations! Evan is part of your tutorial, it will be grand!\")\n", "else:\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "id": "rFXINcHrXc_A" }, "source": [ "The use of `pass` here is very important. While you can actually skip the `else` and `pass` statements and the code will behave identically, using them is an important signal that you intended for the negative case to do nothing. When you are writing code, you should start thinking about reading code and how others will read your code.\n", "\n", "In short, when you have one side of an `if` statement that has no code use an `else` and a `pass` to be a good citizen. Remember, the person you will collaborate the most about your code is yourself in 3-6 months. Love yourself, use `pass`." ] }, { "cell_type": "markdown", "metadata": { "id": "q8Emk_D9Xc_A" }, "source": [ "_Note_: what have you noticed in this session about quotes? What is the difference between ``'`` and ``\"``?\n", "\n", "\n", "Another simple example:\n", "\n", "```\n", "if True is False:\n", " print(\"I'm so confused\")\n", "else:\n", " print(\"Everything is right with the world\")\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "TrewKXw6Xc_B", "scrolled": true }, "outputs": [], "source": [ "if True is False:\n", " print(\"I'm so confused\")\n", "else:\n", " print(\"Everything is right with the world\")" ] }, { "cell_type": "markdown", "metadata": { "id": "cGk2Rx3aXc_B" }, "source": [ "It is always good practice to handle all cases explicity. **_Conditional fall through_** is a common source of bugs.\n", "\n", "Sometimes we wish to test multiple conditions. Use `if`, `elif`, and `else`.\n", "\n", "```\n", "my_favorite = 'pie'\n", "\n", "if my_favorite == 'cake':\n", " print(\"He likes cake! I'll start making a double chocolate velvet cake right now!\")\n", "elif my_favorite == 'pie':\n", " print(\"He likes pie! I'll start making a cherry pie right now!\")\n", "else:\n", " print(\"He likes \" + my_favorite + \". I don't know how to make that.\")\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "SksttTg_Xc_B" }, "outputs": [], "source": [ "my_favorite = 'pie'\n", "\n", "if my_favorite == 'cake':\n", " print(\"He likes cake! I'll start making a double chocolate velvet cake right now!\")\n", "elif my_favorite == 'pie':\n", " print(\"He likes pie! I'll start making a cherry pie right now!\")\n", "else:\n", " print(\"He likes \" + my_favorite + \". I don't know how to make that.\")" ] }, { "cell_type": "markdown", "metadata": { "id": "uYf9JtVtXc_B" }, "source": [ "**Note**: There is a big difference between the above using `elif` and this code that uses sequential `if`s:\n", "\n", "```\n", "if my_favorite == 'cake':\n", " print(\"He likes cake! I'll start making a double chocolate velvet cake right now!\")\n", "if my_favorite == 'pie':\n", " print(\"He likes pie! I'll start making a cherry pie right now!\")\n", "else:\n", " print(\"He likes \" + my_favorite + \". I don't know how to make that.\")\n", "```\n", "\n", "Before you run, the cell, can you describe how these two blocks differ in their outcomes?" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "XXBYtPT9Xc_C" }, "outputs": [], "source": [ "if my_favorite == 'cake':\n", " print(\"He likes cake! I'll start making a double chocolate velvet cake right now!\")\n", "if my_favorite == 'pie':\n", " print(\"He likes pie! I'll start making a cherry pie right now!\")\n", "else:\n", " print(\"He likes \" + my_favorite + \". I don't know how to make that.\")" ] }, { "cell_type": "markdown", "metadata": { "id": "YsTqvR5lXc_C" }, "source": [ "**Conditionals** can take ``and`` and ``or`` and ``not``. E.g.\n", "\n", "```\n", "my_favorite = 'pie'\n", "\n", "if my_favorite == 'cake' or my_favorite == 'pie':\n", " print(my_favorite + \" : I have a recipe for that!\")\n", "else:\n", " print(\"Ew! Who eats that?\")\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "3_9Ja-6rXc_C" }, "outputs": [], "source": [ "my_favorite = 'pie'\n", "\n", "if my_favorite == 'cake' or my_favorite == 'pie':\n", " print(my_favorite + \" : I have a recipe for that!\")\n", "else:\n", " print(\"Ew! Who eats that?\")" ] }, { "cell_type": "markdown", "metadata": { "id": "uGcoUB8gXc_C" }, "source": [ "### 3.2 For\n", "\n", "For loops are the standard loop, though `while` is also common. For has the general form:\n", "```\n", "for items in list:\n", " do stuff\n", "```\n", "\n", "**NOTICE THE INDENTATION! INDENTING IS AN IMPORTANT PART OF Python's SYNTAX**\n", "\n", "For loops and collections like tuples, lists and dictionaries are natural friends.\n", "\n", "```\n", "instructors\n", "\n", "for instructor in instructors:\n", " print(instructor)\n", " \n", "print(instructor) \n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "t1k3wF7oXc_C" }, "outputs": [], "source": [ "instructors" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "1G7ArDygXc_C" }, "outputs": [], "source": [ "for instructor in instructors:\n", " print(instructor)" ] }, { "cell_type": "markdown", "metadata": { "id": "v6ln5WZKXc_C" }, "source": [ "Note that after the **_for_** loop has ended, the `instructor` variable remains defined and contains the last value of the list that was iteratred over." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "wm9ovWsEXc_D" }, "outputs": [], "source": [ "instructor" ] }, { "cell_type": "markdown", "metadata": { "id": "tHP1qZBVXc_D" }, "source": [ "You can combine loops and conditionals:\n", "\n", "```\n", "for instructor in instructors:\n", " if instructor.endswith('Hacker'):\n", " print(instructor + \" doesn't sound like a real instructor name!\")\n", " else:\n", " print(instructor + \" is so smart... all those gooey brains!\")\n", " \n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "r631ISRJXc_D" }, "outputs": [], "source": [ "for instructor in instructors:\n", " if instructor.endswith('Hacker'):\n", " print(instructor + \" doesn't sound like a real instructor name!\")\n", " else:\n", " print(instructor + \" is so smart... all those gooey brains!\")" ] }, { "cell_type": "markdown", "metadata": { "id": "gHGqYwFDXc_D" }, "source": [ "Dictionaries can use the `keys` method for iterating.\n", "\n", "```\n", "my_dict.keys()\n", "\n", "for key in my_dict.keys():\n", " if len(key) > 4:\n", " print(my_dict[key])\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "MCT9ls_SXc_D" }, "outputs": [], "source": [ "my_dict.keys()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "52uJaLJSXc_E" }, "outputs": [], "source": [ "for key in my_dict.keys():\n", " if len(key) > 4:\n", " print(my_dict[key])" ] }, { "cell_type": "markdown", "metadata": { "id": "156cmnxSXc_E" }, "source": [ "#### 3.2.1 range()\n", "\n", "Manually constructing a list of sequential numbers is a total pain. A total pain. So Python has a **_function_** called `range` that simplifies the creation of **_lists_** that contain a sequence. Let's see it in action! Note that if we want a sequence from 0 to 2, inclusive, we call the `range` function with a argument of `3`. This is like the upper bound in **_slicing_** - it is always 1 plus the maximum value you want in the list.\n", "\n", "```\n", "range(3)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ytJKkaDdXc_E" }, "outputs": [], "source": [ "range(1000000000000)" ] }, { "cell_type": "markdown", "metadata": { "id": "gDlS44e4Xc_E" }, "source": [ "Wait up, hoss. That result doesn't look like a list! True. However, it acts identically to a list, but works a little different under the hood to save memory. The equivalent hand made list would look like this:" ] }, { "cell_type": "markdown", "metadata": { "id": "J3PRnQNeXc_E" }, "source": [ "```\n", "[0, 1, 2]\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "x1qfjr5VXc_E" }, "outputs": [], "source": [ "[0, 1, 2]" ] }, { "cell_type": "markdown", "metadata": { "id": "olxL8XQYXc_E" }, "source": [ "We can convert a `range` to a `list` by using the `list` type cast **_function_**.\n", "\n", "```\n", "list(range(3))\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "JxMtlmXNXc_F" }, "outputs": [], "source": [ "list(range(3))" ] }, { "cell_type": "markdown", "metadata": { "id": "vl_J5LhsXc_F" }, "source": [ "Notice that Python (in the newest versions, e.g. 3+) has an object type that is a range. This saves memory and speeds up calculations vs. an explicit representation of a range as a list - but it can be automagically converted to a list on the fly by Python. To show the contents as a `list` we can use the type case like with the tuple above.\n", "\n", "Sometimes, in older Python docs, you will see `xrange`. This used the range object back in Python 2 and `range` returned an actual list. Beware of this!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "era4lJpbXc_F" }, "outputs": [], "source": [ "list(range(3))" ] }, { "cell_type": "markdown", "metadata": { "id": "n9QGYe_GXc_F" }, "source": [ "Remember earlier with slicing, the syntax `:3` meant `[0, 1, 2]`? Well, the same upper bound philosophy applies here.\n", "\n", "```\n", "xs = [0, 1, 2]\n", "\n", "for x in xs[0:1]:\n", " if x < 2:\n", " print(x)\n", " else:\n", " pass\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ZAze7cddXc_F" }, "outputs": [], "source": [ "xs = [0, 1, 2]\n", "\n", "for x in xs[0:1]:\n", " if x < 2:\n", " print(x)\n", " else:\n", " pass" ] }, { "cell_type": "markdown", "metadata": { "id": "CoSV9k8YXc_F" }, "source": [ "Let's use range to acccess our instructor list using list element indexing. \n", "\n", "```\n", "for index in range(3):\n", " instructor = instructors[index]\n", " if instructor.endswith('Clown'):\n", " print(instructor + \" doesn't sound like a real instructor name!\")\n", " else:\n", " print(instructor + \" is so smart... all those gooey brains!\")\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "mZrMCd7qXc_F" }, "outputs": [], "source": [ "for index in range(5):\n", " instructor = instructors[index]\n", " if instructor.endswith('Hacker'):\n", " print(instructor + \" doesn't sound like a real instructor name!\")\n", " else:\n", " print(instructor + \" is so smart... all those gooey brains!\")" ] }, { "cell_type": "markdown", "metadata": { "id": "FOyJlHdNXc_G" }, "source": [ "This would probably be better written as below. Why is it better to use to use the `len()` function than hard code the length of the list?\n", "\n", "```\n", "for index in range(len(instructors)):\n", " instructor = instructors[index]\n", " if instructor.endswith('Hacker'):\n", " print(instructor + \" doesn't sound like a real instructor name!\")\n", " else:\n", " print(instructor + \" is so smart... all those gooey brains!\")\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "1Y6OVxvsXc_G" }, "outputs": [], "source": [ "for index in range(len(instructors)):\n", " instructor = instructors[index]\n", " if instructor.endswith('Hacker'):\n", " print(instructor + \" doesn't sound like a real instructor name!\")\n", " else:\n", " print(instructor + \" is so smart... all those gooey brains!\")" ] }, { "cell_type": "markdown", "metadata": { "id": "6N4VCXkDXc_G" }, "source": [ "But in all, it isn't very Pythonesque to use indexes like that (unless you have another reason in the loop) and you would opt instead for the `instructor in instructors` form. \n", "\n", "More often, you are doing something with the numbers that requires them to be integers, e.g. math." ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "-gb4cuCjXc_G" }, "outputs": [], "source": [ "sum = 0\n", "for i in range(10):\n", " sum += i\n", "print(sum)" ] }, { "cell_type": "markdown", "metadata": { "id": "COotO01dXc_H" }, "source": [ "Before we leave the topic of `range()`, let's take a quick look at the documentation for it [here](https://docs.python.org/3.3/library/stdtypes.html?highlight=range#ranges). Notice, it has another calling semantic than the one have have been using.\n", "\n", "We have been using this version:\n", "\n", "```\n", "range(stop)\n", "```\n", "Where the list will end at `stop` minus 1. There is another way the `range` **_function_** can be called which is to give it an inclusive `start` and an exclusive `stop`:\n", "\n", "```\n", "range(start, stop)\n", "```\n", "\n", "This returns a list of number that go from `start` to `stop` minus 1.\n", "\n", "Let's look at a quick example:\n", "\n", "```\n", "range(1, 9)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "f9MYvjxmXc_H" }, "outputs": [], "source": [ "range(1, 9)" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "0MozxrTFp2It" }, "outputs": [], "source": [ "\n", "list(range(1,9))\n" ] }, { "cell_type": "markdown", "metadata": { "id": "g1u1YSWqXc_I" }, "source": [ "What is the difference between `range(3)` and `range(0, 3)`? Use the cells below to experiment. It might help to **_typecast_** the resulting object to a `list` so you can see the result more clearly, e.g. `list(range(3))`" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "8HeDtMN2Xc_I" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "6_zcTmLAXc_J" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Jo0u9iNcXc_J" }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "id": "0BgcoLYoXc_J" }, "source": [ "#### 3.2.2 For loops can be nested\n", "\n", "You can put a for loop _inside_ another for loop. This is called _nesting_. Think of it like the [Matryoshka dolls](https://en.wikipedia.org/wiki/Matryoshka_doll). The example below has a nested loop that counts to four each time the outer loop counts up one. The `print` **_function_** shows the value of the outside loop iterator `i` and the inside loop iterator `j` and the product of the two values. Notice how the inside loop runs through 1 to 3 for each value of the outside loop.\n", "\n", "We use some string formatting for the `print` statement. These are called **_f-strings_** because there is an `f` before the string. Don't worry too much about the `print` function statement here as it isn't the point of this example. _Advanced topic_: for more on formatting strings, see [here](https://docs.python.org/3/tutorial/inputoutput.html#fancier-output-formatting).\n", "\n", "```\n", "for i in range(1, 4):\n", " for j in range(1, 4):\n", " print(f'{i} * {j} = {i * j}')\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "CNXyrWYoXc_J" }, "outputs": [], "source": [ "for i in range(1, 4):\n", " for j in range(1, 4):\n", " print(f'{i} * {j} = {i * j}')" ] }, { "cell_type": "markdown", "metadata": { "id": "mjL7S1csXc_J" }, "source": [ "#### 3.2.3 You can exit loops early if a condition is met\n", "\n", "Sometimes, in a for loop, you experience a condition where you want to terminate any further iterations of the loop. The **_reserved word_** `break` will completely exit a for loop. In this example, we exit the for loop when the iteration variable `i` is equal to the integer 4.\n", "\n", "```\n", "for i in range(10):\n", " if i == 4:\n", " break\n", "i\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "R5b8Jqt5Xc_J" }, "outputs": [], "source": [ "for i in range(10):\n", " if i == 4:\n", " break\n", "i" ] }, { "cell_type": "markdown", "metadata": { "id": "D2SpXAEWXc_J" }, "source": [ "#### 3.2.4 You can skip stuff in a loop with `continue`\n", "\n", "Sometimes, in a for loop, you want to skip certain elements. The `continue` statement will effectively skip any further statements for that element in a list. Below, we sum the numbers from `0` to `9` and skip the value `5`.\n", "\n", "```\n", "sum = 0\n", "for i in range(10):\n", " if i == 5:\n", " continue\n", " else:\n", " print(i)\n", " sum += i\n", " \n", "print(\"sum is \", sum)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "m4Dpio1vXc_K" }, "outputs": [], "source": [ "sum = 0\n", "for i in range(10):\n", " if i == 5:\n", " continue\n", " else:\n", " print(i)\n", " sum += i\n", " \n", "print(\"sum is \", sum)" ] }, { "cell_type": "markdown", "metadata": { "id": "xfY4gVfBXc_K" }, "source": [ "#### 3.2.5 You can iterate over letters in a string\n", "\n", "Strings are basically a list. Therefore, you can use a for loop to iteratre over the characters in a string. Note that `c` is a typical variable name for characters in a string. Generally, one letter variable names are not a good thing.\n", "\n", "```\n", "my_string = \"caffeine\"\n", "for c in my_string:\n", " print(c)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "xTxCMU2aXc_K" }, "outputs": [], "source": [ "my_string = \"caffeine\"\n", "for c in my_string:\n", " print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 4 Functions" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "For loops let you repeat some code for every item in a list. Functions are similar in that they run the same lines of code for new values of some variable. They are different in that functions are not limited to looping over items.\n", "\n", "Functions are a critical part of writing easy to read, reusable code.\n", "\n", "Create a function like:\n", "```\n", "def function_name (parameters):\n", " \"\"\"\n", " optional docstring\n", " \"\"\"\n", " function expressions\n", " return [variable]\n", "```\n", "\n", "_Note:_ Sometimes I use the word argument in place of parameter.\n", "\n", "Here is a simple example. It prints a string that was passed in and returns nothing.\n", "\n", "```\n", "def print_string(str):\n", " \"\"\"This prints out a string passed as the parameter.\"\"\"\n", " print(str)\n", " return\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To call the function, use:\n", "```\n", "print_string(\"Dave is awesome!\")\n", "```\n", "\n", "_Note:_ The function has to be defined before you can call it!" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print_string2(\"Dave is OK\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you don't provide an argument or too many, you get an error." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print_string()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.1 Function Parameters\n", "\n", "Parameters (or arguments) in Python are all passed by reference. This means that if you modify the parameters in the function, they are modified outside of the function.\n", "\n", "See the following example:\n", "\n", "```\n", "def change_list(my_list):\n", " \"\"\"This changes a passed list into this function\"\"\"\n", " my_list.append('four');\n", " print('list inside the function: ', my_list)\n", " return\n", "\n", "my_list = [1, 2, 3];\n", "print('list before the function: ', my_list)\n", "change_list(my_list);\n", "print('list after the function: ', my_list)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def change_list(my_list):\n", " \"\"\"This changes a passed list into this function\"\"\"\n", " my_list.append('four');\n", " print('list inside the function: ', my_list)\n", " return\n", "\n", "my_list = [1, 2, 3];\n", "print('list before the function: ', my_list)\n", "change_list(my_list);\n", "print('list after the function: ', my_list)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.2 For advanced folks...\n", "\n", "Variables have scope: **_global_** and **_local_**\n", "\n", "In a function, new variables that you create are not saved when the function returns - these are **_local_** variables. Variables defined outside of the function can be accessed but not changed - these are **_global_** variables, _Note_ there is a way to do this with the **_global_** keyword. Generally, the use of **_global_** variables is not encouraged, instead use parameters.\n", "\n", "```\n", "my_global_1 = 'bad idea'\n", "my_global_2 = 'another bad one'\n", "my_global_3 = 'better idea'\n", "\n", "def my_function():\n", " print(my_global)\n", " my_global_2 = 'broke your global, man!'\n", " global my_global_3\n", " my_global_3 = 'still a better idea'\n", " return\n", " \n", "my_function()\n", "print(my_global_2)\n", "print(my_global_3)\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In general, you want to use parameters to provide data to a function and return a result with the `return`. E.g.\n", "\n", "```\n", "def sum(x, y):\n", " my_sum = x + y\n", " return my_sum\n", "```\n", "\n", "If you are going to return multiple objects, what data structure that we talked about can be used? Give and example below." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 4.3 Parameters have different types:\n", "\n", "| type | behavior |\n", "|------|----------|\n", "| required | positional, must be present or error, e.g. `my_func(first_name, last_name)` |\n", "| keyword | position independent, e.g. `my_func(first_name, last_name)` can be called `my_func(first_name='Dave', last_name='Beck')` or `my_func(last_name='Beck', first_name='Dave')` |\n", "| default | keyword params that default to a value if not provided |\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "def print_name(first, last='the Data Scientist'):\n", " print('Your name is %s %s' % (first, last))\n", " return\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def print_name(first, last='the Data Scientist'):\n", " print('Your name is %s %s' % (first, last))\n", " return" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Play around with the above function." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print_name('Dave', last='his Data Science Majesty')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions can contain any code that you put anywhere else including:\n", "* if...elif...else\n", "* for...else\n", "* while\n", "* other function calls" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "def print_name_age(first, last, age):\n", " print_name(first, last)\n", " print('Your age is %d' % (age))\n", " if age > 35:\n", " print('You are really old.')\n", " return\n", "```\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "def print_name_age(first, last, age):\n", " print_name(first, last)\n", " print('Your age is %d' % (age))\n", " if age > 35:\n", " print('You are really old.')\n", " return" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```\n", "print_name_age(age=46, last='Beck', first='Dave')\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "print_name_age(age=46, last='Beck', first='Dave')" ] }, { "cell_type": "markdown", "metadata": { "id": "0HkLaZ7sXc_K", "tags": [] }, "source": [ "## 5 The Zen of Python\n", "\n", "Finally, let's use end with a philosophy of Python. This is a fun [Easter Egg](https://en.wikipedia.org/wiki/Easter_egg_(media)), to see it, `import this`:" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "ri49oLdbXc_K" }, "outputs": [], "source": [ "import this" ] }, { "cell_type": "markdown", "metadata": { "id": "ohjY-dUcXc_K" }, "source": [ "## 6 References\n", "\n", "Some links to references from content in this notebook are consolidated here for easy access. Enjoy!\n", "\n", "* [Using equations in Markdown in Jupyter notebooks](https://medium.com/analytics-vidhya/writing-math-equations-in-jupyter-notebook-a-naive-introduction-a5ce87b9a214)\n", "* [How numbers are represented in a computer](http://steve.hollasch.net/cgindex/coding/ieeefloat.html)\n", "* [Grace Hopper](https://en.wikipedia.org/wiki/Grace_Hopper) and [her photo of a `bug` in her notebook](https://en.wikipedia.org/wiki/Grace_Hopper#/media/File:First_Computer_Bug,_1945.jpg)\n", "* Programmer culture touchpoint: the word [grok](https://en.wikipedia.org/wiki/Grok)\n", "* Converting code from one programming language to another is called [Porting](https://en.wikipedia.org/wiki/Porting)\n", "* _slices_ and _ranges_ in Python are known as **[_half-open intervals_](https://en.wikipedia.org/wiki/Interval_(mathematics))**\n", "* [Python documentation for lists](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists)\n", "* [Negative list indices in Python](https://googlethatforyou.com?q=negative%20indexing%20in%20python)\n", "* [Python documentation for dictionaries](https://docs.python.org/3/tutorial/datastructures.html#dictionaries)\n", "* [Python documentation for the `range` function](https://docs.python.org/3.3/library/stdtypes.html?highlight=range#ranges)\n", "* [Third party documentation for `if` statements](https://www.w3schools.com/python/python_conditions.asp)\n", "* [Third party documentation for `for` loops](https://www.w3schools.com/python/python_for_loops.asp)\n", "* [Third party documentation for functions](https://www.w3schools.com/python/python_functions.asp)\n", "* The correct name for the \"Russian Nesting Doll\" is a \"[Matryoshka doll](https://en.wikipedia.org/wiki/Matryoshka_doll)\"\n", "* [Formatting strings to include values of variables](https://docs.python.org/3/tutorial/inputoutput.html#fancier-output-formatting)\n", "* [Zen of Python](https://www.python.org/dev/peps/pep-0020/)\n", "* [Easter Egg](https://en.wikipedia.org/wiki/Easter_egg_(media))" ] }, { "cell_type": "markdown", "metadata": { "id": "gCo9fPQ8Xc_K" }, "source": [ "## 7 Breakout for Data Structures and Flow Control\n", "\n", "\n", "\n", "### 7.1 The FizzBuzz task\n", "\n", "Let's do this! **FizzBuzz** is our first task for today. **FizzBuzz** is a common toy programming problem that is often used in software engineering job interviews. Today, we are not after the _most compact_, _most clever_, or even the _most beautiful_ solution. Your goal is to solve the problem using **_for_** and **_if_** as your primary tools. You will likely also want to use the `%` operator. Before we describe **FizzBuzz**, let's talk about the **moduluo** operation.\n", "\n", "If you recall from yesterday, you may have experimented with the **_[modulus](https://en.wikipedia.org/wiki/Modulo_operation)_** or `%` operator. When used between two **_integer_** values, it returns the integer remainder of division. Let's start with a simple example of `5` **modulo** `3`:\n", "\n", "```\n", "5 % 3\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "cU9ZZN8gX1H4" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "wjZB4-3oXc_K" }, "outputs": [], "source": [ "5 % 3" ] }, { "cell_type": "markdown", "metadata": { "id": "pPtPe5i1Xc_K" }, "source": [ "Let's do another example... What is the result of the following:\n", "\n", "```\n", "10 % 5\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Nn9m33lDXc_L" }, "outputs": [], "source": [ "10 % 5" ] }, { "cell_type": "markdown", "metadata": { "id": "_RVFkybfXc_L" }, "source": [ "Now, on to **FizzBuzz**. No it isn't the high-test caffeine cola you might need right now. Instead, it is a challenge to output certain text as the code iterates over elements in a list. Here is the formal definition of the problem that we will use today.\n", "\n", "_\"Write a program that prints the numbers from 1 to 100. But for multiples of three print `Fizz` instead of the number and for the multiples of five print `Buzz`. For numbers which are multiples of both three and five print `FizzBuzz`.\"_" ] }, { "cell_type": "markdown", "metadata": { "id": "fhVO2co1Xc_L" }, "source": [ "To get started, you will need a `for` loop and it will probably use a `range` list. Inside of the for loop, you will likely have at least two `if` statements that use the `%` operator followed by a `print`.\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "eJtkMjCvXc_L" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "dSmde3x7Xc_L" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "OTmq4esUXc_L" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "f_VbOXLdXc_L" }, "outputs": [], "source": [] }, { "cell_type": "markdown", "metadata": { "id": "Wev8o3W6Xc_L" }, "source": [ "\n", "For advanced folks, a hint here is that you might be able to avoid some `if` statements by using the `end` parameter to the `print` function. Notice how these two cell blocks output differently.\n", "\n", "```\n", "print(\"Fizz\")\n", "print(\"Buzz\")\n", "```\n", "\n", "In another cell:\n", "\n", "```\n", "print(\"Fizz\", end=\"\")\n", "print(\"Buzz\", end=\"\")\n", "print()\n", "```" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "y7THsstdXc_L" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "b9OgPgSuXc_L" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "owE3ll8uXc_L" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "OITXjc62bY4n" }, "outputs": [], "source": [ "\n" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Se_EV7gobbAa" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "WIdtMY2nbf0Y" }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "id": "Um5NnUosbsV8" }, "outputs": [], "source": [] } ], "metadata": { "colab": { "collapsed_sections": [], "name": "C-HACK_Tutorial_2_Data_Structures_and_Flow_Control.ipynb", "provenance": [ { "file_id": "1qBs73jU3dqbA0U4YDHikej7YVkxzEMdZ", "timestamp": 1609868436325 } ], "toc_visible": true }, "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.13" } }, "nbformat": 4, "nbformat_minor": 4 }