diff --git a/Life-after-the-course.ipynb b/Life-after-the-course.ipynb deleted file mode 100644 index 7fb7e42..0000000 --- a/Life-after-the-course.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Life-after-the-course.ipynb","provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyMSn0HmmK8l6LguBLkg2C2D"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"QMJDG-UsDngf"},"source":["# Life after the course\n","\n","Entry level programming in Python - CDH 2021\n","\n","Congratulations, you finished the course. During the course, you learned basic Python techniques as well as important refactoring and debugging skills. Finally, you learned how to import CSV files and obtained leads on how to conduct your own analysis.\n","\n","Due to the limited time, we could not cover all the basic skills that a programmer needs in order to be economic with her development time. Also, while online notebooks are a great teaching tool and we would not have been able to cover as much ground without them, you will be better able to reuse your own code if you learn how to run standalone Python programs on your own computer.\n","\n","In order to help you with the next steps on your learning journey, we list the concepts below and provide links to web pages where you can learn more about the topic in question. We recommend that you scroll through the entire notebook; all principles and techniques discussed here are essential best practices."]},{"cell_type":"markdown","metadata":{"id":"F2I_ZaA9J496"},"source":["## Troubleshooting\n","\n","Whether you are trying to install something and it is refusing or your own code is throwing errors at you, more often than not a well-chosen web search will lead you to a solution. Good queries generally include the name of the program or package that you use, the name of the feature or function that you use, and the name of the error that you get (or a concise description of the problem: \"no output\", \"lower value than expected\", etcetera). For example [`pandas read_csv EncodingError`](https://duckduckgo.com/?q=pandas+read_csv+EncodingError).\n","\n","In many cases, a web search will lead you to [Stack Overflow](https://stackoverflow.com) (or a related question-and-answer site). You can also post your own questions about code-related problems here. There are some [tips](https://stackoverflow.com/help/how-to-ask) to help you maximize the change that you'll get a useful answer. If somebody answers your question adequately, be sure to [accept the answer](https://stackoverflow.com/help/someone-answers)."]},{"cell_type":"markdown","metadata":{"id":"cCxnaLPZVblw"},"source":["## Command line interface (CLI, shell)\n","\n","Command line interfaces (CLIs) let you control your computer by typing commands instead of by clicking with your mouse. Every PC comes with a CLI by default (including macs). On Windows, the default CLI is called Command Prompt (`cmd.exe`) while on other platforms, it is usually called Terminal. In both cases, the text-based interface running within the window is called the *shell*. Since the distinction is not so important most of the time, we often use the word \"shell\" or \"terminal\" to refer to either.\n","\n","You don't need to be a shell expert, but being able to navigate your file system and to run basic commands can be very useful when programming on your own PC. There are many [introductory tutorials online](https://duckduckgo.com/?q=basic+command+line+interface+tutorial). https://ss64.com is a useful cross-platform reference of standard commands and syntax."]},{"cell_type":"markdown","metadata":{"id":"E343lYdIZvPB"},"source":["## Software needed for editing and running Python on your PC\n","\n","Running standalone Python on your PC is a bit different from using notebooks. At the very least, you will need a code editor and a Python interpreter. As the name suggests, a Python interpreter is a program that reads Python code and executes the program that is described in the code.\n","\n","Over time, programmers usually end up installing a lot of other software as well. For this reason, it is generally worthwhile to install a package manager."]},{"cell_type":"markdown","metadata":{"id":"TsJgFTy7hiPv"},"source":["### Editor\n","\n","While there are more options, we will mention a few general-purpose code editors that are both widely used and actively maintained:\n","\n","- [BBEdit](https://www.barebones.com/products/bbedit/index.html) (macOS)\n","- [Notepad++](https://notepad-plus-plus.org) (Windows)\n","- [Sublime Text](https://www.sublimetext.com) (cross-platform)\n","- [TextMate](https://macromates.com) (macOS)\n","- [Visual Studio Code](https://code.visualstudio.com) (cross-platform)\n","\n","There are also \"integrated development environments\" (IDEs) specifically targeted at Python programming, such as [Spyder](https://www.spyder-ide.org) for data scientists and [PyCharm](https://www.jetbrains.com/pycharm/) for application developers. These have lots of bells and whistles. Some people find them very convenient. We mention them here for completeness, but we recommend learning how to work without one first."]},{"cell_type":"markdown","metadata":{"id":"agGDd9aQk_or"},"source":["### Python and a package manager\n","\n","macOS and Linux come with Python preinstalled by default, though this is usually an outdated version of Python. In principle, you *could* also just [download Python from the website](https://www.python.org/downloads/). However, since it is likely that you'll be installing more software alongside Python, we recommend investing some additional time to install a package manager instead, which will give you a central workflow for installing Python as well as any related software. Especially on Windows, using a package manager will likely provide a smoother experience as well.\n","\n","One approach to installing a package manager is [Anaconda](https://www.anaconda.com). It is specifically targeted at data scientists working with Python and it ships with many commonly used Python packages by default, as well as the Spyder IDE that we mentioned in the editor section. For a much smaller download, you can install [miniconda](https://docs.conda.io/en/latest/miniconda.html) instead, to get just Python, Anaconda's package manager (`conda`) and a small amount of supporting software. While conventient, `conda` is not a complete solution like the general purpose package managers that we discuss next.\n","\n","Linux distribution generally ship with a general purpose package manager by default, such as `apt-get` or `yum`. If you work with Linux, you are probably already familiar with your package manager. If you install Python through such a package manager, you might need to install a secondary package for Python *development* as well, which might for example be named `python-devel`.\n","\n","macOS does not ship with a package manager by default, but you can install [MacPorts](https://www.macports.org) or [HomeBrew](https://brew.sh).\n","\n","Windows does not follow the same conventions as Linux and macOS, but there are options. [Chocolatey](https://chocolatey.org) is a dedicated package manager for Windows. Since Windows 10, Microsoft provides its own [native package manager](https://docs.microsoft.com/en-us/windows/package-manager/) as well. At the DH Lab, we have tried neither of these options, so we cannot comment on how well they work. Alternatively, you can use the `pacman` package manager that is included with [Git for Windows](https://gitforwindows.org), which we recommend to install anyway. More about Git in a later section."]},{"cell_type":"markdown","metadata":{"id":"SprAGQ0AzjfR"},"source":["## Basic workflow for running standalone Python\n","\n","Notebooks contain a mixture of formatted text and runnable snippets of Python code. Standalone Python programs, on the other hand, are plain text files containing only Python code (including comments) with the `.py` extension. Suppose that you copy-paste the following code into a new file using your code editor, and save it with the name `hello.py`:\n","\n","```python\n","print('Hello, world!')\n","```\n","\n","Using a shell, you can now navigate to the folder containing `hello.py` and type the following command in order to run it:\n","\n","```shell\n","python3 hello.py\n","```\n","\n","On Windows, depending on how you installed Python, you might need to run `py` instead of `python3`.\n","\n","*On Windows, the `python3` or `py` command will only work if your shell knows where to find Python. If you installed Python through a package manager, use the shell that ships with it, such as Anaconda Prompt. If you downloaded Python directly from the website, search the web on how to set the `PATH` environment variable and optionally also `PATHEXT`).*\n","\n","Typing just `python` instead of `python3` might work, too, but in some cases, this is still Python version 2 because it was installed on your PC by default. You can check the version like this:\n","\n","```shell\n","python --version\n","```"]},{"cell_type":"markdown","metadata":{"id":"Q0sFMv09Vzdp"},"source":["## Modules\n","\n","The official name for a plain text file that contains Python code is *module*. The `hello.py` from the previous section is an example of a module. Modules are named this way because your program can consist of multiple files, so they enable *modular programming*. Spreading your code over multiple files can make it easier to find back the right piece of code (if you chunk your code in a logical way). Individual modules can also be reused in new programs.\n","\n","A module or group of modules that is specifically meant for reuse is called a *library*. By convention, a library is usually saved in a separate folder and we call that folder a *package*. We will discuss libraries and packages again in the section on dependencies.\n","\n","Suppose that we have a module named `cheerlead.py` with the functions that we wrote for the third exercise (the short notation used here was discussed in the \"Iterables\" section of the final exercise tips):"]},{"cell_type":"code","metadata":{"id":"N69uA9Ibrakg"},"source":["announce = 'We have a: {}'.format\n","yell = 'Go go {}!!!'.format\n","\n","def cheer(name):\n"," letters = '\\n'.join(map(announce, name))\n"," return '\\n'.join([letters, yell(name)])"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"A-5PwPAYra7B"},"source":["and we have a second module in the same folder, named `greet.py`, which uses the `cheer` function from `cheerlead.py`:\n","\n","```python\n","from cheerlead import cheer\n","\n","name = input('Welcome, visitor. What is your name? ')\n","print(cheer(name))\n","```\n","\n","We can now run\n","\n","```shell\n","python3 greet.py\n","```\n","\n","While `greet.py` contains only part of the program, Python knows where to find the rest by following the `import` statements. You can read more about modules [here](https://docs.python.org/3/tutorial/modules.html)."]},{"cell_type":"markdown","metadata":{"id":"Lp68EBfdDp6B"},"source":["## Dependencies\n","\n","So far, we have used the word \"package\" liberally, but there are actually two kinds of \"package\": it can either refer to any software that you install using your package manager (such as Python itself), or to a collection of Python modules that was published for general reuse. This section is about the latter kind. When you use such a Python package in your project, this is called a dependency.\n","\n","All the `import` statements that we have seen in examples so far, can be roughly divided into three categories. Firstly, imports from other modules in the same directory, which are often written by the same author. The following examples appeared in previous sections:\n","\n","```python\n","from cheerlead import cheer\n","from greet import main as greet_main\n","```\n","\n","Secondly, imports from *standard modules*. These modules are part of the standard library that ships with Python, so you never need to install them manually. Most of the following examples appeared in the tips:\n","\n","```python\n","import csv\n","import os.path as op\n","from operator import add\n","from itertools import repeat\n","from functools import reduce\n","from statistics import mean, stdev\n","from datetime import datetime as dt\n","```\n","\n","Finally, imports from *third-party packages*. These are neither part of your own code, nor of the Python standard library. The following examples appeared in the last two sections of the tips:\n","\n","```python\n","import pandas\n","from sklearn.cluster import AgglomerativeClustering\n","```\n","\n","In Google Colab, many third-party packages are installed by default, so the code examples just worked. In the general case, however, third-party packages must be downloaded first. When your program requires such packages in order to run, it is necessary to document those dependencies. In the next three subsections, we discuss the main ingredients that you need in order to manage your dependencies well."]},{"cell_type":"markdown","metadata":{"id":"nxzGlbHfRIN1"},"source":["### Virtual environments\n","\n","Once you start programming, you never stop. After your first program, there will be more projects. At some point, you might even be working on two or more projects in parallel.\n","\n","It is unlikely that two projects have exactly the same dependencies. In many cases, the dependencies of one project will conflict with the dependencies of another. For this reason (and a few other reasons), it is highly recommended to keep separate sets of installed dependencies for each project. This is the job of virtual environments.\n","\n","A virtual environment is a folder in which you install third-party packages. You can have as many virtual environments as you want. Each virtual environment can also have its own version of Python. When you *activate* a virtual environment, its installed packages become available to you, while the packages inside all other virtual environments are invisible. When you install additional packages, they are added to the active virtual environment only.\n","\n","In the most basic case, you run `python3 -m venv` in the shell and tell it to create a new environment in a given directory. For example, the following command will create an environment in the folder `.env` within your current working directory:\n","\n","```shell\n","python3 -m venv .env\n","```\n","\n","After the above command, you can activate the environment like this on Linux, macOS and emulating environments like the MSYS2 included in Git for Windows:\n","\n","```shell\n","source .env/bin/activate\n","```\n","\n","and like this in the Windows Command Prompt:\n","\n","```shell\n",".env\\Scripts\\activate.bat\n","```\n","\n","After this you can run `deactivate` to leave the environment again. There are a couple of variations possible, such as selecting a different version of Python. You can read more about creating and using virtual environments [here](https://docs.python.org/3/tutorial/venv.html).\n","\n","Beyond the basic case, there are various tools that add sophistications, such as storing environments in a central place and switching between them with shorter commands. Anaconda/miniconda takes this quite far by including environment creation and switching into its own `conda` command. You can read more about that [here](https://docs.conda.io/projects/conda/en/latest/user-guide/getting-started.html)."]},{"cell_type":"markdown","metadata":{"id":"Aydk8okoYqV3"},"source":["### Installing packages\n","\n","By default, every virtual environment has the `pip` command, which lets you install third-party packages that were published to the [Python Package Index (PyPI)](https://pypi.org). Basically, this is a second, dedicated package manager just for Python packages. Manually installing a single package, for example `pandas`, looks like this:\n","\n","```shell\n","python3 -m pip install pandas\n","```\n","\n","Of course, it is also possible to update packages and to uninstall them again. You can read more about pip [here](https://packaging.python.org/installing/). Again, `conda` has its own way of doing things, which you can read more about [here](https://conda.io/projects/conda/en/latest/user-guide/tasks/manage-pkgs.html)."]},{"cell_type":"markdown","metadata":{"id":"oypf9UVDcbVS"},"source":["### `requirements.txt`\n","\n","When using an external package, it is often the case that the feature you need was not yet present in an older version. It might also be removed again in a newer version. For this reason, the **versions** of the packages that you use, **are very important**. Each package itself might again depend on other packages (such indirect dependencies are automatically included when you `pip install` a package), and the versions of those indirect dependencies matter as well.\n","\n","It is **vitally important** to record the exact versions of all your direct and indirect dependencies, so that you can reproduce your environment at a later time or on a different computer. Without this, *it might be impossible to get your program to work again*.\n","\n","By convention, we store a listing of all direct and indirect dependencies with their exact versions in a file called `requirements.txt`. You can quickly create or update a `requirements.txt` based on the contents of your active virtual environment with `pip freeze`:\n","\n","```shell\n","python3 -m pip freeze > requirements.txt\n","```\n","\n","With `conda`, you can also do this:\n","\n","```shell\n","conda list > requirements.txt\n","```\n","\n","You should run either command again every time you add, update or remove a package. When publishing your code, **always** include the `requirements.txt`.\n","\n","You can install all the exact versions of packages specified in a `requirements.txt` using `pip install -r`:\n","\n","```shell\n","python3 -m pip install -r requirements.txt\n","```\n","\n","See [here](https://pip.pypa.io/en/latest/user_guide/#requirements-files) for more information about `requirements.txt`. There are some tools, such as [pip-tools](https://pypi.org/project/pip-tools/), that streamline the management of the `requirements.txt` and which can also automatically remove indirect dependencies that are no longer needed after an update.\n","\n","The `setup.py` or `setup.cfg` that comes with [`setuptools`](https://setuptools.pypa.io/en/latest/userguide/quickstart.html) is a more sophisticated alternative to the `requirements.txt`. It is recommended to convert to using `setuptools` when you consider publishing your package to PyPI. Like `requirements.txt`, it integrates well with `pip`."]},{"cell_type":"markdown","metadata":{"id":"rPBZJd32-I_i"},"source":["## The interactive Python prompt\n","\n","If you just enter `python3` in the shell, without passing the name of a module, Python will run in interactive mode. It shows a prompt that looks like this:\n","\n"," >>>\n","\n","After the prompt, you can enter any Python code. It can also be an `import` statement in order to retrieve functions from an existing module. Python will run the code that you enter, print any output and then present you with a new prompt. Among other things, this is useful for debugging individual functions, for using Python as an advanced calculator, or for trying out short snippets of code before typing them into a module.\n","\n","You can exit the interactive prompt by typing `quit()` (note that this doesn't work inside a regular module). You can also type `help()` for very helpful interactive documentation."]},{"cell_type":"markdown","metadata":{"id":"yn6rwOg-0Tmz"},"source":["## `main`\n","\n","In the example from the previous section, there was a very strict task division between `cheerlead.py` and `greet.py`. `cheerlead.py` contained only reusable functions. If you were to run `python cheerlead.py`, it would silently exit without reading input or printing output. `greet.py`, on the other hand, contained *no* reusable code and was *only* fit for being run as a program. If we were to do `import greet` inside another module, that module would always ask for the same input and print the same output as `greet.py` would do, even if that other module is actually supposed to do something else. We could say that `cheerlead.py` is a reusable module while `greet.py` is a program entry point, although this isn't an official distinction.\n","\n","The task division doesn't have to be so strict. We can write modules that are both fit for reuse and that can also be run as a program. In order to do this, we follow the convention of defining a `main` function. All code that is supposed to run only when the module is run as a program, should go inside `main`. We can rewrite `greet.py` to follow this convention:\n","\n","```python\n","from cheerlead import cheer\n","\n","def main():\n"," # same code as before, now inside main\n"," name = input('Welcome, visitor. What is your name? ')\n"," print(cheer(name))\n","\n","# call main, but only if this module was\n","# run as the entry point of the program\n","if __name__ == '__main__':\n"," main()\n","```\n","\n","With the above adjustment, `python greet.py` will read input and print output as before, but the same will not happen if we do `import greet` inside another module and then run that module. Though we can still achieve that by explicitly importing and calling `main` if we want to:\n","\n","```python\n","from greet import main as greet_main\n","\n","def main():\n"," print('This module is mostly doing the same as greet.py.')\n"," greet_main()\n","\n","if __name__ == '__main__':\n"," main()\n","```\n","\n","We could now continue to add a `main` function to `cheerlead.py` as well, and to add reusable functions to `greet.py` for importing in other modules. In this way, every module can be a reusable module and a program entry point at the same time."]},{"cell_type":"markdown","metadata":{"id":"a4INew0rDA5I"},"source":["## Exit status (exit code)\n","\n","A long-standing convention in shells is that programs \"return\" a number when they exit, similar to how a function might return a value. So far, we have done nothing to indicate what should be this *exit status* of our program. By default, Python assumes that we want to set the exit status to `0` (zero), so that has been the implicit exit code of our programs. We can see the exit code of the last command that we ran using `echo %ERRORLEVEL%` in the Windows Command Prompt, or `echo $?` in most other shells:\n","\n","```shell\n","python3 greet.py\n","echo $?\n","```\n","\n","The shell uses the exit status to detect whether a command ran successfully. Zero indicates success while non-zero exit codes indicate failure. Some programs use different numbers to indicate different ways in which they can fail.\n","\n","You are not required to set the exit code explicitly. If your program terminates with an error, Python will set the exit status to `1` by default, so that the shell understands that the program failed. You *can* however set the exit code explicitly using `sys.exit` (which also immediately terminates the program). A common pattern is to return a number from the `main` function and then pass this to `sys.exit`. We demonstrate this pattern in the small program below:\n","\n","```python\n","import sys\n","\n","def main():\n"," # Let's see whether Python is consistent today.\n"," if 1 < 2:\n"," return 0 # success\n"," else:\n"," return 1 # failure\n","\n","if __name__ == '__main__':\n"," sys.exit(main())\n","```"]},{"cell_type":"markdown","metadata":{"id":"9lR2Badd7pon"},"source":["## Program arguments\n","\n","We have previously shown the program `greet.py`, which will ask us for a name and then cheer it. Arguably, it would be a bit more efficient if we could pass the name already when calling the program, so we could skip the interactive question. Something like this:\n","\n","```shell\n","python3 greet.py Julian\n","```\n","\n","In the above example command, `Julian` is an argument to the `greet.py` program, similar to how we can pass arguments to functions.\n","\n","Using program arguments is a great way to make your program more flexible. For example, by making the path to a file a program argument, you make it easier to run your program with other files, or on another computer, where files might be located in a different folder.\n","\n","In the previous section, we saw `sys.exit`, which lets us set the program exit code; the same `sys` standard module also provides `argv`, which is a list with the program arguments, including the name of your program as the first element. Since `main` represents the program as a whole, let's extend the pattern for invoking `main` to include both program arguments and the exit status:\n","\n","```python\n","import sys\n","\n","def main(argv):\n"," if len(argv) == 1:\n"," print(\"You didn't pass any arguments.\")\n"," return 1\n"," print('You passed these arguments:')\n"," print(argv[1:])\n"," return 0\n","\n","if __name__ == '__main__':\n"," sys.exit(main(sys.argv))\n","```\n","\n","In the general case, a program may have many parameters, some of which may be optional. There is a syntax for working with named arguments as well, which would look like `python3 greet.py --name Julian` in our example above. By convention, the most important named arguments can also be abbreviated, which would look like `-n` instead of `--name`. You may also have parameters that accept a variable number of values, and then we generally expect that we can pass named arguments in any order. As you might imagine, extracting all that information correctly from `sys.argv`, which is just a simple list of strings, would be really difficult. Thankfully, you don't have to do this yourself.\n","\n","The `argparse` standard module gives you the means to just describe which arguments your program expects. It will read `sys.argv` for you and figure out what goes with what. The Python documentation includes an excellent [tutorial](https://docs.python.org/3/howto/argparse.html) on how to use it, so we won't do that here.\n","\n","Assuming that you have read that tutorial, here is a pattern that we suggest for integrating `argparse` in the invocation of your `main` function:\n","\n","```python\n","import sys\n","import argparse\n","\n","# The argument parser is defined outside of the main function.\n","# In a large program with many options, you might even have\n","# a dedicated module just for the argument parser.\n","argparser = argparse.ArgumentParser(\n"," description='Description of your program',\n"," # maybe you also want to define an epilog\n",")\n","\n","def main(argv):\n"," options = argparser.parse_args(argv[1:])\n"," # the options object can be passed to other functions that\n"," # main calls internally\n"," return 0\n","\n","if __name__ == '__main__':\n"," sys.exit(main(sys.argv))\n","```\n","\n","As a final tip, we will mention that you can save a set of arguments to a file and then pass the name of that file to your program in order to have all arguments in the file applied. This is functionality that `argparse` gives us for free. Suppose that I often want to run `python3 greet.py --name Julian`. I can write the following in a file named `greet.conf`:\n","\n"," --name\n"," Julian\n","\n","If I then run `python3 greet.py @greet.conf`, it will do exactly the same as when I would run `python3 greet.py --name Julian`. In this case, the difference is not so impressive, but when you are passing more than a few arguments, this can be very convenient."]},{"cell_type":"markdown","metadata":{"id":"XXiw0yh4IoWE"},"source":["## Assertions\n","\n","Python has an `assert` keyword that lets you check that a condition that *should* be `True` is *actually* `True`. This is different from `if`, where the truth of the condition is optional; if you `assert` a condition and it is `False`, your program will stop with an error message. We can use this to protect ourselves and other programmers from mistakes. For example, we can add an assertion to our `cheer` function as follows:"]},{"cell_type":"code","metadata":{"id":"Hv82mos_Ditb"},"source":["def cheer(name):\n"," assert isinstance(name, str)\n"," letters = '\\n'.join(map(announce, name))\n"," return '\\n'.join([letters, yell(name)])"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"pdYC4dG8qbi1"},"source":["Now, our program will still work if used as intended, but if somebody passes a number, the program will fail with an `AssertionError`:"]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":402},"id":"c1H0veEyqxlr","executionInfo":{"status":"error","timestamp":1638205958138,"user_tz":-60,"elapsed":313,"user":{"displayName":"J Gonggrijp","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"10559993329647399108"}},"outputId":"b9d7d157-e102-41cb-d64e-679ae19f2fa5"},"source":["print(cheer('Kermit'))\n","print(cheer(100))"],"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["We have a: K\n","We have a: e\n","We have a: r\n","We have a: m\n","We have a: i\n","We have a: t\n","Go go Kermit!!!\n"]},{"output_type":"error","ename":"AssertionError","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)","\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcheer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'Kermit'\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[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcheer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m100\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\u001b[0m in \u001b[0;36mcheer\u001b[0;34m(name)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcheer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\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[0;32massert\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\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 3\u001b[0m \u001b[0mletters\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'\\n'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mannounce\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\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[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;34m'\\n'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mletters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0myell\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\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;31mAssertionError\u001b[0m: "]}]},{"cell_type":"markdown","metadata":{"id":"5TGC07rTr_mb"},"source":["We can make the error more informative by adding a comma and a string that will appear when the assertion fails:"]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":317},"id":"9TUQ7gVzsdyS","executionInfo":{"status":"error","timestamp":1638206188361,"user_tz":-60,"elapsed":317,"user":{"displayName":"J Gonggrijp","photoUrl":"https://lh3.googleusercontent.com/a/default-user=s64","userId":"10559993329647399108"}},"outputId":"87ddce03-0a2b-4fdc-c877-e0c045b3ff33"},"source":["def cheer(name):\n"," assert isinstance(name, str), 'name must be a string'\n"," letters = '\\n'.join(map(announce, name))\n"," return '\\n'.join([letters, yell(name)])\n","\n","print(cheer(100))"],"execution_count":null,"outputs":[{"output_type":"error","ename":"AssertionError","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)","\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;34m'\\n'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mletters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0myell\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\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[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 6\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcheer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m100\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\u001b[0m in \u001b[0;36mcheer\u001b[0;34m(name)\u001b[0m\n\u001b[1;32m 1\u001b[0m \u001b[0;32mdef\u001b[0m \u001b[0mcheer\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\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[0;32massert\u001b[0m \u001b[0misinstance\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mstr\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'name must be a string'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 3\u001b[0m \u001b[0mletters\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'\\n'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmap\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mannounce\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mname\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[1;32m 4\u001b[0m \u001b[0;32mreturn\u001b[0m \u001b[0;34m'\\n'\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mjoin\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mletters\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0myell\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mname\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[1;32m 5\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n","\u001b[0;31mAssertionError\u001b[0m: name must be a string"]}]},{"cell_type":"markdown","metadata":{"id":"S3n1rFNcswVL"},"source":["You can use as few or as many assertions in your code as you want. This is mostly a matter of taste. You don't need to omit them for performance; if you have a program that needs to run for a long time and you worry that the assertions might be slowing it down, just run `python3 -o program.py` instead of `python3 program.py` and all assertions will be skipped. Just keep in mind that assertions are meant for checking assumptions, rather than for reporting errors; for reporting errors there is the `raise` keyword, which you can read more about in Python's [exceptions tutorial](https://docs.python.org/3/tutorial/errors.html).\n","\n","There is however a special type of function that is all about writing assertions: the unittest."]},{"cell_type":"markdown","metadata":{"id":"Ajt86gVUv02n"},"source":["## Testing\n","\n","So far, when we wrote a function and we wanted to check that it worked, we just wrote a line in which we called the function. We did this in notebooks, and we could also use the interactive Python prompt for this purpose.\n","\n","```python\n","print(yell('Kermit'))\n","```\n","\n","We expect this line to output `Go go Kermit!!!`.\n","\n","If we edit the `yell` function again in the future, we will want to write such a line of code again to check that it still works. However, this would mean repeating ourselves. Better would be to save our test code in a function so we can run it as often as we want. Such a function is called a unittest. A unittest for the `yell` function might look like this:"]},{"cell_type":"code","metadata":{"id":"eB4uCJ4xyvE8"},"source":["def test_yell():\n"," assert yell('Kermit') == 'Go go Kermit!!!'"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"Gr-9hXvnzLhh"},"source":["We might as well write tests for `announce` and `cheer` while we're at it and save all of our tests in a module named `cheerlead_test.py`, next to the `cheerlead.py` module:"]},{"cell_type":"code","metadata":{"id":"SCtmdYJA0FgH"},"source":["from cheerlead import announce, yell, cheer\n","\n","def test_yell():\n"," assert yell('Kermit') == 'Go go Kermit!!!'\n","\n","def test_announce():\n"," assert announce('x') == 'We have a: x'\n","\n","def test_cheer():\n"," name = 'Rose'\n"," output = cheer(name)\n"," lines = output.splitlines()\n"," assert len(lines) == len(name) + 1\n"," for index, letter in enumerate(name):\n"," assert lines[index] == announce(letter)\n"," assert lines[-1] == yell(name)\n","\n","def main():\n"," # Note that we are putting function names in a list.\n"," # This is allowed! You can do it, too!\n"," tests = [test_yell, test_announce, test_cheer]\n"," for test in tests:\n"," test()\n","\n","if __name__ == '__main__':\n"," main()"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"kb_40quq2DN7"},"source":["Now, whenever we change the contents of `cheerlead.py`, we only need to run `python cheerlead_test.py` in order to check that everything still works. If everything works, we get no output, otherwise we will see an `AssertionError`. We can add or update tests as desired. There is still some room for improvement, though:\n","\n","- It is a bit counterintuitive to remember that *no output* means that all tests *pass*. It would be nice to get some kind of explicit confirmation instead.\n","- The `cheerlead_test.py` module as a whole is essentially a list of test functions, but we have to list those tests *again* in the `tests` variable inside the `main` function. We have to manually update that variable every time we add or remove a test, so we are repeating ourselves. Ideally, we should have a program that automatically detects any test functions that are present and then runs them all.\n","- The `main` function will stop as soon as any assertion fails. That means that if `test_yell` fails, we get no information on whether `announce` and `cheer` are working as intended. It would be more convenient if all tests always run, even if some of them fail.\n","\n","The [third-party `pytest` package](https://docs.pytest.org/) solves all of these problems. If we `pip install pytest` and remember to update our `requirements.txt`, we can still write our test module the same way, but we don't need the `main` function and the `tests` variable anymore:\n","\n","```python\n","from cheerlead import announce, yell, cheer\n","\n","def test_yell():\n"," assert yell('Kermit') == 'Go go Kermit!!!'\n","\n","def test_announce():\n"," assert announce('x') == 'We have a: x'\n","\n","def test_cheer():\n"," name = 'Rose'\n"," output = cheer(name)\n"," lines = output.splitlines()\n"," assert len(lines) == len(name) + 1\n"," for index, letter in enumerate(name):\n"," assert lines[index] == announce(letter)\n"," assert lines[-1] == yell(name)\n","```\n","\n","Now, when we run just the command `pytest`, it will do all of the following:\n","\n","- It recognizes all modules with a name ending in `_test.py` as test modules.\n","- In every test module, it recognizes all functions with a name starting with `test_` as unittests.\n","- It runs *all* tests, even if some tests fail along the way.\n","- It shows which tests are being run, indicating for each whether it passed or not.\n","- When an assertion fails, instead of just showing us the raw `AssertionError`, it gives us a detailed breakdown of the failing condition.\n","\n","On top of all that, `pytest` gives us many other tools to make testing even more flexible and efficient. For example, we can also check that functions will fail in a particular way if you pass them particular arguments. Testing with `pytest` is such a helpful, powerful tool during development that we recommend using it in every Python project. You can read all about it [here](https://docs.pytest.org/)."]},{"cell_type":"markdown","metadata":{"id":"esIxQGvUQZhH"},"source":["## Version control (Git)\n","\n","A version control system (VCS) keeps track of the changes that you make to your code. This enables you to find back changes that you made in the past and find out why you made them. You can also use this to revert an old change, while keeping changes that came after it. VCSs do this by efficiently storing all versions of your code in a system called a *repository*.\n","\n","All modern VCSs also allow you to create *branches*, which you can think of as parallel series of versions, or \"alternative histories\" of your code. You might work on a new feature on one branch, recording several changes as you go, then switch to another branch to fix a bug that you noticed while working on the feature, but which isn't related to the feature itself. Fixing the bug on a separate branch lets you focus on the bug, without having to worry about unfinished code related to the new feature. When you finish the bugfix, you switch back to the feature branch, and when you finish that as well, you can *merge* the branches, creating a single version of your program that includes *both* the bugfix *and* the new feature.\n","\n","Branches are also a great tool for collaborating with other programmers. When working on a large project, you might develop one feature while another programmer is developing another feature at the same time on another branch. You don't have to see each other's changes until you merge your branches together. This is such an efficient workflow that all software development teams are using it. However, once you get used to a VCS, you'll want to use it even for a small project that you work on alone.\n","\n","Git is a distributed VCS (DVCS) that has become very popular. \"Distributed\" basically means that it can handle branches very well: developers store their branches locally and they can optionally synchronize them with collaborators. Popular platforms like GitHub, BitBucket and GitLab facilitate such collaboration (although it can also be done without such a platform). Git is by no means the only good DVCS (for example, Mercurial is also good), but if you have not chosen a DVCS yet, Git is a fine choice.\n","\n","The book [Pro Git](https://git-scm.com/book) is a detailed introduction to Git. You can either read it on screen, free of charge, or buy it in print. If you want to get started quickly with a short tutorial and save the book for later, [Git Immersion](https://gitimmersion.com) is a good choice.\n","\n","Some advice:\n","\n","- Save many commits (versions) with small changes between them. Don't overhaul entire modules and then record only a single new commit, because this largely defeats the purpose of having a VCS.\n","- One logical change per commit. If you fix a typo, then that fix is a commit all by itself, even if you changed only a single character. If you rename a function which you happen to call in twenty different modules, then the name changes in the module where it is defined as well as in all the modules where it is called all belong together in a single commit. Other, unrelated changes that you might have made in those same modules should *not* be part of the same commit.\n","- If you worked a little bit \"out of order\", Git has tricks that let you include only some of the changes that you made in the next commit, while keeping the remainder for subsequent commits. Look into \"interactive staging\" on how to do this.\n","- Similarly, if you make a change that with hindsight should have been included in an earlier commit, you can fix this afterwards. Look into \"interactive rebase\" on how to do this. Note that you should only rebase commits that you have not shared with other people yet.\n","- If, with hindsight, you combined changes in a commit that should have been in separate commits, you can also split that commit afterwards during an interactive rebase. However, keep in mind that reordering and merging small commits is much easier than breaking apart large commits. This is another reason why you should err on the side of tiny commits."]}]} \ No newline at end of file diff --git a/README.md b/README.md index 2a57175..4452f1e 100644 --- a/README.md +++ b/README.md @@ -4,4 +4,4 @@ The entry level course 'Programming in Python', by the [Utrecht Centre for Digit The course was first taught 15-16 November, 2021. -This repository contains all teaching materials, exercises, solutions and extra resources relevant to the course. Where possible, all files are provided as Python Notebooks. \ No newline at end of file +This repository contains all teaching materials, exercises, solutions and extra resources relevant to the course. All files are provided as IPython Notebooks. \ No newline at end of file diff --git a/exercises/2_exercise.ipynb b/exercises/2_exercise.ipynb deleted file mode 100755 index 6ecdb2d..0000000 --- a/exercises/2_exercise.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Exercise 2.ipynb","provenance":[],"collapsed_sections":[],"authorship_tag":"ABX9TyP0DJevbsf+LA115QvuuYbc"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"QXRFmxivqk3J"},"source":["# Exercise 2\n","\n","1. \n"," 1. Loop over `exercise_list`, and find the word `\"stressed\"`. Assign it to a new variable.\n"," 2. Reverse the word you found in 1.1, and print the reversed word."]},{"cell_type":"code","metadata":{"id":"loap3-NPqqGD"},"source":["exercise_list = [1, 12.9, \"stressed\", \"bar\", True]"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"3leg-2-oqsmU"},"source":["2. Make a list of numbers. Print the average. See what happens when you try to add strings to the list."]},{"cell_type":"code","metadata":{"id":"qfYQgZ6UtGYX"},"source":[""],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"yL3K8Yygte30"},"source":["3. For each of the following lists, check if the first and last values are the same. Print `\"yay\"` if so, `\"nay\"` if not. Try to first turn them into a lists of lists. Are there any results you did not expect?"]},{"cell_type":"code","metadata":{"id":"EZvk0hKluPNy"},"source":["list1 = [1, 2, 3, 5, 1]\n","list2 = [1, 2, 3, 5, \"1\"]\n","list3 = [1, 2, 3, 5, True]\n","list4 = [False, \"True\", \"False\", \"False\"]\n","list5 = [\"true\", False, \"True\"]"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"FMySjPAXx4v1"},"source":["4. *FizzBuzz* (advanced)\n","\n"," 1. Print all numbers from 1 to 100. The numbers are provided by the code below.\n"," 2. If a number is divisible by 3, print `\"Fizz\"` instead.\n"," 3. If a nummber is divisible by 5, print `\"Buzz\"` instead.\n"," 4. If a number is divisible by 3 AND divisible by 5, print only`\"FizzBuzz\"`, not \"Fizz\" or \"Buzz\".\n","\n","Hint: use the modulo operator: `number1 % number2`. Try to see if you can figure out what it does.\n","\n"]},{"cell_type":"code","metadata":{"id":"Z3CaG-uhyngV"},"source":["numbers = list(range(0, 101))\n","print(2 % 3)\n","print(3 % 3)\n"],"execution_count":null,"outputs":[]}]} \ No newline at end of file diff --git a/exercises/2_solutions.ipynb b/exercises/2_solutions.ipynb deleted file mode 100755 index 06f53ab..0000000 --- a/exercises/2_solutions.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Exercise 2 - solutions.ipynb","provenance":[],"collapsed_sections":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"v1wakPAeqvhA"},"source":["# Exercise 2 - Solutions"]},{"cell_type":"markdown","metadata":{"id":"iPcFeOQjuxE4"},"source":["## 1"]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"0ZaiO9o6q7VO","executionInfo":{"status":"ok","timestamp":1636915394327,"user_tz":-60,"elapsed":5,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"261578b6-8d55-42f7-943a-38a0c27f8cb7"},"source":["exercise_list = [1, 12.9, \"stressed\", \"bar\", True]\n","\n","for element in exercise_list:\n"," if element == \"stressed\":\n"," word = element\n","\n","reversed_word = \"\"\n","for letter in word:\n"," reversed_word = letter + reversed_word\n","print(word + \" in reverse is: \" + reversed_word)"],"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["stressed in reverse is: desserts\n"]}]},{"cell_type":"markdown","metadata":{"id":"KYfCrRt1rbbd"},"source":["## 2"]},{"cell_type":"code","metadata":{"id":"4_FAlJ5irdkI"},"source":["numbers = [1, 5, -12, 38987, 0, 24]\n","\n","total = 0\n","length = 0\n","for num in numbers:\n"," total = total + num\n"," length = length + 1\n","average = total/length\n","print(average)\n","\n","# Adding strings makes the program fail, you cannot add a string to a number!\n","\n","# Bonus: using builtin functions\n","total = sum(numbers)\n","length = len(numbers)\n","print(total/length)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"Eu7Idfj7uyv1"},"source":["## 3"]},{"cell_type":"code","metadata":{"id":"XOKAZfR0uzoy"},"source":["list1 = [1, 2, 3, 5, 1]\n","list2 = [1, 2, 3, 5, \"1\"],\n","list3 = [1, 2, 3, 5, True]\n","list4 = [False, \"True\", \"False\", \"False\"]\n","list5 = [\"banana\", \"bananas\", \"Banana\"]\n","\n","master_list = [list1, list2, list3, list4, list5]\n","for sub_list in master_list:\n"," if sub_list[0] == sub_list[-1]:\n"," print(\"yay\")\n"," else:\n"," print(\"nay\")\n","\n","# You might not expect list 3 to be a \"yay\"\n","# However, in Python False and True are equal to 0 and 1\n","print(False == 0)\n","print(True == 1)\n","\n","# list5 is a nay, because strings are case sensitive\n","# if you want to compare them case-insensitive, first make then all lowercase\n","print(\"banana\".lower() == \"Banana\".lower())"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"nY1j9g2dyoqc"},"source":["## 4"]},{"cell_type":"code","metadata":{"id":"qC2qt-sPypwM"},"source":["# Many optimizations are possible!\n","numbers = list(range(0, 101))\n","\n","for num in numbers:\n"," if num % 3 == 0 and num % 5 == 0:\n"," print(\"FizzBuzz\")\n"," elif num % 3 == 0:\n"," print(\"Fizz\")\n"," elif num % 5 == 0:\n"," print(\"Buzz\")\n"," else:\n"," print(num)"],"execution_count":null,"outputs":[]}]} \ No newline at end of file diff --git a/exercises/3_exercise.ipynb b/exercises/3_exercise.ipynb deleted file mode 100644 index 1bd53f7..0000000 --- a/exercises/3_exercise.ipynb +++ /dev/null @@ -1,76 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Exercise3.ipynb", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "Fj68DvsUltDP" - }, - "source": [ - "# Exercise 3\n", - "\n", - "This is the third hands-on exercise of the 2021 CDH entry level Python course at Utrecht University.\n", - "\n", - "For this exercise, you may choose whether you use your own code from exercise 2, or the code below. The exercise consists of two parts:\n", - "\n", - "1. Refactor the code into functions, so that the logic is reusable and non-repetitive and the purpose of each line of code is clear.\n", - "2. Identify any hard-coded parameters and replace them by constants that you define at the top.\n", - "\n", - "If you finish the exercise quickly, you can try whether you can generalize your functions to make them more powerful. For bonus points!\n", - "\n", - "Good luck!" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "--nCEHqYlmKw", - "outputId": "e1294fd0-7353-4205-e887-f21e6a82719b" - }, - "source": [ - "name = 'Python' # could be your own name\n", - "print('We have a: ' + name[0])\n", - "print('We have a: ' + name[1])\n", - "print('We have a: ' + name[2])\n", - "print('We have a: ' + name[3])\n", - "print('We have a: ' + name[4])\n", - "print('We have a: ' + name[5])\n", - "print('Go go ' + name.upper() + '!!!')" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "We have a: P\n", - "We have a: y\n", - "We have a: t\n", - "We have a: h\n", - "We have a: o\n", - "We have a: n\n", - "Go go PYTHON!!!\n" - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/exercises/3_solutions.ipynb b/exercises/3_solutions.ipynb deleted file mode 100644 index 030e004..0000000 --- a/exercises/3_solutions.ipynb +++ /dev/null @@ -1,120 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Exercise3-answer.ipynb", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "Fj68DvsUltDP" - }, - "source": [ - "# Exercise 3\n", - "\n", - "This is the third hands-on exercise of the 2021 CDH entry level Python course at Utrecht University.\n", - "\n", - "For this exercise, you may choose whether you use your own code from exercise 2, or the code below. The exercise consists of two parts:\n", - "\n", - "1. Refactor the code into functions, so that the logic is reusable and non-repetitive and the purpose of each line of code is clear.\n", - "2. Identify any hard-coded parameters and replace them by constants that you define at the top.\n", - "\n", - "Good luck!" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "--nCEHqYlmKw", - "outputId": "e1294fd0-7353-4205-e887-f21e6a82719b" - }, - "source": [ - "name = 'Python' # could be your own name\n", - "print('We have a: ' + name[0])\n", - "print('We have a: ' + name[1])\n", - "print('We have a: ' + name[2])\n", - "print('We have a: ' + name[3])\n", - "print('We have a: ' + name[4])\n", - "print('We have a: ' + name[5])\n", - "print('Go go ' + name.upper() + '!!!')" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "We have a: P\n", - "We have a: y\n", - "We have a: t\n", - "We have a: h\n", - "We have a: o\n", - "We have a: n\n", - "Go go PYTHON!!!\n" - ] - } - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "sc8aY_ZrT-Gh", - "outputId": "4b53cf51-4124-495a-e498-2bdb97079f4e" - }, - "source": [ - "ANNOUNCE_START = 'We have a: '\n", - "YELL_START = 'Go go '\n", - "YELL_END = '!!!'\n", - "\n", - "def announce(letter):\n", - " return ANNOUNCE_START + letter\n", - "\n", - "def yell(name):\n", - " return YELL_START + name + YELL_END\n", - "\n", - "def cheerlead(name):\n", - " lines = []\n", - " for letter in name:\n", - " lines.append(announce(letter))\n", - " lines.append(yell(name))\n", - " return '\\n'.join(lines)\n", - "\n", - "print(cheerlead('Python'))" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "We have a: P\n", - "We have a: y\n", - "We have a: t\n", - "We have a: h\n", - "We have a: o\n", - "We have a: n\n", - "Go go Python!!!\n" - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/exercises/4_exercise.ipynb b/exercises/4_exercise.ipynb deleted file mode 100644 index 71c0c9d..0000000 --- a/exercises/4_exercise.ipynb +++ /dev/null @@ -1,69 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Exercise4.ipynb", - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "bVfoqS2eXjOV" - }, - "source": [ - "# Exercise 4\n", - "\n", - "This is the fourth hands-on exercise of the 2021 CDH entry level Python course at Utrecht University.\n", - "\n", - "The following program takes in a binary string of ones and zeros. It returns `True` if all bits are ones and `False` otherwise. However, there is a bug in the program. In the example below, the program returns `True` while there is clearly a zero in the string.\n", - "\n", - "1. Insert a breakpoint and step through the program to find out what is going wrong. Step multiple times through the program if necessary and do not stop until you fully understand what is going on.\n", - "2. Try to think of at least two ways in which you might solve the problem. Which is the safest way to be *very* sure that the problem will *never* happen again?\n", - "\n", - "If you have written a program with a bug during exercise 2 or 3, you may choose to use that program for this exercise instead." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "3N0mSvSyXWe4", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "f0c90396-c2e0-45ed-d502-73b8e59f16e4" - }, - "source": [ - "def only_ones(binary_string):\n", - " for bit in binary_string:\n", - " if bit is '0':\n", - " return False\n", - " return True\n", - "\n", - "only_ones('1O1')" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "True" - ] - }, - "metadata": {}, - "execution_count": 1 - } - ] - } - ] -} \ No newline at end of file diff --git a/exercises/4_solutions.ipynb b/exercises/4_solutions.ipynb deleted file mode 100644 index 9d4cf2e..0000000 --- a/exercises/4_solutions.ipynb +++ /dev/null @@ -1,85 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Exercise4-answer.ipynb", - "provenance": [], - "collapsed_sections": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "bVfoqS2eXjOV" - }, - "source": [ - "# Exercise 4\n", - "\n", - "This is the fourth hands-on exercise of the 2021 CDH entry level Python course at Utrecht University.\n", - "\n", - "The following program takes in a binary string of ones and zeros. It returns `True` if all bits are ones and `False` otherwise. However, there is a bug in the program. In the example below, the program returns `True` while there is clearly a zero in the string.\n", - "\n", - "1. Insert a breakpoint and step through the program to find out what is going wrong. Step multiple times through the program if necessary and do not stop until you fully understand what is going on.\n", - "2. Try to think of at least two ways in which you might solve the problem. Which is the safest way to be *very* sure that the problem will *never* happen again?\n", - "\n", - "If you have written a program with a bug during exercise 2 or 3, you may choose to use that program for this exercise instead." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "3N0mSvSyXWe4" - }, - "source": [ - "def only_ones(binary_string):\n", - " import pdb; pdb.set_trace()\n", - " for bit in binary_string:\n", - " if bit is '0':\n", - " return False\n", - " return True\n", - "\n", - "only_ones('1O1')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "M0OZwOYEb2S1" - }, - "source": [ - "## Answer\n", - "\n", - "The problem is that the string contains the capital letter `'O'` instead of the digit `'0'`. Stepping with the debugger, you would eventually be at the line\n", - "\n", - "```python\n", - " if bit is '0':\n", - "```\n", - "\n", - "and running the command `p bit`, you would find that it prints `'O'`. At this point, you *might* notice that `bit` looks slightly different from the character in the condition.\n", - "\n", - "Otherwise, after going over this line a couple of times and starting to doubt yourself, you might try `p bit is '0'` and you would find that it prints `False`. At this point, you would certainly conclude that the string does not contain a zero, but something that looks similar to a zero.\n", - "\n", - "A solution that might quickly come to mind, is to fix the string. After all, a binary string of ones and zeros is not supposed to contain a capital letter `'O'`. This is indeed a mistake that needs to be fixed.\n", - "\n", - "However, this is not a complete solution. Next time somebody calls `only_ones`, they might again mistakenly include a character other than `'1'` or `'0'`, and the function would give the wrong answer again. This can be prevented by changing the condition:\n", - "\n", - "```python\n", - " if bit is not '1':\n", - "```\n", - "\n", - "Now, if the string contains *anything* other than a `'1'`, whether it's a `'0'` or something else, it will always returns `False`, as it should." - ] - } - ] -} \ No newline at end of file diff --git a/exercises/5_exercise.ipynb b/exercises/5_exercise.ipynb deleted file mode 100755 index 1b30355..0000000 --- a/exercises/5_exercise.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Exercise 5.ipynb","provenance":[],"collapsed_sections":[],"authorship_tag":"ABX9TyN61O3wVJQW63lhTuCcO6hc"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"vJPGrtLJMaJd"},"source":["# Exercise 5 \n","\n","1. Upload your own dataset, or use `sample_data/california_housing_test.csv`\n","2. Use the example code to read the data from the CSV file\n","3. Print the following items:\n"," 1. The last row\n"," 2. The last column\n"," 3. The first row. If this is a header row, try if you can come up with a way to separate it from the data rows.\n","\n","Use best practises (write functions, document the code, etc)"]},{"cell_type":"code","metadata":{"id":"mIvIGXjLNFTp"},"source":[""],"execution_count":null,"outputs":[]}]} \ No newline at end of file diff --git a/exercises/5_solutions.ipynb b/exercises/5_solutions.ipynb deleted file mode 100755 index ad5a6e1..0000000 --- a/exercises/5_solutions.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"cells":[{"cell_type":"markdown","metadata":{"id":"EeUBZA5JNW9j"},"source":["# Exercise 5 - Solutions"]},{"cell_type":"code","execution_count":18,"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"elapsed":898,"status":"ok","timestamp":1637060409073,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"},"user_tz":-60},"id":"gVgEcMXaNHOz","outputId":"21cc2676-fb2e-4519-c1b3-758c6bb945d5"},"outputs":[{"name":"stdout","output_type":"stream","text":["[['Abkhazia', 'Sukhumi'], ['Afghanistan', 'Kabul'], ['Akrotiri and Dhekelia', 'Episkopi Cantonment'], ['Albania', 'Tirana'], ['Algeria', 'Algiers'], ['American Samoa', 'Pago Pago'], ['Andorra', 'Andorra la Vella'], ['Angola', 'Luanda'], ['Anguilla', 'The Valley'], ['Antigua and Barbuda', \"St. John's\"], ['Argentina', 'Buenos Aires'], ['Armenia', 'Yerevan'], ['Aruba', 'Oranjestad'], ['Ascension Island', 'Georgetown'], ['Australia', 'Canberra'], ['Austria', 'Vienna'], ['Azerbaijan', 'Baku'], ['Bahamas', 'Nassau'], ['Bahrain', 'Manama'], ['Bangladesh', 'Dhaka'], ['Barbados', 'Bridgetown'], ['Belarus', 'Minsk'], ['Belgium', 'Brussels'], ['Belize', 'Belmopan'], ['Benin', 'Porto-Novo'], ['Bermuda', 'Hamilton'], ['Bhutan', 'Thimphu'], ['Bolivia', 'Sucre'], ['Bolivia', 'La Paz'], ['Bosnia and Herzegovina', 'Sarajevo'], ['Botswana', 'Gaborone'], ['Brazil', 'Brasília'], ['British Virgin Islands', 'Road Town'], ['Brunei', 'Bandar Seri Begawan'], ['Bulgaria', 'Sofia'], ['Burkina Faso', 'Ouagadougou'], ['Burundi', 'Bujumbura'], ['Cambodia', 'Phnom Penh'], ['Cameroon', 'Yaoundé'], ['Canada', 'Ottawa'], ['Cape Verde', 'Praia'], ['Cayman Islands', 'George Town'], ['Central African Republic', 'Bangui'], ['Chad', \"N'Djamena\"], ['Chile', 'Santiago'], ['China', 'Beijing'], ['Christmas Island', 'Flying Fish Cove'], ['Cocos (Keeling) Islands', 'West Island'], ['Colombia', 'Bogotá'], ['Comoros', 'Moroni'], ['Cook Islands', 'Avarua'], ['Costa Rica', 'San José'], ['Croatia', 'Zagreb'], ['Cuba', 'Havana'], ['Curaçao', 'Willemstad'], ['Cyprus', 'Nicosia'], ['Czech Republic', 'Prague'], [\"Côte d'Ivoire\", 'Yamoussoukro'], ['Democratic Republic of the Congo', 'Kinshasa'], ['Denmark', 'Copenhagen'], ['Djibouti', 'Djibouti'], ['Dominica', 'Roseau'], ['Dominican Republic', 'Santo Domingo'], ['East Timor (Timor-Leste)', 'Dili'], ['Easter Island', 'Hanga Roa'], ['Ecuador', 'Quito'], ['Egypt', 'Cairo'], ['El Salvador', 'San Salvador'], ['Equatorial Guinea', 'Malabo'], ['Eritrea', 'Asmara'], ['Estonia', 'Tallinn'], ['Ethiopia', 'Addis Ababa'], ['Falkland Islands', 'Stanley'], ['Faroe Islands', 'Tórshavn'], ['Federated States of Micronesia', 'Palikir'], ['Fiji', 'Suva'], ['Finland', 'Helsinki'], ['France', 'Paris'], ['French Guiana', 'Cayenne'], ['French Polynesia', 'Papeete'], ['Gabon', 'Libreville'], ['Gambia', 'Banjul'], ['Georgia', 'Tbilisi'], ['Germany', 'Berlin'], ['Ghana', 'Accra'], ['Gibraltar', 'Gibraltar'], ['Greece', 'Athens'], ['Greenland', 'Nuuk'], ['Grenada', \"St. George's\"], ['Guam', 'Hagåtña'], ['Guatemala', 'Guatemala City'], ['Guernsey', 'St. Peter Port'], ['Guinea', 'Conakry'], ['Guinea-Bissau', 'Bissau'], ['Guyana', 'Georgetown'], ['Haiti', 'Port-au-Prince'], ['Honduras', 'Tegucigalpa'], ['Hungary', 'Budapest'], ['Iceland', 'Reykjavík'], ['India', 'New Delhi'], ['Indonesia', 'Jakarta'], ['Iran', 'Tehran'], ['Iraq', 'Baghdad'], ['Ireland', 'Dublin'], ['Isle of Man', 'Douglas'], ['Israel', 'Jerusalem'], ['Italy', 'Rome'], ['Jamaica', 'Kingston'], ['Japan', 'Tokyo'], ['Jersey', 'St. Helier'], ['Jordan', 'Amman'], ['Kazakhstan', 'Astana'], ['Kenya', 'Nairobi'], ['Kiribati', 'Tarawa'], ['Kosovo', 'Pristina'], ['Kuwait', 'Kuwait City'], ['Kyrgyzstan', 'Bishkek'], ['Laos', 'Vientiane'], ['Latvia', 'Riga'], ['Lebanon', 'Beirut'], ['Lesotho', 'Maseru'], ['Liberia', 'Monrovia'], ['Libya', 'Tripoli'], ['Liechtenstein', 'Vaduz'], ['Lithuania', 'Vilnius'], ['Luxembourg', 'Luxembourg'], ['Macedonia', 'Skopje'], ['Madagascar', 'Antananarivo'], ['Malawi', 'Lilongwe'], ['Malaysia', 'Kuala Lumpur'], ['Maldives', 'Malé'], ['Mali', 'Bamako'], ['Malta', 'Valletta'], ['Marshall Islands', 'Majuro'], ['Mauritania', 'Nouakchott'], ['Mauritius', 'Port Louis'], ['Mexico', 'Mexico City'], ['Moldova', 'Chisinau'], ['Monaco', 'Monaco'], ['Mongolia', 'Ulaanbaatar'], ['Montenegro', 'Podgorica'], ['Montserrat', 'Plymouth'], ['Morocco', 'Rabat'], ['Mozambique', 'Maputo'], ['Myanmar', 'Naypyidaw'], ['Nagorno-Karabakh Republic', 'Stepanakert'], ['Namibia', 'Windhoek'], ['Nauru', 'Yaren'], ['Nepal', 'Kathmandu'], ['Netherlands', 'Amsterdam'], ['New Caledonia', 'Nouméa'], ['New Zealand', 'Wellington'], ['Nicaragua', 'Managua'], ['Niger', 'Niamey'], ['Nigeria', 'Abuja'], ['Niue', 'Alofi'], ['Norfolk Island', 'Kingston'], ['North Korea', 'Pyongyang'], ['Northern Cyprus', 'Nicosia'], ['United Kingdom Northern Ireland', 'Belfast'], ['Northern Mariana Islands', 'Saipan'], ['Norway', 'Oslo'], ['Oman', 'Muscat'], ['Pakistan', 'Islamabad'], ['Palau', 'Ngerulmud'], ['Palestine', 'Jerusalem'], ['Panama', 'Panama City'], ['Papua New Guinea', 'Port Moresby'], ['Paraguay', 'Asunción'], ['Peru', 'Lima'], ['Philippines', 'Manila'], ['Pitcairn Islands', 'Adamstown'], ['Poland', 'Warsaw'], ['Portugal', 'Lisbon'], ['Puerto Rico', 'San Juan'], ['Qatar', 'Doha'], ['Republic of China (Taiwan)', 'Taipei'], ['Republic of the Congo', 'Brazzaville'], ['Romania', 'Bucharest'], ['Russia', 'Moscow'], ['Rwanda', 'Kigali'], ['Saint Barthélemy', 'Gustavia'], ['Saint Helena', 'Jamestown'], ['Saint Kitts and Nevis', 'Basseterre'], ['Saint Lucia', 'Castries'], ['Saint Martin', 'Marigot'], ['Saint Pierre and Miquelon', 'St. Pierre'], ['Saint Vincent and the Grenadines', 'Kingstown'], ['Samoa', 'Apia'], ['San Marino', 'San Marino'], ['Saudi Arabia', 'Riyadh'], ['Scotland', 'Edinburgh'], ['Senegal', 'Dakar'], ['Serbia', 'Belgrade'], ['Seychelles', 'Victoria'], ['Sierra Leone', 'Freetown'], ['Singapore', 'Singapore'], ['Sint Maarten', 'Philipsburg'], ['Slovakia', 'Bratislava'], ['Slovenia', 'Ljubljana'], ['Solomon Islands', 'Honiara'], ['Somalia', 'Mogadishu'], ['Somaliland', 'Hargeisa'], ['South Africa', 'Pretoria'], ['South Georgia and the South Sandwich Islands', 'Grytviken'], ['South Korea', 'Seoul'], ['South Ossetia', 'Tskhinvali'], ['South Sudan', 'Juba'], ['Spain', 'Madrid'], ['Sri Lanka', 'Sri Jayawardenapura Kotte'], ['Sudan', 'Khartoum'], ['Suriname', 'Paramaribo'], ['Swaziland', 'Mbabane'], ['Sweden', 'Stockholm'], ['Switzerland', 'Bern'], ['Syria', 'Damascus'], ['São Tomé and Príncipe', 'São Tomé'], ['Tajikistan', 'Dushanbe'], ['Tanzania', 'Dodoma'], ['Thailand', 'Bangkok'], ['Togo', 'Lomé'], ['Tonga', 'Nukuʻalofa'], ['Transnistria', 'Tiraspol'], ['Trinidad and Tobago', 'Port of Spain'], ['Tristan da Cunha', 'Edinburgh of the Seven Seas'], ['Tunisia', 'Tunis'], ['Turkey', 'Ankara'], ['Turkmenistan', 'Ashgabat'], ['Turks and Caicos Islands', 'Cockburn Town'], ['Tuvalu', 'Funafuti'], ['Uganda', 'Kampala'], ['Ukraine', 'Kiev'], ['United Arab Emirates', 'Abu Dhabi'], ['United Kingdom; England', 'London'], ['United States', 'Washington, D.C.'], ['United States Virgin Islands', 'Charlotte Amalie'], ['Uruguay', 'Montevideo'], ['Uzbekistan', 'Tashkent'], ['Vanuatu', 'Port Vila'], ['Vatican City', 'Vatican City'], ['Venezuela', 'Caracas'], ['Vietnam', 'Hanoi'], ['Wales', 'Cardiff'], ['Wallis and Futuna', 'Mata-Utu'], ['Western Sahara', 'El Aaiún'], ['Yemen', 'Sanaá'], ['Zambia', 'Lusaka'], ['Zimbabwe', 'Harare']]\n"]}],"source":["# please note, the solutions can vary depending on your own dataset\n","\n","import csv\n","\n","FILENAME = 'capitals.csv'\n","\n","def read_data(filename):\n"," ''' Read data from a CSV file,\n"," Return a list (rows) of lists (columns)\n"," '''\n"," with open(filename) as csv_file:\n"," reader = csv.reader(csv_file, delimiter=',')\n"," return list(reader)\n","\n","\n","def get_column(data, column_index):\n"," ''' \n"," Return column at index as a list\n"," '''\n"," entire_column = []\n"," for row in data:\n"," column = row[column_index]\n"," entire_column.append(column)\n"," return entire_column\n","\n","def separate_headers(data):\n"," '''\n"," Separates headers from the data\n"," Returns both as separate lists\n"," '''\n"," headers = data[0]\n"," dataset = data[1:]\n"," return [headers, dataset]\n","\n","def inspect_data(filename):\n"," data = read_data(filename)\n"," \n"," last_row = data[-1]\n"," last_column = get_column(data, -1)\n"," first_row = data[0]\n","\n"," print(last_row)\n"," print(last_column)\n"," print(first_row)\n","\n"," # let's assume your csv file has headers\n"," headers, dataset = separate_headers(data)\n","\n"," # the first row with actual data\n"," print(actual_data[0])\n","\n","inspect_data(FILENAME)"]}],"metadata":{"colab":{"collapsed_sections":[],"name":"Exercise 5 - Solutions.ipynb","provenance":[]},"kernelspec":{"display_name":"Python 3","name":"python3"},"language_info":{"name":"python"}},"nbformat":4,"nbformat_minor":0} diff --git a/lessons/00 index.ipynb b/lessons/00 index.ipynb new file mode 100644 index 0000000..212e18b --- /dev/null +++ b/lessons/00 index.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# CDH course \"Programming in Python\"\n","\n","**April 2023 edition**\n","\n","[Teams channel](https://teams.microsoft.com/l/channel/19%3aAlr7pcE2v9p1eaKT1BtNxJAB9mgCFT1olZvAMswJlEc1%40thread.tacv2/Algemeen?groupId=7fd15384-6748-4852-8646-d96963fb3524&tenantId=d72758a0-a446-4e0f-a0aa-4bf95a4a10e7)\n","\n","## Course modules\n","\n","1. [Introduction](https://colab.research.google.com/drive/1i4wJpUIr77Fh1renWNjt00Bd51NbC1nB)\n","2. [Values and expressions](https://colab.research.google.com/drive/17K6C_EZoeGtRxoTbYQvygFEdpWgQ2QFp)\n","3. [Conditionals](https://colab.research.google.com/drive/1KkZ2fS75o7giccQJakRhyvYBV7JdFnVw)\n","4. [Datastructures](https://colab.research.google.com/drive/1JxzmIzwcipnwFBntv0WZOlT-d2fUjoRF)\n","5. [Assertions](https://colab.research.google.com/drive/1Nv6vgkH2zjJes7LXUCVhsDwFOGCtTbHM)\n","6. [Loops](https://colab.research.google.com/drive/1AZY4ESmsKKMvbalBDLlMrezAM5NzXXxV)\n","7. [Functions](https://colab.research.google.com/drive/1APhegD_KpLRFn5bC6Ater2wFpT8_Opfr) \n","8. [Debugging](https://colab.research.google.com/drive/1yQskT6SyKvXtXewx5kCla2NOmasgP8Vi)\n","9. [String manipulation](https://colab.research.google.com/drive/1Z7NNMxqHTSMoUadH3pVL6Bg6oii4qUoQ)\n","10. [Dictionaries](https://colab.research.google.com/drive/16mecEPkVGUBIFoHIALO7dE8qv7PynHL9)\n","11. [Working with files](https://colab.research.google.com/drive/17G-gA5-GNKX-mQglrPVNtndV2YhBafBr)\n","\n","## Extra material\n","\n","- [Functions exercises](https://colab.research.google.com/drive/13__hh18xcBeZ5xjeby21KXUBYjRpb_Vy)\n","- [Tips](https://colab.research.google.com/drive/1qKVaI3Ct1hOsM_06mZdXpx0sLSR_O-6R)\n","\n","## Projects\n","- [Text analysis](https://colab.research.google.com/drive/1wUgaVE70dzjIlIEuZtgQalqYI2UcfiXK)\n","\n","## Exercise solutions\n","\n","1. [Introduction](https://colab.research.google.com/drive/1RIwG7hA-Ymjcm1dmSW6wA_hu1clDNrAd)\n","2. [Values and expressions](https://colab.research.google.com/drive/1JKeNehBZ9hhHXPdVunQ_r9cv-lLR9Byy)\n","3. [Conditionals](https://colab.research.google.com/drive/1Nvvjc3fGnMg2tWvfw2W1gVn2oKKbWzGI)\n","4. [Datastructures](https://colab.research.google.com/drive/1juOQFMlRmeVUfbKWy0wtZ9lWkSZmr2Gn)\n","5. [Assertions](https://colab.research.google.com/drive/1tqjXsHnnJeEAivrxqRoOSW9eNESCwLIK)\n","6. [Loops](https://colab.research.google.com/drive/1vy2gKHtBUMk60u2bmCYlcqmhIFpI2PI-)\n","7. [Functions](https://colab.research.google.com/drive/13M4t34msJvudQTN-Im24w4iRfctOuNCv)\n","8. Debugging - no solutions\n","9. [String manipulation](https://colab.research.google.com/drive/1Z7NNMxqHTSMoUadH3pVL6Bg6oii4qUoQ)\n","10. [Dictionaries](https://colab.research.google.com/drive/1Qw7vgiyRVg1E-BkUEvCxX0e6QZQ9y_k6)\n","11. [Working with files](https://colab.research.google.com/drive/1Nz3lhsntgw4yAI6257drrp-EtEQEVogF)"],"metadata":{"id":"RQ73d6XVysi7"}}]} \ No newline at end of file diff --git a/lessons/01 introduction.ipynb b/lessons/01 introduction.ipynb new file mode 100644 index 0000000..5b3110b --- /dev/null +++ b/lessons/01 introduction.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyOqiugh/2SmC5zeIHsVl+q8"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 1: Introduction\n","## CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","## Welcome!\n","\n","## Who are we?\n","\n","- Julian Gonggrijp, Jelte van Boheemen, Luka van der Plas, Mees van Stiphout\n","- Developers at the Digital Humanities Lab\n","\n","## Who are you?\n","\n","- Entry level course, no previous experience required\n","- If you have some experience, parts of the course may be familiar. Challenge yourself with some difficult exercises!\n","\n","## Goals\n","\n","- Introduce the basics of the Python programming language\n","- Write simple computer programs\n","- Simple data analysis on your own data\n","- Teach good practises that you can apply to all your future programming, and make you a self-reliant programmer\n","\n","## Colab Notebooks\n","\n","- Runs Python code in your web browser, no installing required\n","- If you do not have a Google account, please make one\n","- Presenting straight from Colab, so you can follow our example\n","- Copy the notebooks to edit them, instructions in exercise 1"],"metadata":{"id":"Buvh9v-iYeOO"}},{"cell_type":"markdown","source":["## Python\n","\n","- Programming language\n","- Invented by Guido van Rossum (former Benevolent Dictator For Life) in 1989\n","- *High level*\n"," - Far removed from machine language\n"," - Written in C (slightly lower level)\n","- Designed to be readable\n","- Many versions, currently on major version 3."],"metadata":{"id":"STQf1EROV-4I"}},{"cell_type":"markdown","source":["### Why learn Python?\n","\n","- (Relatively) easy to learn\n","- Widely used\n"," - Easy to install and run on a variety of platforms\n"," - Many resources available\n","- Many good packages and libraries available"],"metadata":{"id":"rC4AwjL06k0q"}},{"cell_type":"markdown","source":["## Notebooks 101\n","\n","Let's get started!"],"metadata":{"id":"xyNb4mPMcQCd"}},{"cell_type":"markdown","source":["### Copy a notebook to your own Google Drive\n","\n","You can only run code in this notebook, not edit it. To edit it, you need to copy it to [your own Google Drive](https://drive.google.com) first.\n","\n","To do so, click on the *File* menu and choose the ninth option from the top: *Save a copy in Drive*. You can now find the copy in your drive, in the directory *Colab Notebooks*.\n","\n","Tip: give it a recognizable name (e.g. `Module 1 - my solutions`).\n"],"metadata":{"id":"4lc8nYpP9mtf"}},{"cell_type":"markdown","source":["### Adjust some settings\n","\n","Open the *Settings*, in the *Tools* menu or by clicking the cogwheel icon in the top right. Open the *Editor* section.\n","\n","- Set *Indentation width in spaces* to **4**.\n","- Switch *Show line numbers* **on**.\n","\n","The other settings are up to you."],"metadata":{"id":"8zoSNQtC_6_v"}},{"cell_type":"markdown","source":["### Execute Python code\n","\n","Press the triangle icon in the top left corner of a code block to run it, *OR* type **ctrl-enter** when the text cursor is in the code block. Type **ctrl-shift-enter** to run only the current line.\n","\n","If you open a notebook for the first time, or if you have not run any code for a while, it takes a while before you see a result."],"metadata":{"id":"qtRYKOWnB5Wl"}},{"cell_type":"code","source":["print('Hello')\n","print('Goodbye')"],"metadata":{"id":"MdA4_KyrDAsf"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Python 101"],"metadata":{"id":"AoBoZqIeFEru"}},{"cell_type":"markdown","source":["### `print`\n","\n","In the previous code block, we saw the `print` function in action. It causes Python to \"talk\" to us."],"metadata":{"id":"ZOqgk7VAFKnJ"}},{"cell_type":"markdown","source":["### Values\n","\n","Between the parentheses `( )` of the `print` function, we put the *value* that we want Python to show. We can also write the value without passing it to `print`."],"metadata":{"id":"NOtudpGlFe78"}},{"cell_type":"code","source":["'Hello'"],"metadata":{"id":"in8WoUafGEyK"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["A bare value does not always cause output. We will explore this in the first exercise."],"metadata":{"id":"BHQPB7LuQ1mf"}},{"cell_type":"markdown","source":["### Comments\n","\n","A comment starts with a hash `#` and runs until the end of the line. Python ignores comments. You can use them as notes for yourself and for other programmers."],"metadata":{"id":"Src0ZdRKGHtl"}},{"cell_type":"code","source":["# Python will not look here!\n","\n","print('Hello') # comments can start after code"],"metadata":{"id":"ssP4GWUOIxWS"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Use comments to explain *why* your code was written the way it is. You will be grateful to yourself when you read your own code after a few weeks!"],"metadata":{"id":"YxXeF4u5I2c_"}},{"cell_type":"code","source":["# Useless comment:\n","\n","# Print \"Hello\".\n","print('Hello')\n","\n","# Useful comment:\n","\n","# Everyone writes \"Hello\" in this exercise, but\n","# I prefer something a little bit more British.\n","print('How do you do?')"],"metadata":{"id":"nMTlvlbbJUWu"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### `pass`\n","\n","You can write `pass` to do nothing. It behaves almost like a comment, but isn't. It is sometimes useful as a placeholder, as we will see later on in the course."],"metadata":{"id":"ZhgCPUNTLIZX"}},{"cell_type":"code","source":["pass"],"metadata":{"id":"oS7kfP3OLtJn"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 1.1: Try it out\n","\n","Read each of the code blocks below. Try to predict what it will do, then run the block to check your prediction.\n","\n","Do you see any (subtle or not-so subtle) surprises? Can you explain them?"],"metadata":{"id":"pKIEfocbMaIR"}},{"cell_type":"code","source":["print(1)\n","1"],"metadata":{"id":"6hlNxRNNM1fV"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('oops')\n","'oops'"],"metadata":{"id":"VIm6FdRIM6OE"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print()"],"metadata":{"id":"_MN48xz5NAya"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('apricot')\n","print('banana')\n","print('cherry')"],"metadata":{"id":"g9WKeIA2NVIA"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["'apricot'\n","'banana'\n","'cherry'"],"metadata":{"id":"NCbCfbHaNafJ"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# apricot\n","# banana\n","# cherry"],"metadata":{"id":"-ZuiJ92yNqpi"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('apricot')\n","'banana'\n","# cherry"],"metadata":{"id":"b9bTbrNSNwwn"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# apricot\n","'banana'\n","print('cherry')"],"metadata":{"id":"GYmcSm6iOAiA"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('apricot')\n","'banana'\n","pass"],"metadata":{"id":"rbjHe9KbOzFb"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print(pass)"],"metadata":{"id":"V1GiIP_ZNK8H"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print(#oops)"],"metadata":{"id":"sNNoSfndOSiw"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('apricot', 'banana')"],"metadata":{"id":"6IZS1NUuTdOX"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 1.2: Hello, world!\n","\n","The classic way to demonstrate a programming language's syntax is the hello world-program. This is the minimal amount of code required to output the text \"Hello, world!\" to the user. \n","\n","Write a hello world-program for Python."],"metadata":{"id":"Tr3wPlHMeBCI"}},{"cell_type":"code","source":["# Your solution here"],"metadata":{"id":"jN7WTVOOSq2C"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[2. Values and expressions](https://colab.research.google.com/drive/17K6C_EZoeGtRxoTbYQvygFEdpWgQ2QFp)"],"metadata":{"id":"zI0ohEpPUwpC"}}]} \ No newline at end of file diff --git a/lessons/02 values and expressions.ipynb b/lessons/02 values and expressions.ipynb new file mode 100644 index 0000000..267516f --- /dev/null +++ b/lessons/02 values and expressions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 2: Values and expressions\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [1. Introduction](https://colab.research.google.com/drive/1i4wJpUIr77Fh1renWNjt00Bd51NbC1nB)\n","\n","### This module\n","\n","- The basic types of values that exist in Python.\n","- How to store values for later use.\n","- How to create values from other values."],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## Primitive types and values\n","\n","> In computer science, primitive data types are a set of basic data types from which all other data types are constructed. [wikipedia](https://en.wikipedia.org/wiki/Primitive_data_type)\n","\n","In Python:\n","\n","- integer - `int`\n","- floating point - `float`\n","- string - `str`\n","- boolean - `bool`\n","- none - `None`\n"],"metadata":{"id":"AqGUR1POYVNL"}},{"cell_type":"markdown","source":["### integer\n","'whole number'"],"metadata":{"id":"8sSOrG7FdMT5"}},{"cell_type":"code","source":["1\n","2\n","-12\n","289883891009329819081202\n","0"],"metadata":{"id":"wTlfkN-Sa_MG"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### floating point\n","'decimal number'"],"metadata":{"id":"iBCZZWfDdS7o"}},{"cell_type":"code","source":["2.1\n","-3.2\n","12.8\n","0.0\n",".8"],"metadata":{"id":"2JbaI2-pbTF5"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### string\n","'text'"],"metadata":{"id":"om0zZYCBdd8F"}},{"cell_type":"code","source":["'hello'\n","'we can choose between single'\n","\"or double quotes!\"\n","\n","\"I don't want to do this\"\n","\n","# escaping difficult characters with \\ \n","\"I won't say \\\"banana\\\"\\\\\"\n","\n","# line breaks are preserved\n","'''a long string\n","\n","that can go over multiple lines'''\n","\n","''\n","\"\""],"metadata":{"id":"DB6KZC5Sblwy"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["*escape characters* only show when printing"],"metadata":{"id":"dQ6u3Syk4fS4"}},{"cell_type":"code","source":["# escape character: \\n (newline)\n","print('hello \\n world')\n","'hello \\n world'"],"metadata":{"id":"7QCMtj3S4d6E"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### boolean\n","true or false"],"metadata":{"id":"ouf6r2zmdjY9"}},{"cell_type":"code","source":["True\n","False\n","false\n","true\n","\"True\""],"metadata":{"id":"8n81rHXFb9cl"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### None\n","'nothing here'"],"metadata":{"id":"xS0efw6fdoW9"}},{"cell_type":"code","source":["None\n","none\n","\"none\""],"metadata":{"id":"fOZdR0YUcFRb"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Difference between types\n","\n","Use `type(value)` to find the type of a value."],"metadata":{"id":"jockLUXXd2Ad"}},{"cell_type":"code","source":["type(10)\n","type(3.14159)\n","type('hello')\n","type(True)\n","type('True')\n","type(None)"],"metadata":{"id":"lHtfczHxd89N"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Careful! A number in quotes is not actually a number, but a string. A string that looks like a number will **NOT** behave like a number."],"metadata":{"id":"kZffa20rXLOQ"}},{"cell_type":"code","source":["type('10')\n","type('3.14159')"],"metadata":{"id":"-Zv10HJFXUW8"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Likewise, a string that looks like a Boolean will **NOT** behave like a boolean."],"metadata":{"id":"rJ_mNXXAYIpy"}},{"cell_type":"code","source":["type('False')"],"metadata":{"id":"PN0FTHz2YRPM"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["`int`, `str` etcetera can be used to convert values between different types. Careful though, not all conversions you can think of will do what you expect!"],"metadata":{"id":"-0p3SmmgWdif"}},{"cell_type":"code","source":["int('10')\n","float('10')\n","str(10)\n","str(False)\n","bool('False') # !!!\n","NoneType('None')"],"metadata":{"id":"FPeklTLXWuXl"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["It is useful to know that each character in a string is stored as an integer. `ord(character)` lets you retrieve that integer."],"metadata":{"id":"YGU7CclEYz2y"}},{"cell_type":"code","source":["ord('2')\n","ord('a')\n","ord('A')\n","ord('\\n')\n","ord('\\t')"],"metadata":{"id":"U_63E6jfab6N"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["`chr(integer)` does the opposite: it lets you retrieve the character corresponding to a given integer."],"metadata":{"id":"0dh3t4uZa9AT"}},{"cell_type":"code","source":["chr(49)\n","chr(98)\n","chr(946)\n","chr(22823)\n","chr(129327)"],"metadata":{"id":"ffIkwHahcGv9"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Variables\n","\n","- container holding a value\n","- assigning\n"," - `variable_name = value`\n","- reassigning\n"," - `name = 'jelte'`\n"," - `name = 'julian'`\n","- in Python, no strict type\n"," - `a = 1`\n"," - `a = 'hello'`"],"metadata":{"id":"InNZNIOpezlG"}},{"cell_type":"code","source":["a = 1\n","b = \"hello\"\n","c = True\n","d = None\n","\n","print(a)"],"metadata":{"id":"wgaSYh4yfGCx"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Tip: the notebook remembers variables from previous cells, but only if you executed them."],"metadata":{"id":"BD2s2EqKfQtx"}},{"cell_type":"code","source":["print(a)\n","print(b)\n","print(c)"],"metadata":{"id":"pJ-N_rc8fZia"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Anything can go in a variable, not just single values"],"metadata":{"id":"uADEckPZgGt_"}},{"cell_type":"code","source":["d = a\n","print(d)\n","\n","e = print\n","e(b)"],"metadata":{"id":"ehEig-sCgL48"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Beware! When we assign a value, the variable stores it at that exact moment. \n","Changing one variable does not change another.\n"],"metadata":{"id":"TaiYZ3R6ghq0"}},{"cell_type":"code","source":["number = 0\n","\n","container = number\n","\n","print(container)\n","\n","number = 1\n","\n","print(container)\n","print(number)\n"],"metadata":{"id":"pIIq1la9g1Qr"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Variable names\n","\n","#### Rules\n","\n","- must start with a letter or underscore (`_`)\n","- can only contain letters (`a-z`, `A-Z`), numbers (`0-9`), and underscore (`_`)\n","- variable names are case sensitive. `name` is a different variable from `Name` \n","\n","#### Conventions\n","\n","Next to the rules, there are some conventions. \n","Please stick to them, so others will have no trouble reading and understanding your code.\n","- lowercase\n"," - DO: `name`\n"," - DON'T: `Name`\n"," - DON'T: `NAME`1\n","- readable\n"," - DO: `name`\n"," - DON'T: `n_a_m_e`\n"," - DON'T: `x098277`\n","- multiple words2\n"," - DO: `first_name` (*snake_case*)\n"," - DON'T: `FirstName` (*PascalCase*)\n"," - DON'T `firstName` (*camelCase*)\n","- comprehensive (but short)\n"," - DO: `name`\n"," - DON'T: `n`\n"," - DON'T: `the_name_of_the_person_i_want_to_print` \n","\n","1 *Fully uppercased variable names actually indicate constants, and adhere to Python conventions. We will explain this later.* \n","2 *This is purely a cultural thing. Other languages (and even other concepts within Python) use different casing*"],"metadata":{"id":"nMn_xu6Ih3hJ"}},{"cell_type":"code","source":[],"metadata":{"id":"m4pTI2BEn-Z-"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 2.1: Variables and state\n","\n","In each of the code blocks below, try to predict what will be printed, then run the code. If your guess was incorrect, try to figure out why the result is different. If your guess was correct, celebrate!"],"metadata":{"id":"pDU1uK2Igmki"}},{"cell_type":"code","source":["flavor = 'vanilla'\n","print(flavor)"],"metadata":{"id":"FydkKnx_hUPq"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["temperature = 70\n","print(flavor)"],"metadata":{"id":"LTWods50h-Ij"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print(temperature)\n","temperature = 35\n","print(temperature)"],"metadata":{"id":"l2vT4L7piGRf"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["dog_name = 'Bobby'\n","cat_name = 'Garfield'\n","dog_name = cat_name\n","cat_name = dog_name\n","print(dog_name)\n","print(cat_name)"],"metadata":{"id":"k1Z_yWLXiWy7"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Before running the following code, try to explain why it does *not* output `chocolate`."],"metadata":{"id":"BZ50KykuAYPs"}},{"cell_type":"code","source":["sweet = 'chocolate'\n","savory = 'cheese'\n","dessert = 'sweet'\n","print(dessert)"],"metadata":{"id":"X3xHg6K4Aicn"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["In each of the following lines of code, replace `None` by a value of your choice. Make it such that `my_int` is an integer, `my_float` is a float, `my_bool` is a boolean and `my_string` is a string."],"metadata":{"id":"0az3tNK7WD3G"}},{"cell_type":"code","source":["my_int = None\n","my_float = None\n","my_bool = None\n","my_string = None"],"metadata":{"id":"lY-M8mfSXDfG"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 2.2: Bonus"],"metadata":{"id":"dvNIQh7KYuJb"}},{"cell_type":"markdown","source":["How could you verify in code whether the variables you wrote above have the correct type? Write this code below.\n","\n","Hint: scroll back to the section [Difference between types](#scrollTo=Difference_between_types)."],"metadata":{"id":"GI9fyUO8XOcp"}},{"cell_type":"code","source":[],"metadata":{"id":"Om6z53RXYBoS"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["In the code block below, replace the question mark `?` by a variable name. Make it such that the final output is `'Hooray!'`."],"metadata":{"id":"h6UKIMXCj3w9"}},{"cell_type":"code","source":["cheer = 'Hooray!'\n","alarm = 'Oh no!'\n","anthem = 'Wilhelmus van Nassauwe'\n","alarm = anthem\n","? = cheer\n","cheer = anthem\n","anthem = alarm\n","print(anthem)"],"metadata":{"id":"3MI6_DY7ku30"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Expressions\n","\n","- An expression is a combination between *operands* and *operators*. \n","- Think of arithmetic: `1 + 2`\n","\n"],"metadata":{"id":"ZXd6jCn90CA_"}},{"cell_type":"markdown","source":["### Arithmetic"],"metadata":{"id":"s8uJy_kI9C8S"}},{"cell_type":"code","source":["1 + 6\n","5 - 2\n","10 / 3\n","5 * 5\n","\n","a = 8\n","b = 10\n","\n","c = b - a\n","print(c)"],"metadata":{"id":"f9ACtc0e13i-"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# multiple operators\n","4 + (3 * 5)\n","(4 + 3) * 5"],"metadata":{"id":"w9cfOflP8DEJ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### String expressions"],"metadata":{"id":"zkt9aNKm28Lc"}},{"cell_type":"code","source":["\"hello\" + \" world!\"\n","a = \"my age is: \"\n","b = 33\n","\n","a + b"],"metadata":{"id":"6os4-rt43ThF"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["a = 'hello'\n","a * 5"],"metadata":{"id":"SyrelaMu42UZ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Reassigning variables\n","\n","- You can use a variable itself when reassigning. This is useful when trying to expand an existing variable."],"metadata":{"id":"DPbfP65xXlfb"}},{"cell_type":"code","source":["a = \"hello\"\n","a = a + \", world!\"\n","print(a)\n","\n","b = 'bye'\n","b = b + b\n","print(b)\n","\n","b = b + b\n","print(b)"],"metadata":{"id":"ogL2Iw3-Xs15"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 2.3: Expressions\n","\n"],"metadata":{"id":"z_bXvnya5J2_"}},{"cell_type":"markdown","source":["1. Try to predict the value of each of the following code blocks. Can you explain any surprises?"],"metadata":{"id":"j9xhznQlbCBf"}},{"cell_type":"code","source":["1 + 1"],"metadata":{"id":"0QcMB4xwbSfL"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["1 * 1"],"metadata":{"id":"eHKN9kP9bWkm"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["a = 1\n","b = 2\n","a + b"],"metadata":{"id":"uINoRNNbbXwJ"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["c = b\n","a * b * c"],"metadata":{"id":"4xyWkYlnbc_8"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["'hakuna' + 'matata'"],"metadata":{"id":"7tW2T4mebljv"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["liquid = 'water~'\n","liquid * 3"],"metadata":{"id":"uEdPHIhBb2Mw"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["5 - 2 - 1"],"metadata":{"id":"-D7BB50Qceo2"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["5 - (2 - 1)"],"metadata":{"id":"OQUGr5rGck3m"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["income = 100\n","tax = 20\n","net_income = income - tax\n","tax = 15\n","net_income"],"metadata":{"id":"Jc8fawaIdCD5"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. In the code block below, change the values of `character` and `multiplier` so that the output becomes `'Goooood!'`."],"metadata":{"id":"TlLkcRv-droI"}},{"cell_type":"code","source":["character = 'o'\n","multiplier = 5\n","\n","begin = 'G'\n","middle = character * multiplier\n","end = 'd!'\n","\n","begin + middle + end"],"metadata":{"id":"pYZUkeDJenob"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. Rewrite your Hello world-program:\n"," - Build the \"hello, world!\" string using multiple variables.\n"," - Make the program say \"hello, world!\" 3 times, each time on a new line"],"metadata":{"id":"G8X4n_a8a5tl"}},{"cell_type":"code","source":[],"metadata":{"id":"nDUVvhDEfIVI"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 2.4: Bonus"],"metadata":{"id":"3HCqdTj2fVPK"}},{"cell_type":"markdown","source":["1. Find out and describe what the following operators do:\n"," - `%` (e.g. `10 % 2`)\n"," - `//` (e.g. `10 // 2`)\n"," - `**` (e.g. `10 ** 2`)\n"," - Tip: write the expressions using variables. Change the variables and see how it affects the outcome."],"metadata":{"id":"EKFdkLkWa8EY"}},{"cell_type":"code","source":[],"metadata":{"id":"V59a7vpDfzO2"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Predict what will be printed on each line in the following code block, then run the code to check your answer. If you made any mistakes, try to figure out what is causing the difference."],"metadata":{"id":"o0WYIAUla-AX"}},{"cell_type":"code","source":["word = 'stylometry'\n","repeats = 3\n","extra = 2\n","\n","print((word * repeats) + str(extra))\n","print(word * (repeats + extra))\n","print(word * repeats + str(extra))\n","print((word + str(extra)) * repeats)\n","print(word + str(extra * repeats))\n","print(word + str(extra) * repeats)"],"metadata":{"id":"Z9Vd9pdIUzT5"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. Using just the variables `word`, `repeats` and `extra` from the previous code block, write a single big expression that evaluates to `'stylometry555stylometry'`."],"metadata":{"id":"DRObBQZHgsIG"}},{"cell_type":"code","source":[],"metadata":{"id":"uLuiUk10gqwM"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Boolean expressions\n","Expressions that result in `True` or `False`\n"],"metadata":{"id":"QaamMzJY6ISR"}},{"cell_type":"code","source":["# equals\n","1 == 1\n","\"hello\" == 'hello'\n","'2' == 2"],"metadata":{"id":"kLjya4Au6Ucu"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# does not equal\n","1 != 1\n","\"hello\" != 'hello'\n","'2' != 2"],"metadata":{"id":"tYNp6nUp7ixW"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# greater than\n","2 > 1\n","2 > 5\n","'b' > 'a'\n","\n","2 > 2\n","\n","# greater than (or equal)\n","2 >= 2"],"metadata":{"id":"oixxKDHV7s5J"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# less than\n","2 < 1\n","2 < 5\n","'b' < 'a'\n","2 < 2\n","\n","# less than (or equal)\n","2 <= 2"],"metadata":{"id":"Z198kfCf75sU"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 2.5: boolean expressions"],"metadata":{"id":"pvrcgKU18OrJ"}},{"cell_type":"markdown","source":["1. Predict for each boolean expression below: `True` or `False`? If any of your predictions is incorrect, try to find the reason."],"metadata":{"id":"sWdnjezoil9j"}},{"cell_type":"code","source":["name = 'Jelte'\n","height = 2\n","\n","name * height == 'Jelte Jelte'\n","height < 2\n","2 <= height\n","1 < height <= 2\n","2 <= height < 1\n","name <= 'Julian'\n","height * 3 + 1 >= height"],"metadata":{"id":"RpSvrom3Z8fQ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Run the code block below. Did you expect this result? Can you explain it?"],"metadata":{"id":"zJiaGIlZBN_P"}},{"cell_type":"code","source":["1 == True"],"metadata":{"id":"_PrnFf2lioMB"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. Replace one value in each of the following expressions so the expression becomes `True`."],"metadata":{"id":"q8QviA70kdQE"}},{"cell_type":"code","source":["1 > height\n","height == 0\n","'Julian' < name * 2\n","name < 1 * name"],"metadata":{"id":"qDQ9Ob5Zkrqm"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["4. Replace one operator in each of the following expressions so the expression becomes `True`."],"metadata":{"id":"YbdV7SQVmDVV"}},{"cell_type":"code","source":["5 < 4\n","2 + 1 == 1\n","3 + 3 == 3 + 2"],"metadata":{"id":"hzjXIwkAmChv"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["5. The *Groot woordenboek van de Nederlandse taal* by Van Dale publishers, colloquially known as \"De dikke Van Dale\", is a three-tome Dutch dictionary. The first tome contains words starting a–i, the second j–q and the third r–z. In the code block below, write an expression that will tell you whether `word` should be in the second tome. Try different values of `word` to verify that your solution is correct. You do not need to check whether the word is actually Dutch!"],"metadata":{"id":"SwyAMDzDn2_X"}},{"cell_type":"code","source":["word = 'archaïsch'\n","\n","# your expression here"],"metadata":{"id":"lmCGfx_DqMWe"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[3. Conditionals](https://colab.research.google.com/drive/1KkZ2fS75o7giccQJakRhyvYBV7JdFnVw)"],"metadata":{"id":"jXSxbjf4q6q5"}}]} \ No newline at end of file diff --git a/lessons/03 conditionals.ipynb b/lessons/03 conditionals.ipynb new file mode 100644 index 0000000..a97ddaf --- /dev/null +++ b/lessons/03 conditionals.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyOwt+JcPyfyBfscI/sF+CKo"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 3: Conditionals\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [2. Values and expressions](https://colab.research.google.com/drive/17K6C_EZoeGtRxoTbYQvygFEdpWgQ2QFp)\n","\n","### This module\n","\n","- Execute code only under specific conditions."],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## `if`\n","\n","- Only evaluate part of the code if some condition is met\n","- Syntax: `if :`\n","- `` can be any expression that evaluates to `True` or `False`\n","- Introducing *indented blocks* "],"metadata":{"id":"SshSsbtF8ldm"}},{"cell_type":"code","source":["a = 12\n","\n","if a > 10:\n"," print('the condition is met!')"],"metadata":{"id":"Va6X8kIz9ey0"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["a = 15\n","\n","if a < 10:\n"," print('everything on the same indentation level belongs to this if-condition')\n"," print('so this will only get printed if the condition is met')\n"," print('and so does this')\n","print('but not this!')"],"metadata":{"id":"ADXv-2u090ql"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["- Indented blocks are the reason we sometimes need `pass` as a placeholder (remember [1. introduction](https://colab.research.google.com/drive/1i4wJpUIr77Fh1renWNjt00Bd51NbC1nB)). It lets us create an indented block, without defining any behavior for it yet."],"metadata":{"id":"5gqn2ac_sg7Y"}},{"cell_type":"code","source":["if earth == 'square':\n"," # TODO not sure yet how to handle this case\n"," pass"],"metadata":{"id":"ZdH7HnL6tDpS"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## `else`\n","\n","- `if` is nice, but what if we are interested in the other case?"],"metadata":{"id":"sQxxBZwm-FYm"}},{"cell_type":"code","source":["letter ='b'\n","\n","if letter == 'a':\n"," print('we found the letter a')\n","\n","if letter == 'b': \n"," print('this is not a')\n","\n","if letter == 'c':\n"," print('this is not a')"],"metadata":{"id":"atRhlkGq-Mh1"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Instead of specifying *all other* cases, use `else:`"],"metadata":{"id":"O1repWSS-3Y0"}},{"cell_type":"code","source":["letter = 'b'\n","\n","if letter == 'a':\n"," print('we found the letter a')\n","else:\n"," print('this is not a')"],"metadata":{"id":"4n9ksUuH-8kE"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## `elif`\n","\n","Specify extra cases with `elif :` (else if)\n","\n"],"metadata":{"id":"Rg1ohowkAGFh"}},{"cell_type":"code","source":["letter = 'a'\n","\n","if letter == 'a':\n"," print('we found the letter a')\n","elif letter == 'b':\n"," print('we found the letter b')\n","else:\n"," print('this is not a or b')"],"metadata":{"id":"JbiihBgdANIM"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Multiple conditions\n","- We can *nest* conditions"],"metadata":{"id":"lVOu8HvVIEj6"}},{"cell_type":"code","source":["number = 11\n","\n","if number > 2:\n"," if number < 10:\n"," print('between 2 and 10')\n"," print('larger than 2, but not smaller than 10')\n","\n","# There is a mistake in the code above, can you find\n","# and fix it?"],"metadata":{"id":"MH_RrrBRIPh4"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["- Even better: we can *combine* conditions\n","- use ` and `, ` or ` and `not `\n"],"metadata":{"id":"8Lvam7rpIms6"}},{"cell_type":"code","source":["number = 11\n","if number > 2 and number < 10:\n"," print('between 2 and 10')\n","\n","\n","letter = 'd'\n","if letter == 'a' or letter =='b' or letter == 'c':\n"," print('a or b or c')\n","\n","if not (letter == 'a' or letter == 'b'):\n"," print('neither a nor b')\n"],"metadata":{"id":"zJ8rBgcfIw4I"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["- `and`, `or`, `not` are operators, just like `+` and `==`. You can use them outside conditionals."],"metadata":{"id":"SmsIZBLEtg9r"}},{"cell_type":"code","source":["height = 185\n","weight = 52\n","\n","tall = height > 180\n","light = weight < 65\n","\n","skinny = tall and light\n","print(skinny)"],"metadata":{"id":"XMWJeaujt2lj"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 3.1: if/elif/else"],"metadata":{"id":"tvXa9KWXAwge"}},{"cell_type":"markdown","source":["1. Try to predict the output of the following code blocks. Can you explain any surprises?"],"metadata":{"id":"pKBuViM9u7ZC"}},{"cell_type":"code","source":["if 3 <= 2:\n"," print('What a strange day.')\n","print('What a strange day.')"],"metadata":{"id":"sEQyw2xJvzQN"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["if None == 0:\n"," pass\n"," print('I got nothing to do.')"],"metadata":{"id":"FnCFfEb_v-0Y"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["name = 'Julian'\n","\n","if name < 'Jelte':\n"," print('Alphabetically before Jelte')\n","elif name > 'Jelte':\n"," print('Alphabetically after Jelte')\n","else:\n"," print('Same name as Jelte')"],"metadata":{"id":"arta4ZQ0vDSC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. In the following code block, replace `None` with your own condition in the `if` statement. If `value` is greater than `5`, `size` must be `'large'`; otherwise, `size` must be `'small'`. Change `value` a few times and rerun the code to check that your condition is correct."],"metadata":{"id":"4SVSiqHSu4WX"}},{"cell_type":"code","source":["value = 4\n","\n","if None:\n"," size = 'large'\n","else:\n"," size = 'small'\n","\n","print(size)"],"metadata":{"id":"czmdFacjeUaL"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. Write an `if`/`elif`/`else` statement like the previous, but with different cutoff points: if `value` is less than `4`, `size` must be `'small'`; if `value` is between `4` and `6` (inclusive), `size` must be `'medium'`; if `value` is greater than `6`, `size` must be `'large'`."],"metadata":{"id":"sEOwMi04e6WW"}},{"cell_type":"code","source":["value = 4\n","\n","# your if/elif/else here\n","\n","print(size)"],"metadata":{"id":"8HeaY6l9f9iA"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["4. Rewrite the conditional that checks if a letter is neither 'a' nor 'b', using a different notation."],"metadata":{"id":"TWzbez_2RUh4"}},{"cell_type":"code","source":["letter = 'c'\n","\n","# original\n","if not (letter == 'a' or letter == 'b'):\n"," print('neither a nor b')"],"metadata":{"id":"XsIg1MD4JrPX"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 3.2: Bonus"],"metadata":{"id":"-XEYQZJ1ya1j"}},{"cell_type":"markdown","source":["*FizzBuzz part 1* (advanced).\n","Write an `if`/`elif`/`else` statement that behaves as follows:\n","\n","- if `value` is divisible by 3 but not by 5, print `'Fizz'`;\n","- if `value` is divisible by 5 but not by 3, print `'Buzz'`;\n","- if `value` is divisible by 3 *and* by 5, print `'FizzBuzz'`;\n","- in all remaining cases, print `value`.\n","\n","Tip: use the result of [Exercise 2.4.1](https://colab.research.google.com/drive/17K6C_EZoeGtRxoTbYQvygFEdpWgQ2QFp#scrollTo=Exercise_2_4_Bonus)!"],"metadata":{"id":"POVFwRu_f91I"}},{"cell_type":"code","source":["value = 9\n","\n","# Your code here"],"metadata":{"id":"SZGeQtqEhiAK"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[4. Datastructures](https://colab.research.google.com/drive/1JxzmIzwcipnwFBntv0WZOlT-d2fUjoRF)"],"metadata":{"id":"YBC4OfihzFho"}}]} \ No newline at end of file diff --git a/lessons/04 datastructures.ipynb b/lessons/04 datastructures.ipynb new file mode 100644 index 0000000..a725e97 --- /dev/null +++ b/lessons/04 datastructures.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 4: Datastructures\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [3. Conditionals](https://colab.research.google.com/drive/1KkZ2fS75o7giccQJakRhyvYBV7JdFnVw)\n","\n","### This module\n","\n","- Working with collections of many values"],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## Datastructures\n","\n","- Way to organize data, to make accessing it efficient\n","- Different types of data structures available\n","- For now, we will work with `list` and `tuple`"],"metadata":{"id":"rDdBkbX5kmUD"}},{"cell_type":"code","source":["student1 = 'jasmin'\n","student2 = 'ravi'\n","student3 = 'john'\n","# not very efficient, what if we want to add another student? Or take one out?"],"metadata":{"id":"bmAaWSOPm87H"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Lists\n","\n","- `list`: an ordered collection of values\n","- One type of *iterable*, a collection you that allows iteration over its elements\n","- Syntax: `[element1, element2, ...]`\n","- Empty list also exists: `[]`"],"metadata":{"id":"8Vl5wbRunR82"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","\n","print(students)"],"metadata":{"id":"sewvhM8JnhJZ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Lists can contain values of mixed types:"],"metadata":{"id":"zmKyJPoQnwmK"}},{"cell_type":"code","source":["['hello', 1, False]"],"metadata":{"id":"Bp6_Mev2nzZV"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Lists can also contain variables"],"metadata":{"id":"dt_IOpu_rqbk"}},{"cell_type":"code","source":["usa = 'United States of America'\n","nl = 'The Netherlands'\n","countries = [usa, nl]"],"metadata":{"id":"TTCPoO7QrtVy"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Accessing elements\n","- Every element has an *index*\n","- Index goes from 0 to length of the list - 1\n","- Negative index counts backwards from the last element"],"metadata":{"id":"uYR5FBUEoR0P"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","students[0]\n","students[1]\n","students[2]\n","students[-1]"],"metadata":{"id":"2eL0BOUJodLK"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["- Lists can be *unpacked* into variables"],"metadata":{"id":"cyX0YcO5uZRa"}},{"cell_type":"code","source":["numbers = [1, 2, 3]\n","one, two, three = numbers"],"metadata":{"id":"m6ETvPPXuc4z"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Changing elements\n","- Assign element at index just like you would a variable"],"metadata":{"id":"KvOEQrqRrS0T"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","students[0] = 'johanna'\n","\n","new_student = 'mark'\n","students[1] = new_student\n","\n","students"],"metadata":{"id":"wFyceuSArcEB"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Adding elements\n","- The `+` operator works for two lists\n","- The `.append(value)` function works on a list"],"metadata":{"id":"DixopwTyr6gN"}},{"cell_type":"code","source":["hello_world = ['hello', ',', 'world']\n","exclamation = ['!']\n","\n","full_sentence = hello_world + exclamation\n","print(full_sentence)"],"metadata":{"id":"nPyn0UHcsDbG"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# note: .append() works in-place, you don't need to reassign the variable\n","students = ['jasmin', 'ravi', 'john']\n","students.append('mark')\n","print(students)"],"metadata":{"id":"Y2B57KQRsO2a"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Nested lists\n","- Anything goes in a list, including *another* list"],"metadata":{"id":"kUUwwkDVtXOC"}},{"cell_type":"code","source":["small_list = [4, 5, 6]\n","big_list = [1, 2, 3, small_list]\n","\n","print(big_list)\n","print(big_list[-1])\n","print(type(big_list[-1]))\n","\n","# Access the last element of the small_list inside big_list:"],"metadata":{"id":"EPxrRcL0tbpN"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Accessing multiple elements\n","- Select multiple values at once: *slicing*\n","- Syntax: `list[start_index:end_index]`\n","- end_index is *exclusive*, so 'up to' end"],"metadata":{"id":"1HDqXMbWwmbk"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","# 0 1 2 3\n","students[0:1]\n","students[0:2]\n"],"metadata":{"id":"wIS3jCYlw2P6"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["`start_index` and `end_index` are optional"],"metadata":{"id":"BblECQZfw7Uy"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","students[1:]\n","students[:-1]\n","students[:]\n"],"metadata":{"id":"6fIsX2VvxEq9"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["- slices can be used to reassign list elements\n","\n"],"metadata":{"id":"n9lZQ72ExR4Z"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","\n","students[0:2] = ['johanna', 'mark']\n","\n","print(students)"],"metadata":{"id":"C5AIMJEHxWnX"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["- in this way, you can also add or remove elements in the middle"],"metadata":{"id":"CPHEdywi-IuC"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","\n","students[1:2] = []\n","print(students)\n","\n","students[1:1] = ['ravi']\n","print(students)"],"metadata":{"id":"Tzhdcojp-TTn"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Checking if an element is in a list\n","- Use the syntax ` in `"],"metadata":{"id":"nfpm1orRO34Q"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","\n","'ravi' in students\n","'Ravi' in students"],"metadata":{"id":"0A9JACKJPCYt"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Useful tricks\n","- the `len` *function* (we will learn about functions later) gives us the length of a list"],"metadata":{"id":"2NX28b3sZscv"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","len(students)"],"metadata":{"id":"A7UHSeTtZ2nw"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["- `list.index()` finds a value and gives us the index"],"metadata":{"id":"cO6hX3FBZ6cC"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","students.index('ravi')"],"metadata":{"id":"VPmLssc7aByj"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Tuples\n","- Different type of *iterable*\n","- Syntax: `(element1, element2, ...)`\n","- Important difference: not *mutable* (cannot change elements)\n","- Often used to unpack, we will work with tuples in data analysis"],"metadata":{"id":"ZyOZeS2SuRJ6"}},{"cell_type":"code","source":["students = ('jasmin', 'ravi', 'john')\n","students[0]"],"metadata":{"id":"etiZVM_puu4Z"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 4.1: Lists\n","\n","1. For each of the `print` statements below, what do you expect is printed? Run the lines to check predictions"],"metadata":{"id":"70aMsClGPRy9"}},{"cell_type":"code","source":["countries = ['japan', 'hungary', 'maldives', 'gabon', 'bhutan']\n","\n","print(countries[0])\n","print(countries[-3])\n","print(countries[0:1] + countries[2:4])\n","\n","more_countries = countries + ['mexico', 'haiti']\n","print(more_countries)\n","\n","countries.append(['mexico', 'haiti'])\n","print(countries)"],"metadata":{"id":"KMUxwcSqPlU1"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Transform the list below into `['jasmin', 'john', 'ravi']` in one line of code. \n","\n"],"metadata":{"id":"TyebsOIpU6hv"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']"],"metadata":{"id":"H8o6vsHKVKoq"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. For each of the print statements below, what do you expect is printed? Run the lines to check predictions."],"metadata":{"id":"HMU5X7XFWbCw"}},{"cell_type":"code","source":["random_fruit = 'pineapple'\n","fruits = ['apple', 'pear', random_fruit]\n","print(fruits)\n","\n","random_fruit = 'blueberry'\n","print(fruits)\n","\n","random_veggie = ['brussel sprouts']\n","veggies = ['broccoli', 'green beans', random_veggie]\n","print(veggies)\n","\n","random_veggie.append('kale')\n","print(veggies)"],"metadata":{"id":"u_RWc8wBWgMT"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 4.2: Bonus\n","\n","Below we introduce another parameter in the list slice. Try to explain what it does."],"metadata":{"id":"3BfUO-jKS_u1"}},{"cell_type":"code","source":["countries = ['japan', 'hungary', 'maldives', 'gabon', 'bhutan']\n","\n","print(countries[0:5:1])\n","print(countries[0:5:2])\n","print(countries[-1::-1])\n","print(countries[-1::-2])"],"metadata":{"id":"Y9oxyQb7TIPI","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681202305255,"user_tz":-120,"elapsed":627,"user":{"displayName":"Mees van Stiphout","userId":"10520931415894572279"}},"outputId":"158288d5-94e0-4068-d13e-af2a5c85177f"},"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["['japan', 'hungary', 'maldives', 'gabon', 'bhutan']\n","['japan', 'maldives', 'bhutan']\n","['bhutan', 'gabon', 'maldives', 'hungary', 'japan']\n","['bhutan', 'maldives', 'japan']\n"]}]},{"cell_type":"markdown","source":["The piece of code below is supposed to recognize \"fancy\" words: words that are longer than 5 characters, contain at least one copy of the letter 'a' and start with an uppercase. However, the code is broken. It does not recognize any of our fancy example words.\n","\n","1. Change the value of `word` into each of the examples in the comments on the first two lines and then run the code. See for yourself that the code considers none of the example words fancy. Try some other words as well.\n","3. Try to understand why the code is giving the wrong result. Can you come up with a word that the code does consider fancy?\n","4. Repair the code so that it gives the right result for all examples, and any other words that you come up with."],"metadata":{"id":"Mb6CvHt3CaA0"}},{"cell_type":"code","source":["# fancy: Alhambra, Arthur, Jasmine, Turandot\n","# not so fancy: Jeep, paper, Python, Ada\n","word = 'Alhambra'\n","\n","lengthy = len(word) > 5\n","has_a = 'a' in word\n","first_uppercase = 'A' <= word[1] <= 'Z'\n","\n","if lengthy and has_a and first_uppercase:\n"," print('The word is fancy')\n","else:\n"," print('The word is not so fancy')"],"metadata":{"id":"QQyGzsqCCe3o"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[5. Assertions](https://colab.research.google.com/drive/1Nv6vgkH2zjJes7LXUCVhsDwFOGCtTbHM)"],"metadata":{"id":"HiEWGB1V1W4U"}}]} \ No newline at end of file diff --git a/lessons/05 assertions.ipynb b/lessons/05 assertions.ipynb new file mode 100644 index 0000000..050c103 --- /dev/null +++ b/lessons/05 assertions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 5: Assertions\n","\n","### Exercise solutions\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [4. Datastructures](https://colab.research.google.com/drive/1JxzmIzwcipnwFBntv0WZOlT-d2fUjoRF)\n","\n","### This module\n","\n","- Interrupting the program if something isn't right, with useful output."],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## `assert`\n","\n","With an assertion, you tell Python that you want something to be `True`. This is an easy way to insert sanity checks in your code."],"metadata":{"id":"bxJaE7DE4ig4"}},{"cell_type":"code","source":["assert 2 < 3"],"metadata":{"id":"PzRUSOI54_Zq"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["For clarity, you can describe the expectation."],"metadata":{"id":"tPPNPy2q5hAU"}},{"cell_type":"code","source":["sky = 'red'\n","\n","assert sky == 'blue', 'We expect to be on Earth'"],"metadata":{"id":"58Pa2nRq5x8R"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["You can use `assert` statements to:\n","- provide a sanity check, make sure something is true at some point in the code\n","- provide test conditions for your code, make sure what you programmed actually behaves the way you wish"],"metadata":{"id":"aLDwedXecSLp"}},{"cell_type":"markdown","source":["## Exercise 5.1: Assertions\n","In each of the code blocks below, try to predict what will be the output, then run the code. If your guess was incorrect, try to figure out why the result is different. If your guess was correct, celebrate!"],"metadata":{"id":"m_FYfvXbbZXe"}},{"cell_type":"code","source":["assert True"],"metadata":{"id":"ztDylwg9biL5"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["assert False, \"The assertion fails because the value is False\""],"metadata":{"id":"0Uk4w2DBbxfD"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["assert \"True\""],"metadata":{"id":"orOWCpWVbzKf"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["assert \"False\", \"The assertion fails because the value is False\""],"metadata":{"id":"F6NjZ7gOb05u"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["assert 1"],"metadata":{"id":"KB_YkNSIb2KT"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["assert 1 == True, \"The number 1 is not True\""],"metadata":{"id":"1iUK81Nvb3Ri"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["assert 0"],"metadata":{"id":"Tje6e-Jgb4rn"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 5.2: Bonus - Test-driven development\n","[Test-driven development](https://en.wikipedia.org/wiki/Test-driven_development) is a proccess where you **first** write some test conditions, and then write the code that should satisfy these conditions. \n","Implement the following programs in these steps:\n","1. Create multiple test conditions using `assert`\n","2. Run the cell, the tests should fail (output `AssertionError`)\n","3. Write the code that satisfies the conditions\n","4. The cell should complete succesfully\n","\n","We have already implemented step 1 for these exercises."],"metadata":{"id":"xgqh3r7Bcj_F"}},{"cell_type":"markdown","source":["In the code block below, change the value for `b`, and create an expression for `c` using `a` and `b` so that the assert statements succeed.\n"],"metadata":{"id":"TMWSMWg7dQqB"}},{"cell_type":"code","source":["a = 12\n","b = 0\n","\n","# Write an expression for c using a and b\n","c = 0\n","\n","assert a < b, 'a should be smaller than b'\n","assert a != b, 'a and b should not be equal'\n","assert c == 18, 'c should be 18'"],"metadata":{"id":"Q_yIUKSRdVjF"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["In the code block below, change `students` so that it satisfies the `assert` statements. Also, add messages to the assert statements that explain what they test (in human language)."],"metadata":{"id":"1u_bBUpSfQr5"}},{"cell_type":"code","source":["students = ['ernie', 'bert']\n","\n","assert len(students) == 3\n","assert students[0] < students[1] < students[2]"],"metadata":{"id":"UOp8NFVOfR6Z"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[6. Loops](https://colab.research.google.com/drive/1AZY4ESmsKKMvbalBDLlMrezAM5NzXXxV)"],"metadata":{"id":"JaaguG-D3k_i"}}]} \ No newline at end of file diff --git a/lessons/06 Loops - Legacy.ipynb b/lessons/06 Loops - Legacy.ipynb new file mode 100644 index 0000000..2adbdf4 --- /dev/null +++ b/lessons/06 Loops - Legacy.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyO/OJ7mLjXRcw3YDskGFU1J"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"code","execution_count":null,"metadata":{"id":"ZGnlpVha4WwJ"},"outputs":[],"source":[]},{"cell_type":"markdown","source":["# CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)"],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["# 1. Loops\n","\n","Loops are the most primitive way to run code *repeatedly*. For example:\n","\n","- Run some lines of code for each word in a text.\n","- Run some lines of code for each number in a list.\n","- Run some lines of code until you have found the answer to a question.\n","\n","There are \"smarter\" ways to repeat code that we will cover later in the course."],"metadata":{"id":"mzWET4w4lAr4"}},{"cell_type":"markdown","source":["## `while` loops\n","\n","A `while` loop looks like an `if` statement, but it repeats as long as the condition is `True`:"],"metadata":{"id":"d7GJLYfEXwfs"}},{"cell_type":"code","source":["name = 'Jelte'\n","while len(name) < 10:\n"," name = name + '!'\n","print(name)"],"metadata":{"id":"Fnut4-DIYmb8","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667900027935,"user_tz":-60,"elapsed":517,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"91a840be-aa92-47c9-c07f-bb52cb0447bc"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["Jelte!!!!!\n"]}]},{"cell_type":"markdown","source":["`while` loops are impractical if you want to repeat something for every element of an iterable, such as a list."],"metadata":{"id":"p9-je4X0zkhq"}},{"cell_type":"markdown","source":["## `for` loops over lists\n","\n","Do something with every element in a list:"],"metadata":{"id":"BDCe1ux90B7r"}},{"cell_type":"code","source":["the_list = [1, 'hello', True]\n","\n","for element in the_list:\n"," print(element)"],"metadata":{"id":"O0XEpRMI0WG2","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667900112073,"user_tz":-60,"elapsed":395,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"41b9437b-26e9-45c4-ffb6-48e2d0510e0b"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["1\n","hello\n","True\n"]}]},{"cell_type":"markdown","source":["The body of the loop is an *indented block*, just like in an `if` or `while` statement. You can have multiple lines that repeat together:"],"metadata":{"id":"gdd6v6LU1DlK"}},{"cell_type":"code","source":["words = ['A', 'very', 'short', 'sentence']\n","full_text = ''\n","\n","for word in words:\n"," full_text = full_text + word + ' '\n"," print(word)\n"," print(full_text)"],"metadata":{"id":"dpqb0qFc1u0s","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667900436458,"user_tz":-60,"elapsed":384,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"9311ae9c-066d-4dbf-da9a-7c440473dac3"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["A\n","A \n","very\n","A very \n","short\n","A very short \n","sentence\n","A very short sentence \n"]}]},{"cell_type":"markdown","source":["The loop ends when the indentation ends. Here, we calculate the sum of a list of numbers, and print the sum only at the end:"],"metadata":{"id":"vDU53qkB2zo4"}},{"cell_type":"code","source":["numbers = [9, 9, 4, 7, 6]\n","sum = 0\n","\n","for number in numbers:\n"," sum = sum + number\n","print(sum)"],"metadata":{"id":"q6ucnoqeUnlI","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667900533282,"user_tz":-60,"elapsed":550,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"461dfdab-3387-4d9e-d59e-ad73fb8993cd"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["35\n"]}]},{"cell_type":"markdown","source":["## Exercise 1: basic `for` loops\n","\n","1. Make a small change to the following code block (copied from above), so that it prints the `full_text` only at the end, when it is complete."],"metadata":{"id":"0Gun_3cX1ey8"}},{"cell_type":"code","source":["words = ['A', 'very', 'short', 'sentence']\n","full_text = ''\n","\n","for word in words:\n"," full_text = full_text + word + ' '\n"," print(word)\n"," print(full_text)"],"metadata":{"id":"nMF8WE3F19HC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Using a `for` loop, create a copy of the list of fruits below that has the fruits in the reverse order. Change the contents of the list on the first line to check that your solution is general."],"metadata":{"id":"8zB10pLC2ZaT"}},{"cell_type":"code","source":["fruits = ['apricot', 'banana', 'cherry', 'date']\n","\n","# insert your code here\n","# SHOULD output ['date', 'cherry', 'banana', 'apricot']\n","\n","reverse_fruits = fruits[-1::-1]\n","print(reverse_fruits)\n","\n","reverse_fruits = []\n","for fruit in fruits[-1::-1]:\n"," reverse_fruits.append(fruit)\n"," reverse_fruits = reverse_fruits + [fruit]\n","print(reverse_fruits)\n","\n","reverse_fruits = []\n","for fruit in fruits:\n"," reverse_fruits = [fruit] + reverse_fruits\n"," print(fruit, reverse_fruits)\n","print(reverse_fruits)\n","\n","reverse_fruits = []\n","reverse_fruits = [fruits[0]] + reverse_fruits\n","reverse_fruits = [fruits[1]] + reverse_fruits\n","reverse_fruits = [fruits[2]] + reverse_fruits\n","reverse_fruits = [fruits[3]] + reverse_fruits\n","print(reverse_fruits)\n","\n","reverse_fruits = []\n","for fruit in fruits:\n"," reverse_fruits[0:0] = [fruit]\n","print(reverse_fruits)\n","\n","reverse_fruits = []\n","reverse_fruits[0:0] = [fruits[0]]\n","reverse_fruits[0:0] = [fruits[1]]\n","reverse_fruits[0:0] = [fruits[2]]\n","reverse_fruits[0:0] = [fruits[3]]\n","\n","reverse_fruits = []\n","for fruit in fruits:\n"," reverse_fruits[-1:0] = [fruit]\n"],"metadata":{"id":"bAwZ_ipU28AY","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667903740371,"user_tz":-60,"elapsed":363,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"6d1d0526-c780-4eaa-d9e4-2262de2691c2"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["apricot ['apricot']\n","banana ['banana', 'apricot']\n","cherry ['cherry', 'banana', 'apricot']\n","date ['date', 'cherry', 'banana', 'apricot']\n","['date', 'cherry', 'banana', 'apricot']\n"]}]},{"cell_type":"markdown","source":["## Variations on loops\n","\n","All of the following variations can also be combined."],"metadata":{"id":"DATxv0pM2gQc"}},{"cell_type":"markdown","source":["### Infinite loop"],"metadata":{"id":"MVcUZD4T7j4h"}},{"cell_type":"code","source":["while True:\n"," print('Hello, living lab!')"],"metadata":{"id":"l40DJzDx2nCz"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Generally something to avoid, but sometimes useful with `break`."],"metadata":{"id":"0axR682t-ub4"}},{"cell_type":"markdown","source":["### Breaking out of a loop"],"metadata":{"id":"2xzzyBX43Rbq"}},{"cell_type":"code","source":["basket = ['apricot', 'banana', 'cherry', 'date']\n","\n","for fruit in basket:\n"," print(fruit)\n"," if fruit == 'elderberry':\n"," print('Yay, this basket has elderberry! 🤤')\n"," break\n","else:\n"," print('Aww no elderberry. 😞')"],"metadata":{"id":"kbbKDHwd4Eiq","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667904280773,"user_tz":-60,"elapsed":439,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"6ff54d8a-dfa6-4995-c469-1b3177bce245"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["apricot\n","banana\n","cherry\n","date\n","Aww no elderberry. 😞\n"]}]},{"cell_type":"markdown","source":["`break`/`else` can be used both with `for` and `while` loops. The `else` is not required."],"metadata":{"id":"3C9WlDSd-8zw"}},{"cell_type":"markdown","source":["### Skipping to the next iteration"],"metadata":{"id":"ZZGIvGNg673Z"}},{"cell_type":"code","source":["chores = ['dishwashing', 'vacuum cleaning', 'laundry']\n","\n","for task in chores:\n"," # I really hate vacuum cleaning\n"," if task == 'vacuum cleaning':\n"," continue\n"," print(task)"],"metadata":{"id":"AyVZVJtL7nMJ","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667904433491,"user_tz":-60,"elapsed":525,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"2df5b782-b01c-4bea-812f-4f17ab255e5e"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["dishwashing\n","laundry\n"]}]},{"cell_type":"markdown","source":["Works both in `for` and `while`."],"metadata":{"id":"3fs83n3H_J_j"}},{"cell_type":"markdown","source":["### Nested loops\n","\n","Nesting loops is **allowed**, to arbitrary depth. `for` and `while` can be mixed. However, nesting loops has a big **disadvantage**: your code quickly becomes less readable.\n","\n","Below, we use nested loops to iterate over nested lists."],"metadata":{"id":"FHf46PtqBvVb"}},{"cell_type":"code","source":["table = [\n"," ['bread', 'fluffy', 'light brown'],\n"," ['olives', 'savory', 'dark green'],\n"," ['grapes', 'sweet', 'shiny red'],\n","]\n","\n","for row in table:\n"," print('new row:')\n"," for cell in row:\n"," print(cell, end='; ') # does not finish with a linebreak\n"," print() # puts a linebreak"],"metadata":{"id":"WffnwizrCvPw","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667904767636,"user_tz":-60,"elapsed":527,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"64cc2f10-38da-4276-a401-26eeffd95890"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["new row:\n","bread; fluffy; light brown; \n","new row:\n","olives; savory; dark green; \n","new row:\n","grapes; sweet; shiny red; \n"]}]},{"cell_type":"markdown","source":["### Iterating over a string"],"metadata":{"id":"DZVVVSYy8HGd"}},{"cell_type":"code","source":["invitation = '''\n"," Dear Jelte,\n","\n"," I hereby invite you for my Python party on the 9th of November.\n"," The bar will open at 2 PM. 🍸 Please bring pseudocode.\n","\n"," Yours sincerely,\n"," Julian\n","'''\n","\n","lowercase = 0\n","uppercase = 0\n","other = 0\n","for character in invitation:\n"," if 'a' <= character <= 'z':\n"," lowercase = lowercase + 1\n"," elif 'A' <= character <= 'Z':\n"," uppercase = uppercase + 1\n"," else:\n"," other = other + 1\n","\n","print(lowercase, 'lowercase,', uppercase, 'uppercase and', other, 'other.')"],"metadata":{"id":"14DRs2jK8Po7","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667905025657,"user_tz":-60,"elapsed":459,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"bd49b199-0647-4e5b-86fd-19c7d09497ee"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["106 lowercase, 11 uppercase and 60 other.\n"]}]},{"cell_type":"markdown","source":["### Iterating over generated sequences\n","\n","*Generators* are iterables that produce one value at a time, so they do not need to store all their values at the same time.\n","\n","`range` creates a generator that produces consecutive numbers."],"metadata":{"id":"HrfN3OhbELuM"}},{"cell_type":"code","source":["for number in range(5):\n"," print(number)"],"metadata":{"id":"iqNQLZVcHYRX","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667905473540,"user_tz":-60,"elapsed":11,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"40591d82-d9d1-4c9c-c887-042daa2f9a81"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["0\n","1\n","2\n","3\n","4\n"]}]},{"cell_type":"markdown","source":["`enumerate` creates a new iterable based on another iterable, so you get not only the values but also their indices."],"metadata":{"id":"9GySTLd_Hq9l"}},{"cell_type":"code","source":["basket = ['apricot', 'banana', 'cherry', 'date']\n","\n","for index, fruit in enumerate(basket):\n"," print('Fruit number', index, 'is', fruit)"],"metadata":{"id":"MIyn99IxH74D","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667905472137,"user_tz":-60,"elapsed":566,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"0c2f832c-c245-49ef-c51c-da9903e163e5"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["Fruit number 0 is apricot\n","Fruit number 1 is banana\n","Fruit number 2 is cherry\n","Fruit number 3 is date\n"]}]},{"cell_type":"markdown","source":["There are many more ways to create generators, and many more ways to use them as well. We will see more of them later on in the course."],"metadata":{"id":"WGlaXiuxISRX"}},{"cell_type":"markdown","source":["## Exercise 2: more loops\n","\n","1. The code block below is written to help you explore what kind of \"stuff\" comes out of `range` and `enumerate`. Read the code from top to bottom. What stands out to you? Why do you think it was written this way?\n","\n","2. Run the code block for each example value of `miracle`. Based on the results, describe in your own words what `range` and `enumerate` do."],"metadata":{"id":"-K0CvNkOLEYE"}},{"cell_type":"code","source":["basket = ['apricot', 'banana', 'cherry', 'date']\n","\n","miracle = range(10)\n","# miracle = range(2, 11)\n","# miracle = range(2, 11, 3)\n","# miracle = range(11, 2, -2)\n","# miracle = range(0.1, 1.0, 0.1)\n","# miracle = enumerate(basket)\n","# miracle = enumerate('pirate')\n","# miracle = enumerate(range(10))\n","\n","print(type(miracle))\n","\n","iteration_count = 0\n","for value in miracle:\n"," iteration_count = iteration_count + 1\n"," if iteration_count > 2:\n"," continue\n"," elif iteration_count == 1:\n"," print(type(value))\n"," print(value)\n","print(value)\n","print('length:', iteration_count)"],"metadata":{"id":"7gappYcLOrsu","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667910549466,"user_tz":-60,"elapsed":465,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"6fff15b1-41c9-4798-bbb6-43c9ef12c85d"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["\n","\n","0\n","1\n","9\n","length: 10\n"]}]},{"cell_type":"markdown","source":["3. The `input` function, demonstrated below, lets you ask the human user for a string and then store it in a variable. Write a program that keeps asking the user for words until the word is `'stop'`. For each word, report to the user how many characters it contains."],"metadata":{"id":"2Haq4E95bN6T"}},{"cell_type":"code","source":["# word = input('Please give me a word: ')\n","# print('you wrote', word)\n","word = ''\n","while word != 'stop':\n"," word = input('Please give me a word: ')\n"," print('you wrote', word)\n"," print('the length is', len(word))\n","\n","word = ''\n","while True:\n"," word = input('Please give me a word: ')\n"," if word == 'stop':\n"," break\n"," # else:\n"," print('you wrote', word)\n"," length = 0\n"," for character in word:\n"," length = length + 1\n"," print('the length is', length)"],"metadata":{"id":"0k_YQbBccyC_","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667914234752,"user_tz":-60,"elapsed":6733,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"15b0c654-f047-4036-b95c-36a42d112d6b"},"execution_count":null,"outputs":[{"name":"stdout","output_type":"stream","text":["Please give me a word: charming\n","you wrote charming\n","the length is 8\n","Please give me a word: stop\n"]}]},{"cell_type":"markdown","source":["4. *FizzBuzz part 2* (advanced). Look back at your solution to exercise 5.3 from day 1 (*FizzBuzz part 1*). Now write a program that does the following: for each integer from `1` up to and including `100`, print `Fizz`, `Buzz`, `FizzBuzz` or the number itself, following the same rules as before. Separate the words and numbers by commas. Add a newline after every tenth number, so you print ten lines in total. The first line should start like `1, 2, Fizz, 4, Buzz, Fizz, ...` and the last line should be `91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz, `."],"metadata":{"id":"uyqbuhKsUlhG"}},{"cell_type":"code","source":["# the end=', ' argument will help you:\n","print('this prints with a comma instead of a newline', end=', ')\n","print('this as well', end=', ')\n","# empty print() adds a newline:\n","print()\n","print('next line for illustration')\n","\n","# iteration = 0\n","for n in range(1, 101):\n"," # iteration = iteration + 1\n"," if n % 15 == 0:\n"," print('FizzBuzz', end=', ')\n"," elif n % 3 == 0:\n"," print('Fizz', end=', ')\n"," elif n % 5 == 0:\n"," print('Buzz', end=', ')\n"," else:\n"," print(n, end=', ')\n"," if n % 10 == 0:\n"," print()\n","\n","numbers = range(1, 101)\n","for number in numbers:\n"," if not number % 15:\n"," output = 'FizzBuzz'\n"," elif not number % 3:\n"," output = 'Fizz'\n"," elif not number % 5:\n"," output = 'Buzz'\n"," else:\n"," output = number\n"," if number == numbers[-1]:\n"," print(output, end='.')\n"," elif not number % 10:\n"," print(output, end=',\\n')\n"," else:\n"," print(output, end=', ')\n","\n","range(100)[10]"],"metadata":{"id":"BUeMXIQXaKna","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667915778770,"user_tz":-60,"elapsed":674,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"2852de82-cad6-4441-8f47-5555c83f08a4"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["10"]},"metadata":{},"execution_count":74}]}]} \ No newline at end of file diff --git a/lessons/06 Loops.ipynb b/lessons/06 Loops.ipynb new file mode 100644 index 0000000..c79a22c --- /dev/null +++ b/lessons/06 Loops.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 6: Loops\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [5. Assertions](https://colab.research.google.com/drive/1Nv6vgkH2zjJes7LXUCVhsDwFOGCtTbHM?usp=share_link) "],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["# 1. Loops\n","\n","Loops are the most primitive way to run code *repeatedly*. For example:\n","\n","- Run some lines of code for each word in a text.\n","- Run some lines of code for each number in a list.\n","- Run some lines of code until you have found the answer to a question.\n","\n","There are \"smarter\" ways to repeat code that we will cover later in the course."],"metadata":{"id":"mzWET4w4lAr4"}},{"cell_type":"markdown","source":["## `while` loops\n","\n","A `while` loop looks like an `if` statement, but it repeats as long as the condition is `True`:"],"metadata":{"id":"d7GJLYfEXwfs"}},{"cell_type":"code","source":["name = 'Mees'\n","while len(name) < 10:\n"," name = name + '!'\n","print(name)"],"metadata":{"id":"Fnut4-DIYmb8"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["`while` loops are impractical if you want to repeat something for every element of an iterable, such as a list."],"metadata":{"id":"p9-je4X0zkhq"}},{"cell_type":"markdown","source":["## `for` loops over lists\n","\n","For loops do something for every element in a list, so the length of the list is the number of iterations. What is especially useful about for-loops is that for every iteration, the item in the list can be used in the indented code block. This means that you can do a certain action for each item in the list without having to provide the index for that item. For example:"],"metadata":{"id":"BDCe1ux90B7r"}},{"cell_type":"code","source":["the_list = [1, 'hello', True]\n","\n","for element in the_list:\n"," print(element)"],"metadata":{"id":"O0XEpRMI0WG2"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["The body of the loop is an *indented block*, just like in an `if` or `while` statement. You can have multiple lines that repeat together:"],"metadata":{"id":"gdd6v6LU1DlK"}},{"cell_type":"code","source":["words = ['A', 'very', 'short', 'sentence']\n","full_text = ''\n","\n","for word in words:\n"," full_text = full_text + word + ' '\n"," print(word)\n"," print(full_text)"],"metadata":{"id":"dpqb0qFc1u0s"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["The loop ends when the indentation ends. Here, we calculate the sum of a list of numbers, and print the sum only at the end:"],"metadata":{"id":"vDU53qkB2zo4"}},{"cell_type":"code","source":["numbers = [9, 9, 4, 7, 6]\n","sum = 0\n","\n","for number in numbers:\n"," sum = sum + number\n","print(sum)"],"metadata":{"id":"q6ucnoqeUnlI","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1667900533282,"user_tz":-60,"elapsed":550,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"461dfdab-3387-4d9e-d59e-ad73fb8993cd"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["35\n"]}]},{"cell_type":"markdown","source":["## Exercise 1: basic `for` loops\n","\n","1. Make a small change to the following code block (copied from above), so that it prints the `full_text` only at the end, when it is complete."],"metadata":{"id":"0Gun_3cX1ey8"}},{"cell_type":"code","source":["words = ['A', 'very', 'short', 'sentence']\n","full_text = ''\n","\n","for word in words:\n"," full_text = full_text + word + ' '\n"," print(word)\n"," print(full_text)"],"metadata":{"id":"nMF8WE3F19HC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Using a `for` loop, create a copy of the list of fruits below that has the fruits in the reverse order. Change the contents of the list on the first line to check that your solution is general."],"metadata":{"id":"8zB10pLC2ZaT"}},{"cell_type":"code","source":["fruits = ['apricot', 'banana', 'cherry', 'date']\n","\n","# insert your code here\n","# SHOULD output ['date', 'cherry', 'banana', 'apricot']\n"],"metadata":{"id":"bAwZ_ipU28AY"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Variations on loops\n","\n","All of the following variations can also be combined."],"metadata":{"id":"DATxv0pM2gQc"}},{"cell_type":"markdown","source":["### Infinite loop"],"metadata":{"id":"MVcUZD4T7j4h"}},{"cell_type":"code","source":["while True:\n"," print('Hello, living lab!')"],"metadata":{"id":"l40DJzDx2nCz"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Generally something to avoid, but sometimes useful with `break`."],"metadata":{"id":"0axR682t-ub4"}},{"cell_type":"markdown","source":["### Breaking out of a loop\n","You can break out of a loop by using the `break` statement, like shown here:"],"metadata":{"id":"2xzzyBX43Rbq"}},{"cell_type":"code","source":["basket = ['apricot', 'banana', 'cherry', 'date']\n","\n","for fruit in basket:\n"," print(fruit)\n"," if fruit == 'elderberry':\n"," print('Yay, this basket has elderberry! 🤤')\n"," break\n","else:\n"," print('Aww no elderberry. 😞')"],"metadata":{"id":"kbbKDHwd4Eiq"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["`break`/`else` can be used both with `for` and `while` loops. The `else` is not required though, you can have an `if` statement without it, in which case nothing will happen if the `if` statement returns `False`."],"metadata":{"id":"3C9WlDSd-8zw"}},{"cell_type":"markdown","source":["### Skipping to the next iteration"],"metadata":{"id":"ZZGIvGNg673Z"}},{"cell_type":"code","source":["chores = ['dishwashing', 'vacuum cleaning', 'laundry']\n","\n","for task in chores:\n"," # I really hate vacuum cleaning\n"," if task == 'vacuum cleaning':\n"," continue\n"," print(task)"],"metadata":{"id":"AyVZVJtL7nMJ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Works both in `for` and `while` loops."],"metadata":{"id":"3fs83n3H_J_j"}},{"cell_type":"markdown","source":["### Nested loops\n","\n","Nesting loops is **allowed**, to arbitrary depth. `for` and `while` can be mixed. However, nesting loops has a big **disadvantage**: your code quickly becomes less readable.\n","\n","Below, we use nested loops to iterate over nested lists."],"metadata":{"id":"FHf46PtqBvVb"}},{"cell_type":"code","source":["table = [\n"," ['bread', 'fluffy', 'light brown'],\n"," ['olives', 'savory', 'dark green'],\n"," ['grapes', 'sweet', 'shiny red'],\n","]\n","\n","for row in table:\n"," print('new row:')\n"," for cell in row:\n"," print(cell, end='; ') # does not finish with a linebreak\n"," print() # puts a linebreak"],"metadata":{"id":"WffnwizrCvPw"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Iterating over a string\n","Note here that when you iterate over a string, python treats the string as if it were a list with characters, including whitespaces. If you want to iterate over the words in a string, you can use the `.split()` function to split the string into a list of strings where each item is one word (separated by whitespace in the original string)."],"metadata":{"id":"DZVVVSYy8HGd"}},{"cell_type":"code","source":["invitation = '''\n"," Dear Mees,\n","\n"," I hereby invite you for my Python party on the 11th of April.\n"," The bar will open at 2 PM. 🍸 Please bring pseudocode.\n","\n"," Yours sincerely,\n"," Julian\n","'''\n","\n","lowercase = 0\n","uppercase = 0\n","other = 0\n","for character in invitation:\n"," if 'a' <= character <= 'z':\n"," lowercase = lowercase + 1\n"," elif 'A' <= character <= 'Z':\n"," uppercase = uppercase + 1\n"," else:\n"," other = other + 1\n","\n","print(lowercase, 'lowercase,', uppercase, 'uppercase and', other, 'other.')\n","\n","long_words = 0\n","short_words = 0\n","for word in invitation.split():\n"," if len(word) > 5:\n"," long_words = long_words + 1\n"," else:\n"," short_words = short_words + 1\n","print(short_words, 'short words', long_words, 'long words')"],"metadata":{"id":"14DRs2jK8Po7"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Iterating over generated sequences\n","\n","*Generators* are iterables that produce one value at a time, so they do not need to store all their values at the same time.\n","\n","`range` creates a generator that produces consecutive numbers."],"metadata":{"id":"HrfN3OhbELuM"}},{"cell_type":"code","source":["for number in range(5):\n"," print(number)"],"metadata":{"id":"iqNQLZVcHYRX"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["`enumerate` creates a new iterable based on another iterable, so you get not only the values but also their indices."],"metadata":{"id":"9GySTLd_Hq9l"}},{"cell_type":"code","source":["basket = ['apricot', 'banana', 'cherry', 'date']\n","\n","for index, fruit in enumerate(basket):\n"," print('Fruit number', index, 'is', fruit)"],"metadata":{"id":"MIyn99IxH74D"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["There are many more ways to create generators, and many more ways to use them as well. We will see more of them later on in the course."],"metadata":{"id":"WGlaXiuxISRX"}},{"cell_type":"markdown","source":["## Exercise 2: more loops\n","\n","1. The code block below is written to help you explore what kind of \"stuff\" comes out of `range` and `enumerate`. Read the code from top to bottom. What stands out to you? Why do you think it was written this way?\n","\n","2. Run the code block for each example value of `miracle`. Based on the results, describe in your own words what `range` and `enumerate` do."],"metadata":{"id":"-K0CvNkOLEYE"}},{"cell_type":"code","source":["basket = ['apricot', 'banana', 'cherry', 'date']\n","\n","miracle = range(10)\n","# miracle = range(2, 11)\n","# miracle = range(2, 11, 3)\n","# miracle = range(11, 2, -2)\n","# miracle = range(0.1, 1.0, 0.1)\n","# miracle = enumerate(basket)\n","# miracle = enumerate('pirate')\n","# miracle = enumerate(range(10))\n","\n","print('type of miracle:', type(miracle))\n","\n","iteration_count = 0\n","for value in miracle:\n"," iteration_count = iteration_count + 1\n"," if iteration_count > 2:\n"," continue\n"," elif iteration_count == 1:\n"," print('type of first iteration:', type(value))\n"," print('value of current iteration:', value)\n","\n","print('number of iterations:', iteration_count)"],"metadata":{"id":"7gappYcLOrsu"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. The `input` function, demonstrated below, lets you ask the human user for a string and then store it in a variable. Write a program that keeps asking the user for words until the word is `'stop'`. For each word, report to the user how many characters it contains."],"metadata":{"id":"2Haq4E95bN6T"}},{"cell_type":"code","source":["word = input('Please give me a word: ')\n","print('you wrote', word)\n"],"metadata":{"id":"0k_YQbBccyC_"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["4. *FizzBuzz part 2* (advanced). Look back at your solution to exercise 3.2 from day 1 (*FizzBuzz part 1*). Now write a program that does the following: for each integer from `1` up to and including `100`, print `Fizz`, `Buzz`, `FizzBuzz` or the number itself, following the same rules as before. Separate the words and numbers by commas. Add a newline after every tenth number, so you print ten lines in total. The first line should start like `1, 2, Fizz, 4, Buzz, Fizz, ...` and the last line should be `91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz, `."],"metadata":{"id":"uyqbuhKsUlhG"}},{"cell_type":"code","source":["# the end=', ' argument will help you:\n","print('this prints with a comma instead of a newline', end=', ')\n","print('this as well', end=', ')\n","# empty print() adds a newline:\n","print()\n","print('next line for illustration')\n"],"metadata":{"id":"BUeMXIQXaKna"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[7. Functions](https://colab.research.google.com/drive/1APhegD_KpLRFn5bC6Ater2wFpT8_Opfr)"],"metadata":{"id":"0eGibfk04LI0"}}]} \ No newline at end of file diff --git a/lessons/07 Functions.ipynb b/lessons/07 Functions.ipynb new file mode 100644 index 0000000..ef8e8dc --- /dev/null +++ b/lessons/07 Functions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 7: Functions\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [6. Loops](https://colab.research.google.com/drive/1AZY4ESmsKKMvbalBDLlMrezAM5NzXXxV)\n","\n","### This module\n","\n","- Storing code in a variable so you can reuse it.\n","- Being explicit about the purpose of your code."],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## (Re)Introducing functions\n","\n","A function is a reusable piece of code, stored in a variable. You *call* a function by passing it a list of *arguments* between parentheses. The function *returns* a value, which you can then use in an expression or store in another variable. We have already seen several functions:"],"metadata":{"id":"mnc8HshNPLte"}},{"cell_type":"code","source":["result = ord('🎵')\n","print(type(result), result)\n","\n","result = len([1, 2, 3])\n","print(type(result), result)\n","\n","result = str(ord)\n","print(type(result), result)"],"metadata":{"id":"IP2mOWYgR-QA"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["The fact that functions are variables, is illustrated by the fact that you can store them in variables and even reassign them:"],"metadata":{"id":"u_YUDiccZKwh"}},{"cell_type":"code","source":["my_ord = ord\n","print(my_ord('a'))\n","ord = chr\n","print(ord(97))\n","\n","# don't do this with 'list'!!!!!\n","\n","# back to sanity!\n","ord = my_ord\n","\n","# this can also restore sanity\n","%reset_selective ord\n","\n","# reset resets everything\n","%reset\n","\n","ord('a')"],"metadata":{"id":"Mct6Hy3HZa5H"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["The list of arguments may be empty. For example, if you pass no arguments to `list`, it returns an empty list:"],"metadata":{"id":"hBgqVL7sSyFx"}},{"cell_type":"code","source":["result = list()\n","print(result)"],"metadata":{"id":"wb98z1kBS9tm"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["You can also pass multiple arguments (depending on the function)."],"metadata":{"id":"Byutz190TEH-"}},{"cell_type":"code","source":["result = max(3, 4, 5)\n","print(result)"],"metadata":{"id":"N7YW9_X_UOuB"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["A *named argument* or *keyword argument*, prefixed with `name=`, makes the purpose of the argument explicit. Below, the argument with the name `end` has the value `' '`."],"metadata":{"id":"H0SocqBbXQ6f"}},{"cell_type":"code","source":["print('one', end=' ')\n","print('two')"],"metadata":{"id":"uTk4InjdXg5g"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Arguments *without* a name are called *positional* arguments, because their roles are determined by the order in which they are supplied.\n","\n","In our example of `max(3, 4, 5)` above, `3`, `4`, and `5` are positional arugments. In this case, the order of the numbers does not actually matter (the maximum is the same, no matter what).\n","\n","However, for most functions, this is not the case! An example you have already seen is `range`: the first argument is the _start_ and the second argument is the _stop_."],"metadata":{"id":"dCUHGgepctcp"}},{"cell_type":"code","source":["assert max(3, 4, 5) is max(4, 3, 5)\n","\n","assert range(1, 5) is not range(5, 1)"],"metadata":{"id":"yCyPbsvAd5PB"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["A function may return \"nothing\", i.e., `None`."],"metadata":{"id":"ECGJttnRUX_J"}},{"cell_type":"code","source":["result = print('hello')\n","print(result)"],"metadata":{"id":"gAMO-QD4Uuxe"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["A function may even return multiple results, i.e., a tuple. We can *unpack* those directly into multiple variables, but we can also store the whole tuple in a single variable."],"metadata":{"id":"Bj4diwbcU1Q7"}},{"cell_type":"code","source":["my_tuple = tuple(['Jelte', 'Julian'])\n","result1, result2 = my_tuple\n","print(my_tuple)\n","print(result1)\n","print(result2)"],"metadata":{"id":"yYRQIGnoVHWA"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Some functions have *side effects*: apart from taking arguments and returning results, they also have some other external effect."],"metadata":{"id":"xMHYhvPhVXet"}},{"cell_type":"code","source":["result1 = input('Please enter PIN: ') # returns input from user\n","result2 = print(result1) # returns nothing\n","print(result2)\n","print(result1)"],"metadata":{"id":"OKEha-rwVo99"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Functions are awesome!\n","\n","The following code, which does *not* use enough functions, is **bad**:"],"metadata":{"id":"emAs76qOagVF"}},{"cell_type":"code","source":["print('\"banana\" has 6 characters and starts with a lowercase')\n","print('\"Ada\" has 3 characters and starts with an uppercase')\n","print('\"epigraph\" has 8 characters and starts with a lowercase')"],"metadata":{"id":"n0UOjklcbEHQ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Problems:\n","\n","- repetitive\n","- not explicit\n","- unmaintainable\n","\n","To some extent, we can address these problems with a loop:"],"metadata":{"id":"vAt_0PfecAGK"}},{"cell_type":"code","source":["words = ['banana', 'Ada', 'epigraph']\n","\n","for word in words:\n"," quoted = '\"' + word + '\"'\n"," length = len(word)\n"," first_character = word[0]\n"," if 'A' <= first_character <= 'Z':\n"," initial = 'an uppercase'\n"," else:\n"," initial = 'a lowercase'\n"," print(quoted, 'has', length, 'characters and starts with', initial)"],"metadata":{"id":"MeUnr3KNcaVZ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["BUT\n","\n","- still not explicit\n","- still repetitive, need to repeat the loop if I want to do this elsewhere"],"metadata":{"id":"FL0w8VMkeLm7"}},{"cell_type":"markdown","source":["Functions let us solve all problems!"],"metadata":{"id":"bBiz8La8jv81"}},{"cell_type":"code","source":["def describe(word):\n"," quoted = '\"' + word + '\"'\n"," length = str(len(word))\n"," first_character = word[0]\n"," if 'A' <= first_character <= 'Z':\n"," initial = 'an uppercase'\n"," else:\n"," initial = 'a lowercase'\n"," return quoted + ' has ' + length + ' characters and starts with ' + initial\n","\n","words = ['banana', 'Ada', 'epigraph']\n","\n","for word in words:\n"," print(describe(word))"],"metadata":{"id":"HOjpPJBNiSvr"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Basic function definitions\n","\n","At a minimum, you need the keyword `def`, a name, a pair of parentheses, a colon, and an indented block. The indented block is called the *function body*. It can contain anything!"],"metadata":{"id":"y77LwKKjk-2D"}},{"cell_type":"code","source":["# Defining the function with the name \"example\"\n","def example():\n"," pass # ah, that placeholder again\n","\n","# Calling the function with the name \"example\"\n","result = example()\n","print(result)"],"metadata":{"id":"Ph3RsaBbllvB"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Keep in mind that a function *definition* only stores the code of the function body inside a variable with the name of the function. The code **does not run** until you *call* the function."],"metadata":{"id":"6Esxqtn0y1Ai"}},{"cell_type":"code","source":["def example():\n"," # Don't call print inside a function!\n"," # We only do this here for demonstration purposes.\n"," print('Hello, world!')\n","\n","print(type(example), example)"],"metadata":{"id":"vBfiX0-WzWQg"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Between the parentheses, we list the *parameters*, the \"slots\" that can be filled by passing arguments when calling the function.\n","\n","The parameters (and any new variables that you make within the function body) have limited _scope_: they only live within the body of the function."],"metadata":{"id":"S3cY2mRgl9z8"}},{"cell_type":"code","source":["def example(name, age):\n"," print(name)\n"," print(age)\n","\n","print(name)\n","print(age)\n","\n","result = example('Julian', 35)\n","print(result)\n","\n","print(name)\n","print(age)"],"metadata":{"id":"fWAzMGqfnC8p"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["At the end of the function body, a function will implicitly return `None`. The `return` keyword lets you return a different value, return before the end of the body, or both. You can use the keyword multiple times, but **a function can return only once**, so an early return will skip the remainder of the function body."],"metadata":{"id":"J5Pd_TjZqnwj"}},{"cell_type":"code","source":["def heaviness(item, weight):\n"," if type(weight) not in (int, float):\n"," # early return, implicit None\n"," return\n"," if weight >= 5:\n"," # early return, different value\n"," return 'heavy'\n"," # final return, different value\n"," return 'light'\n","\n","result = heaviness('letter', 'paper weight')\n","print(result)\n","\n","result = heaviness('feather', 0.01)\n","print(result)\n","\n","result = heaviness('bowling ball', 8)\n","print(result)"],"metadata":{"id":"48ARWWmvrgjz"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Functions should **not** have side effects unless that is the very purpose of the function (like with `print` and `input`). Most functions should return a value rather than printing something to the screen!"],"metadata":{"id":"kOlF8tonzwZr"}},{"cell_type":"code","source":["# GOOD: function returns a value\n","def exclaim(text):\n"," return text + '!'\n","\n","value = exclaim('Julian')\n","print(value)\n","\n","# BAD: function prints to the screen\n","def exclaim(text):\n"," print(text + '!')\n","\n","value = exclaim('Julian')\n","print(value)\n","\n","# OK: function is intended as a special print wrapper\n","def fancy_print(text):\n"," print('>>>', text, '<<<')\n","\n","fancy_print('Julian')"],"metadata":{"id":"EHX1V-E71EkI"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["It is a good habit to start a function with a *documentation string*, **docstring** for short. A docstring should explain the parameters and possible return values of the function, as well as any rules or side effects that apply.\n","\n","A docstring should start with a short description of the function that fits on a single line. If there is more to explain, add the rest after a blank line.\n","\n","By convention, docstrings use three double quotes."],"metadata":{"id":"spLYBkqtvDmF"}},{"cell_type":"code","source":["def heaviness(item, weight):\n"," \"\"\"\n"," Given the name of an item and its weight in kg, classify its heaviness.\n","\n"," If the weight is not a number, it cannot be classified. Otherwise, the\n"," classification is returned as a string: either 'light' or 'heavy'.\n"," \"\"\"\n"," if type(weight) not in (int, float):\n"," return\n"," if weight >= 5:\n"," return 'heavy'\n"," return 'light'\n","\n","print(heaviness.__doc__)\n","\n","print(len.__doc__)\n","print(ord.__doc__)\n","print(print.__doc__)"],"metadata":{"id":"DR6t3PCCvSEX"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.1: functions"],"metadata":{"id":"aPFGhEVz40JP"}},{"cell_type":"markdown","source":["1. We have seen several standard functions during the course, such as `ord` and `len`. List as many as you can from memory. Try to list the types of the parameters and return values of each function as well. Do any of these functions have side effects?"],"metadata":{"id":"hfcz-cSEKZWW"}},{"cell_type":"markdown","source":["2. For exercise purposes, code in the following blocks may call `print` inside a function and omit a docstring. Predict the output, then run the code to see whether your prediction was right. Try to explain any discrepancies."],"metadata":{"id":"BUnMsiUzKbws"}},{"cell_type":"code","source":["def greet(name):\n"," return 'Hello, ' + name + '!'\n","\n","print(greet('Berit'))"],"metadata":{"id":"_3va9jT5O0H7"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["name = 'Luka'\n","\n","def exclaim(name):\n"," print(name + '!')"],"metadata":{"id":"vdTIwoGxM_JV"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def false():\n"," return True\n","\n","print(False)"],"metadata":{"id":"30fv8SAMOblV"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["length = 5\n","width = 2\n","\n","def calculate_area():\n"," area = length * width\n","\n","print(calculate_area())"],"metadata":{"id":"ongrNaZFNNmV"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def question(name):\n"," return 'Who is ' + name + '?'\n","\n","question('Jelte')"],"metadata":{"id":"MSkOCMMyNoUO"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def add(left, right):\n"," return left + right\n","\n","print(add('sweet', 'addition') * add(1, 1))"],"metadata":{"id":"72DDRhD5OQ0g"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["name = 'Julian'\n","age = 36\n","\n","print(name)\n","\n","def example(name):\n"," print(name)\n"," name = 'Berit'\n"," print(name)\n"," print(age)\n","\n","print(name)\n","print(example)\n","print(name)\n","example('Jelte')\n","print(name)\n","print(age)"],"metadata":{"id":"L0GlJecf8ntf"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. In each of the following code blocks, write a docstring for the function, then add assertions and run the block to check that your documentation is correct."],"metadata":{"id":"Rwvwlpp0-Hrt"}},{"cell_type":"code","source":["def odd(number):\n"," return number % 2 == 1"],"metadata":{"id":"ajcRnvzQQ9c5"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def magic(word):\n"," if not word or type(word) != str:\n"," return False\n"," if 'A' <= word[0] <= 'Z':\n"," return True\n"," return False"],"metadata":{"id":"giU_bIKrRME4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def join_commas(words):\n"," first, *rest = list(words)\n"," text = first\n"," for word in rest:\n"," text = text + ', ' + word\n"," return text"],"metadata":{"id":"pAChbRWn-SKS"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["4. Write a function `is_number` that takes one argument. If the argument is a number, it should return `True`; otherwise, it should return `False`. Make sure to include a docstring!"],"metadata":{"id":"mc9RtAeATiHw"}},{"cell_type":"code","source":["# Your definition of is_number here\n","\n","# The following lines will check your solution (no output is good)\n","assert is_number(0)\n","assert is_number(10)\n","assert is_number(0.5)\n","assert is_number(8 / 5)\n","assert not is_number(None)\n","assert not is_number('dear')\n","assert not is_number('123')"],"metadata":{"id":"Ap33-rF-UbsB"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.2: bonus"],"metadata":{"id":"apA7o120TYRl"}},{"cell_type":"markdown","source":["1. Write a function `last_a_index` that, given a string, returns the **last** index of the letter `'a'` in the string. If there is no `'a'` in the string, the function should return `None`."],"metadata":{"id":"nM43w3VlB3-O"}},{"cell_type":"code","source":["# Define last_a_index here\n","\n","assert last_a_index('banana') == 5\n","assert last_a_index('cherry') == None\n","assert last_a_index('Once upon a time, there was a dragon') == 32"],"metadata":{"id":"I5s4_a53ENJC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Write a function `replace` with three string arguments: `text`, `query` and `replacement`. It should return a copy of `text` in which all occurrences of `query` are replaced by `replacement`. For example, `replace('small', 'a', 'e')` should return `'smell'`. You may assume that `query` is always a single character. For an additional challenge, you can try to also handle multi-character query strings. For ultimate challenge, try to think of a way to handle the empty string!"],"metadata":{"id":"z4z3-dOaVROx"}},{"cell_type":"code","source":["# Define replace here\n","\n","assert replace('small', 'a', 'e') == 'smell'\n","assert replace('banana', 'a', 'o') == 'bonono'\n","assert replace('cherry', 'a', 'x') == 'cherry'"],"metadata":{"id":"kyQwfz-mYvfW"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Refining parameters and return values"],"metadata":{"id":"3Lx61L5B0Zqe"}},{"cell_type":"markdown","source":["### Returning multiple values (in a tuple)"],"metadata":{"id":"gRae5PaguhV9"}},{"cell_type":"code","source":["def word_statistics(word):\n"," \"\"\" Given a string, return its length and the case of its first letter. \"\"\"\n"," if 'A' <= word[0] <= 'Z':\n"," casing = 'upper'\n"," else:\n"," casing = 'lower'\n"," return len(word), casing\n","\n","size, initial = word_statistics('Jelte')\n","print(size)\n","print(initial)"],"metadata":{"id":"MJqHyAI31FLZ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Optional parameters\n","\n","Parameters can be made *optional* by using the notation `=None` in the parameter list."],"metadata":{"id":"1ORLASkU2Uga"}},{"cell_type":"code","source":["def emphasize(word, emphasis=None):\n"," \"\"\"\n"," Given a string, return a version with an exclamation mark appended.\n","\n"," The exclamation mark can be replaced by passing the override in a\n"," second argument.\n"," \"\"\"\n"," if emphasis == None:\n"," return word + '!'\n"," return word + emphasis\n","\n","print(emphasize('Julian'))\n","print(emphasize('Julian', '!!!'))"],"metadata":{"id":"IuDsXgrK3rK8"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Parameters with default values\n","\n","The notation `=None` is actually a special case. You can use any value as a default for a parameter. However, it is easy to make mistakes in this way. In case of doubt, just use `None` and add a check inside the function body, as demonstrated above."],"metadata":{"id":"2gPmuYUe1nyO"}},{"cell_type":"code","source":["# Literal strings, numbers and booleans are safe\n","def default_string(value='hello'):\n"," return value\n","\n","def default_int(value=10):\n"," return value\n","\n","def default_bool(value=True):\n"," return value\n","\n","# Do not use variables as default values!\n","name = 'Julian'\n","def default_name(value=name):\n"," return value\n","\n","name = 'Jelte'\n","print(default_name())\n","\n","# Do not use data structures as default values!\n","def append_list(container=[], value=1):\n"," container.append(value)\n"," return container\n","\n","print(append_list())\n","print(append_list())"],"metadata":{"id":"IqabfNzi2-XV"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Mixing positional and named arguments\n","\n","So far, we demonstrated functions where every parameter has its own unique name. With such parameters, the caller is free to choose between positional arguments and named arguments. The order of named arguments can be freely chosen, but they must come after all positional arguments."],"metadata":{"id":"_mTHAoog6glc"}},{"cell_type":"code","source":["def tax_rate(income, entrepeneur):\n"," \"\"\" Determine tax rate, given income and whether payer is entrepeneur. \"\"\"\n"," print(name, other_name)\n"," if entrepeneur:\n"," return 20\n"," first_bracket = min(income, 50000)\n"," second_bracket = income - first_bracket\n"," return (first_bracket * 30 + second_bracket * 40) / income\n","\n","print(tax_rate(40000, True))\n","print(tax_rate(40000, entrepeneur=True))\n","print(tax_rate(income=40000, entrepeneur=True))\n","print(tax_rate(entrepeneur=True, income=40000))\n","print(tax_rate(True, income=40000))\n","print(tax_rate(income=40000, True))"],"metadata":{"id":"ETGRDi8J7cyP"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Functions as first-class citizens\n","\n","As mentioned previously, a function is just a variable. That means you can do the same things with it as with other values. For example, you can pass a function as an argument to another function:"],"metadata":{"id":"1jWzKu5omWUV"}},{"cell_type":"code","source":["def exclaim(text):\n"," return text + '!'\n","\n","fruits = ['apricot', 'banana', 'cherry']\n","\n","exclaimed_fruits = map(exclaim, fruits)\n","\n","print(type(exclaimed_fruits), exclaimed_fruits)\n","\n","list(exclaimed_fruits)"],"metadata":{"id":"ukVglqcwsAdT"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["What is going on inside `map`? Something like this:"],"metadata":{"id":"l4dAFklEvdhZ"}},{"cell_type":"code","source":["def my_map(function, values):\n"," \"\"\" Repeat `function` for every value in `values`. \"\"\"\n"," for value in values:\n"," result = function(value)\n"," # there is an additional step that we will cover later"],"metadata":{"id":"V2-kY5O6xHRo"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Also, a function can define another function inside its body and then use and/or return it:"],"metadata":{"id":"TZXA2q46taZi"}},{"cell_type":"code","source":["def make_greeter(prefix, suffix):\n"," \"\"\" Create a function that greets a person with the given phrasing. \"\"\"\n"," def greeter(name):\n"," \"\"\" Wrap the given name in a greeting. \"\"\"\n"," return prefix + ', ' + name + suffix\n"," return greeter\n","\n","greet_british = make_greeter('How do you do', '?')\n","greet_american = make_greeter('Hi there', '!')\n","\n","print(greet_british('Mees'))\n","print(greet_british('Julian'))\n","print(greet_american('Mees'))\n","print(greet_american('Julian'))"],"metadata":{"id":"fG6-q8EatpRz"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.3: function tricks"],"metadata":{"id":"1xUD2ZNjcqEZ"}},{"cell_type":"markdown","source":["1. In each of the code blocks below, predict the output, check your prediction by running the code, and try to explain any surprises."],"metadata":{"id":"hxRC5Nx-cyM4"}},{"cell_type":"code","source":["def welcome(name=None):\n"," if name is None:\n"," return 'Welcome to my office. How can I help you?'\n"," return 'Please make yourself at home, ' + name + '!'\n","\n","print(welcome())\n","print(welcome('Mees'))"],"metadata":{"id":"HPxio0q6c-M9"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def table(number):\n"," return number, number * 2, number * 3\n","\n","first, second, third = table(5)\n","\n","print(third)"],"metadata":{"id":"NxXqK4ROdxva"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def contact(name, job):\n"," return 'For ' + job + ', contact ' + name + '.'\n","\n","contact_line = contact(job='naming', name='Job')\n","print(contact_line)"],"metadata":{"id":"EVCf3w9qfBCU"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def exclaim(name):\n"," return name + '!'\n","\n","def request(name):\n"," return name + '?'\n","\n","def tell(how):\n"," return 'As my mother would say: ' + how('Julian')\n","\n","print(tell(request))"],"metadata":{"id":"OUSpe-hPl6-G"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def make_enumerate(separator):\n"," def enumerate(items):\n"," if not len(items):\n"," return ''\n"," result = items[0]\n"," for item in items[1:]:\n"," result = result + separator + item\n"," return result\n"," return enumerate\n","\n","with_semicolon = make_enumerate('; ')\n","fruits = with_semicolon(['apricot', 'banana', 'cherry'])\n","print(fruits)"],"metadata":{"id":"uSN17qnvmoWv"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. In each of the following code blocks, something is missing in the function definition. Add the missing element."],"metadata":{"id":"CKma4p6Egkwb"}},{"cell_type":"code","source":["def combine(left, right):\n"," \"\"\" Compute the sum and the product of the arguments. \"\"\"\n"," sum = left + right\n"," product = left * right\n"," return product\n","\n","assert combine(2, 3) == (5, 6)"],"metadata":{"id":"SaygnjMygwNF"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def announce_time(hour, minute):\n"," \"\"\" Announce the time in a speaking clock manner. \"\"\"\n"," if minute < 10:\n"," minute = '0' + str(minute)\n"," time = str(hour) + ':' + str(minute)\n"," return 'At the next beep, the time will be ' + time + '. BEEP!'\n","\n","assert announce_time(12) == 'At the next beep, the time will be 12:00. BEEP!'"],"metadata":{"id":"GqIgTcG6hMuG"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def echo(value):\n"," print(value)\n"," return value\n","\n","assert echo('holiday') == 'holiday'"],"metadata":{"id":"nH77gJdOkS5b"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. In the following code block, write a function `month`, which returns a string name for given numeric month. Month `1` is `'January'` and month `12` is `December`. When no argument is passed, it should default to the current month. **Tip:** you can avoid writing a big `if`/`elif`/`else` tree by using a list of month names and using the month number as a list index."],"metadata":{"id":"YG5XrO1PoIJx"}},{"cell_type":"code","source":["# You may pretend that it is forever April\n","current_month = 4\n","\n","# Your definition of month here\n","\n","assert month(3) == 'March'\n","assert month(4) == 'April'\n","assert month(11) == 'November'\n","assert month() == 'April'"],"metadata":{"id":"TnuU_I0Tq9wQ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["4. In the following code block, write a function `weekday`, which is analogous to `month` in the previous exercise. Day `1` is `'Monday'` while day `0` and day `7` are both `'Sunday'`. Can you avoid writing the string `'Sunday'` twice in your code?"],"metadata":{"id":"WuRrElhUsD40"}},{"cell_type":"code","source":["# You may pretend it is forever Tuesday\n","current_weekday = 2\n","\n","# Your definition of weekday here\n","\n","assert weekday() == 'Tuesday'\n","assert weekday(0) == 'Sunday'\n","assert weekday(7) == 'Sunday'\n","assert weekday(4) == 'Thursday'"],"metadata":{"id":"WUGQqmJysrqS"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.4: bonus"],"metadata":{"id":"ZvfEq3NctoOo"}},{"cell_type":"markdown","source":["1. In exercises 7.3.4 and 7.3.5, where you just implemented `month` and `weekday`, your code was likely very similar. How could you implement both functions without repeating yourself? Check your solution with assertions."],"metadata":{"id":"8au2fNRutw8i"}},{"cell_type":"code","source":[],"metadata":{"id":"JFhOX_Z5uVfC"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Write a function `create_date_format`, which takes two arguments that determine how a date should be displayed. The first argument is function that transforms a weekday number to a string suitable for display, the second argument is a function that transforms a month number. Both arguments default to just displaying the number as-is. `create_date_format` returns a new function. The latter function takes any date defined by a year, month, day and weekday, and returns a string suitable for displaying that date as a whole."],"metadata":{"id":"Gx54DrgJuWKg"}},{"cell_type":"code","source":["# For this code block, you need to have `month` and `weekday`\n","# in your runtime from previous exercises.\n","\n","# Your definition of create_date_format here\n","\n","wordy_format = create_date_format(weekday, month)\n","cryptic_format = create_date_format()\n","\n","assert wordy_format(2023, 4, 11, 2) == 'Tuesday, April 11, 2023'\n","assert cryptic_format(2023, 4, 11, 2) == '2, 4 11, 2023'"],"metadata":{"id":"0KyXFHEWwZ45"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.5: ultimate FizzBuzz (more bonus)\n","\n","1. Write two functions `fizz(number)` and `buzz(number)`. If `number` is divisible by 3, `fizz` should return the string `'Fizz'`; otherwise, it should return the empty string `''`. `buzz` should work like `fizz`, but for divisibility by 5 and the string `'Buzz'`."],"metadata":{"id":"b-p6Ct5_0I-x"}},{"cell_type":"code","source":["# Your solution here\n","\n","for number in [1, 2, 4, 5, 7, 8, 10, 11, 13, 14]:\n"," assert fizz(number) == '', str(number) + ' is not divisible by 3'\n","for number in [3, 6, 9, 12, 15, 18, 21, 24, 27]:\n"," assert fizz(number) == 'Fizz', str(number) + ' is divisible by 3'\n","for number in [1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14]:\n"," assert buzz(number) == '', str(number) + ' is not divisible by 5'\n","for number in [5, 10, 15, 20, 25, 30, 35, 40]:\n"," assert buzz(number) == 'Buzz', str(number) + ' is divisible by 5'"],"metadata":{"id":"407dPPK966R9"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Using your functions `fizz` and `buzz` from step 1, write the function `fizzbuzz(number)`, which implements the well-known rules from before, but with a slight **twist**:\n"," - If the number is divisible by 3 and 5, return `'FizzBuzz'`.\n"," - If the number is divisible by 3 but not by 5, return `'Fizz'`.\n"," - If the number is divisible by 5 but not by 3, return `'Buzz'`.\n"," - In all other cases, return the number itself **as a string**."],"metadata":{"id":"QCKc52-r9DrX"}},{"cell_type":"code","source":["# Your solution here\n","\n","for number in [1, 2, 4, 7, 8, 11, 13, 14]:\n"," assert fizzbuzz(number) == str(number), str(number)\n","for number in [3, 6, 9, 12, 18, 21, 24, 27]:\n"," assert fizzbuzz(number) == 'Fizz', str(number)\n","for number in [5, 10, 20, 25, 35, 40]:\n"," assert fizzbuzz(number) == 'Buzz', str(number)\n","for number in [15, 30, 45, 60, 75]:\n"," assert fizzbuzz(number) == 'FizzBuzz', str(number)"],"metadata":{"id":"NFADyIW3-7qt"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. Write a function `chunk10(sequence)` that takes an iterable `sequence` and returns a list of lists: the first sublist contains the first ten elements of `sequence`, the second sublist contains the next ten elements of `sequence`, and so on. You may assume that the number of values in `sequence` is an exact multiple of 10."],"metadata":{"id":"o_3wq4agCCZH"}},{"cell_type":"code","source":["# Your solution here\n","\n","assert chunk10('Jelte!!!!!') == [list('Jelte!!!!!')]\n","assert chunk10('Hey Julian, let us have lunch!') == [\n"," list('Hey Julian'),\n"," list(', let us h'),\n"," list('ave lunch!'),\n","]\n","assert chunk10(range(20)) == [list(range(10)), list(range(10, 20))]"],"metadata":{"id":"4c0A4kMfDdvt"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["4. In step 1, you may have written definitions for `fizz` and `buzz` that look very similar to each other. Can you think of a way to avoid repeating the common elements?"],"metadata":{"id":"HBA4z4yVIhsn"}},{"cell_type":"code","source":["# Your solution here\n","\n","for number in [1, 2, 4, 5, 7, 8, 10, 11, 13, 14]:\n"," assert fizz(number) == '', str(number) + ' is not divisible by 3'\n","for number in [3, 6, 9, 12, 15, 18, 21, 24, 27]:\n"," assert fizz(number) == 'Fizz', str(number) + ' is divisible by 3'\n","for number in [1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14]:\n"," assert buzz(number) == '', str(number) + ' is not divisible by 5'\n","for number in [5, 10, 15, 20, 25, 30, 35, 40]:\n"," assert buzz(number) == 'Buzz', str(number) + ' is divisible by 5'"],"metadata":{"id":"5g4BRdpLJLIc"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["5. In exercise 7.1.3, you documented the function `join_commas`. We did not actually need to write that function, because it is built into Python, although it goes by the name `', '.join`. That notation also works with other strings, as we demonstrate below. We also remind you of `map`, which appeared in the lecture.

\n","Using these functions, as well as your own `fizzbuzz` from step 2 and your own `chunk10` from step 3, try to recreate (roughly) the same `FizzBuzz` output for the numbers 1 through 100 as in [exercise 6.2.4](https://colab.research.google.com/drive/1AZY4ESmsKKMvbalBDLlMrezAM5NzXXxV#scrollTo=uyqbuhKsUlhG), in as little code as you can."],"metadata":{"id":"BXzFYNGmPeO6"}},{"cell_type":"code","source":["# The following code is just for illustration.\n","# You do not need it in your solution.\n","fruits = ['apricot', 'banana', 'cherry']\n","print(', '.join(fruits))\n","print('\\n'.join(fruits))\n","numbers = list(range(10))\n","print(numbers)\n","strings = map(str, numbers)\n","print(list(strings))"],"metadata":{"id":"nDGUS26IMApD"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[8. Debugging](https://colab.research.google.com/drive/1yQskT6SyKvXtXewx5kCla2NOmasgP8Vi)"],"metadata":{"id":"Dntbbioh29xm"}}]} \ No newline at end of file diff --git a/lessons/07a Functions (extra exercises).ipynb b/lessons/07a Functions (extra exercises).ipynb new file mode 100644 index 0000000..241627f --- /dev/null +++ b/lessons/07a Functions (extra exercises).ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"authorship_tag":"ABX9TyMaLbZUxFMzVIjab/8j3smI"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# 7a - Functions (extra exercises)\n","\n","This notebook contains extra exercises to help you get more familiar with writing python code, and especially making functions. It contains no new theory.\n","\n","There are a lot of exercises, and they can be very similar. Don't feel like you have to do everything: if the exercises start to feel repetitive, you're ready to move on to the next section."],"metadata":{"id":"q2_7oxCuwonl"}},{"cell_type":"markdown","source":["## 1. Writing functions\n","\n","In these exercises, the instructions describe a function that you need to make. Each code block also has some assert statements that try to use your function, which you can use to verify your solution."],"metadata":{"id":"KoEzBrcFxk8T"}},{"cell_type":"markdown","source":["1.1: Write a function `first`, which returns the first item in a list. The function should take one argument (a list).\n","\n","If the list if empty, `first` should return `None`."],"metadata":{"id":"DxKNUR11yfvL"}},{"cell_type":"code","execution_count":null,"metadata":{"id":"YtJmU-K0woBC"},"outputs":[],"source":["# your code here...\n","\n","# check your function\n","assert first(['apple', 'banana', 'orange']) == 'apple'\n","assert first(['just one item']) == 'just one item'\n","assert first([]) == None"]},{"cell_type":"markdown","source":["1.2: Write a function `check_wallet` which takes a list of items as its argument. If the list includes `'wallet'`, it should return the list as-is. If it doesn't, it should add `'wallet'` to the end of list."],"metadata":{"id":"jgxg9ecn0GkZ"}},{"cell_type":"code","source":["# your code here...\n","\n","# check your function\n","assert check_wallet(['keys', 'wallet', 'phone', 'gloves']) == ['keys', 'wallet', 'phone', 'gloves']\n","assert check_wallet(['keys', 'phone']) == ['keys', 'phone', 'wallet']\n","assert check_wallet([]) == ['wallet']"],"metadata":{"id":"Z2Xa8C6z0BrI"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1.3: Write a function `round_to_10` which takes a number as its argument and returns a new number: the input rounded to the nearest multiple of 10."],"metadata":{"id":"Zx9RsFoY2o5M"}},{"cell_type":"code","source":["# your code here...\n","\n","# check your function\n","assert round_to_10(8) == 10\n","assert round_to_10(22.1) == 20\n","assert round_to_10(40) == 40\n","assert round_to_10(55) == 60"],"metadata":{"id":"Y8M_CCuCcVZm"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1.4: Let's make our rounding function a bit more generic. Make a new function `round_to_n` which takes two arguments: the number that you want to round, and the unit that you want to round to. `round_to_n(35, 50)` will round 35 to the nearest multiple of 50."],"metadata":{"id":"YKRA2X94dmfm"}},{"cell_type":"code","source":["# your code here\n","\n","\n","# check your function\n","assert round_to_n(8, 10) == 10\n","assert round_to_n(8, 20) == 0\n","assert round_to_n(24.3, 20) == 20"],"metadata":{"id":"CFukYZRFeMMr"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1.5: Write a function `in_alphabet` that takes a character (a string of length 1) as a parameter. It should return `True` if the character is one of the 26 letters in the latin alphabet. Uppercase and lowercase characters should both return `True`. Otherwise, the function should return `False`."],"metadata":{"id":"9C8cDTS3e62p"}},{"cell_type":"code","source":["# your code here\n","\n","# check your function\n","assert in_alphabet('a') == True\n","assert in_alphabet('f') == True\n","assert in_alphabet('A') == True\n","assert in_alphabet('1') == False\n","assert in_alphabet('✨') == False"],"metadata":{"id":"X9kXxwe3fD7P"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1.6: Use your function `in_alphabet` to write a new function `clean_text`. It should take one parameter, which is a string. It should return a new string, which is like the old one but leaves out any characters that are not in the latin alphabet or the space `' '`."],"metadata":{"id":"lXc43yNgicoA"}},{"cell_type":"code","source":["# your code here...\n","\n","# check your function\n","assert clean_text('Hello, how are you?') == 'Hello how are you'\n","assert clean_text('Hooray! Hooray! Hooray!') == 'Hooray Hooray Hooray'\n","assert clean_text('Yummy!! 😋') == 'Yummy '"],"metadata":{"id":"YOqKnf7rjpvW"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1.7: Write a function `travel_time` that estimates the travel time for a journey. It takes 3 named arguments:\n","- `car`: the distance traversed by car\n","- `bike`: the distance traversed by bike\n","- `walk`: the distance traversed on foot\n","\n","Each of these will be a number (distance in km), and the default value is `0`. Calculate the travel time, assuming that:\n","\n","- Cars have an average speed of 80 km/h\n","- Bikes have an average speed of 16 km/h\n","- Walking has an average speed of 4 km/h\n","\n","Your function should return the travel time in hours."],"metadata":{"id":"mzKQAJxNLUgV"}},{"cell_type":"code","source":["# your code here...\n","\n","# check your function\n","assert travel_time(car=10, walk=0.1) == 0.15\n","assert travel_time(bike=10, walk=0.1) == 0.65\n","assert travel_time(car=55, bike=3, walk=0.3) == 0.95"],"metadata":{"id":"XDVlkfHyMIfE"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1.8: Write a function `to_time` which takes a decimal number of hours (like the output of `travel time`) and converts it to hours, minutes, and seconds. For example, 1.5 hours is 1 hours, 30 minutes and 0 seconds.\n","\n","The input should be a single `float` or `int`, and the output should be three numbers: hours, minutes, and seconds. The output should be given in whole numbers (`int`, not `float`)."],"metadata":{"id":"SQHPePrYxdnG"}},{"cell_type":"code","source":["# your code here...\n","\n","# check your function\n","assert to_time(1.5) == (1, 30, 0)\n","assert to_time(3.6532) == (3, 39, 55)\n","assert to_time(0) == (0, 0, 0)"],"metadata":{"id":"5cdwImkNUGcc"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1.9: Write a function `mean` which takes one argument, a list of numbers, as input. It should return the mean value of the list (a single number)."],"metadata":{"id":"shtLjnOGxen9"}},{"cell_type":"code","source":["# your code here...\n","\n","# check your function\n","assert mean([1, 2, 7 , 2]) == 3.0\n","assert mean([3.2, 4.5, 0.0, 2.5]) == 2.55\n","assert mean([0.0]) == 0.0"],"metadata":{"id":"xJ_XTebzxfCs"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["1.10: Write a function `is_number` that checks if a string describes a number. It takes one argument (a string).\n","\n","It should return `True` if:\n","- Every character in the string is either a digit (0-9) or a decimal point `'.'`)\n","- If there is a decimal point, it should not be more than one.\n","\n","Otherwise, the function should return `False`."],"metadata":{"id":"p1NF-Tbpxfs1"}},{"cell_type":"code","source":["# your code here...\n"," \n","# check your function.\n","assert is_number('12') == True\n","assert is_number('0.5') == True\n","assert is_number('two') == False\n","assert is_number('1.2.3') == False"],"metadata":{"id":"LsA_B5iPxgEE"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## 2. Writing `assert` checks\n","\n","The code blocks below contain a function definition, but are missing some `assert` statements to check if everything works. Read the docstring and try to think of some assertions you could use to check the function.\n","\n","Not all of these functions work as intended! For some functions, you should be able to find assert statements that should succeed, but fail.\n","\n","You do not have to correct the functions (but you can if you want to)."],"metadata":{"id":"o55Hp9SomntG"}},{"cell_type":"code","source":["def distance(a, b):\n"," '''\n"," Gives the distance between two numbers.\n","\n"," Distance is absolute, i.e. always positive.\n"," '''\n","\n"," if a <= b:\n"," return b - a\n"," else:\n"," return a - b\n","\n","# write some checks!"],"metadata":{"id":"aqngxSucow39"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def reverse(word):\n"," '''\n"," Reverses a string\n","\n"," Input must be a string. Output is the same string in reverse order.\n"," '''\n","\n"," new_word = ''\n","\n"," for character in word:\n"," new_word = character + new_word\n"," \n"," return new_word\n","\n","# write some checks!"],"metadata":{"id":"khwUSdMWn1CR"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def exclude_short_words(words, min_length=5):\n"," '''\n"," Filters all short words (shorter than min_length) out of a list\n","\n"," Input should be a list of words (strings). Returns a new list\n"," with only the words longer than min_length.\n"," '''\n","\n"," long_words = []\n","\n"," for word in words:\n"," if len(word) < 5:\n"," long_words.append(word)\n"," \n"," return long_words\n","\n","# write some checks!"],"metadata":{"id":"nkpyPnDgoxKf"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def every_third_item(items):\n"," '''\n"," Returns every third item in a list.\n","\n"," Input should be a list, the output is a new list. Always returns the first\n"," item - after that, returns every third item.\n"," '''\n","\n"," result = []\n","\n"," for index in range(0, len(items), 3):\n"," result.append(items[index])\n"," \n"," return result\n","\n","# write some checks!"],"metadata":{"id":"yQ_-_xnuoyZ9"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def grade(score):\n"," '''\n"," Gives a letter grade (F, D, C, B, A) based on a score from 0-100.\n","\n"," Scores over 60 get grade D, scores over 70 get grade C, etc.\n"," '''\n"," if score >= 60:\n"," return 'D'\n"," elif score >= 70:\n"," return 'C'\n"," elif score >= 80:\n"," return 'B'\n"," elif score >= 90:\n"," return 'A'\n"," else:\n"," return 'F'\n","\n","# write some checks!"],"metadata":{"id":"ArwDSoguox2j"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["def is_prime(number):\n"," '''\n"," Checks if a int is a prime number.\n","\n"," Prime numbers are numbers that are NOT the product\n"," of two smaller numbers (2, 3, 5, 7, 11, are prime numbers)\n"," '''\n","\n"," for smaller_number in range(2, number):\n"," if number % smaller_number == 0:\n"," return False\n","\n"," return True \n","\n","# write some checks!"],"metadata":{"id":"hMIpfW_lMK0l"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## 3. Writing functions with checks\n","\n","For the functions in section 1, we provided some assert statements, but when you write your own programs, you usually don't have those. Instead, you have _something you want to do_, and it is up to you to make your own `assert` checks.\n","\n","For the exercises below, we describe what your function should do. It is up to you to make both the function and the assert statements.\n","\n","For each exercise, consider the following:\n","\n","- What should the function be callled?\n","- What are the input parameters? What type should they be?\n","- What is the output? What type should the output be?\n","- What are some checks you could write?\n","- What should be in the body of the function? How does it work?"],"metadata":{"id":"aKgZVXZXoF3g"}},{"cell_type":"markdown","source":["3.1: Write a function that turns a sentence into a question. The input should be a string. If the last character in the string is a `.` or `!`, it should be replaced with a `?`. Otherwise, we just want to add `?` to the end of the string (without replacing anything)."],"metadata":{"id":"EXgk0_mjoukf"}},{"cell_type":"code","source":[],"metadata":{"id":"ExH64Sbgovw0"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3.2: Write a function that takes a year as input and tells you whether or not that year is a leap year.\n","\n","From [wikipedia](https://en.wikipedia.org/wiki/Leap_year):\n","\n","> Every year that is exactly divisible by four is a leap year, except for years that are exactly divisible by 100, but these centurial years are leap years if they are exactly divisible by 400. For example, the years 1700, 1800, and 1900 are not leap years, but the years 1600 and 2000 are."],"metadata":{"id":"uA4PQxchxUrT"}},{"cell_type":"code","source":[],"metadata":{"id":"VIYiW1OCxVEo"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3.3: Write a function to calculate the area of a circle based on the diameter.\n","\n","- The _area_ is equal the _radius_ of the circle, squared, multiplied by pi. In a formula: $A = r^2 \\times \\pi$. \n","- The radius of a circle is half its diameter.\n","- You can assume that pi is equal to 3.14"],"metadata":{"id":"QzewFsCJomVB"}},{"cell_type":"code","source":[],"metadata":{"id":"oCID8txRotb-"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3.4: We want to calculate prices for an online store. Prices are calculated as follows:\n","- An order will include one or more items, each with their own price. You can just represent the order as a list of prices, e.g. `[15.00, 4.40, 31.50]`\n","- Customers may have a coupon that gives them 10% off all the items in their basket.\n","- If the total of the order (including the coupon discount) is under € 20.00, customers need to pay € 2.00 shipping.\n","\n","Write a function that calculates the total of an order."],"metadata":{"id":"SoO0C4pyxSjO"}},{"cell_type":"code","source":[],"metadata":{"id":"ddWh7EWCxS6M"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3.5: Write a function that counts how often a string occurs within another string."],"metadata":{"id":"m1bBl0RvxXe-"}},{"cell_type":"code","source":[],"metadata":{"id":"GKRKIpKgxXwV"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## 4. Don't repeat yourself\n","\n","An important use for functions is to avoid unnecessary repetition in code. When you write two pieces of very similar code, it's often convenient to make a single function.\n","\n","Each of the code blocks below contains two things:\n","- A section of code that has some repetition\n","- Some assert statements that check if the code works as intended.\n","\n","For each block:\n","- Try to understand what the code does, and identify the repetition.\n","- At the top of the code block, add a definition for a function (or several), that can handle the shared functionality.\n","- Use your functions(s) in the code, and check that everything still works."],"metadata":{"id":"NPXFJd95o3Ei"}},{"cell_type":"code","source":["small_pizza_price = 9.00\n","small_pizza_slices = 6\n","\n","small_pizza_price_per_slice = small_pizza_price / small_pizza_slices\n","print('The small pizza costs €', small_pizza_price_per_slice, 'per slice')\n","\n","medium_pizza_price = 12.00\n","medium_pizza_slices = 8\n","\n","medium_pizza_price_per_slice = medium_pizza_price / medium_pizza_slices\n","print('The medium pizza costs €', medium_pizza_price_per_slice, 'per slice')\n","\n","large_pizza_price = 16.00\n","large_pizza_slices = 8\n","\n","large_pizza_price_per_slice = large_pizza_price / large_pizza_slices\n","print('The large pizza costs €', large_pizza_price_per_slice, 'per slice')\n","\n","# check if everything works\n","assert small_pizza_price_per_slice == 1.5\n","assert medium_pizza_price_per_slice == 1.5\n","assert large_pizza_price_per_slice == 2.0"],"metadata":{"id":"JFc_E5sF5rt1"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["fruit_basket = ['apple', 'banana', 'banana', 'banana', 'apple', 'orange',\n"," 'orange', 'grape', 'grape', 'grape', 'grape', 'grape', 'grape',\n"," 'grape', 'grape', 'grape', 'pear', 'apple', 'strawberry',\n"," 'strawberry', 'strawberry', 'orange']\n","\n","apples = 0\n","for fruit in fruit_basket:\n"," if fruit == 'apple':\n"," apples += 1\n","\n","oranges = 0\n","for fruit in fruit_basket:\n"," if fruit == 'orange':\n"," oranges += 1\n","\n","apples_to_oranges = apples / oranges\n","\n","# check if everything works\n","assert apples_to_oranges == 1"],"metadata":{"id":"lirYtOcWpJ6m"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["weather_this_month = ['rain', 'rain', 'sun', 'sun', 'cloudy', 'cloudy', 'rain',\n"," 'cloudy', 'rain', 'rain', 'cloudy', 'sun', 'cloudy', 'sun', 'sun', 'sun',\n"," 'rain', 'cloudy', 'cloudy', 'sun', 'cloudy', 'rain', 'rain', 'cloudy',\n"," 'cloudy', 'cloudy', 'sun', 'cloudy', 'sun', 'sun']\n","\n","rain_followed_by_sun = 0\n","rain_followed_by_cloudy = 0\n","rain_followed_by_rain = 0\n","\n","for index, weather in enumerate(weather_this_month):\n"," not_last = index < len(weather_this_month) - 1\n"," if weather == 'rain' and not_last:\n"," weather_next_day = weather_this_month[index + 1]\n"," if weather_next_day == 'sun':\n"," rain_followed_by_sun += 1\n"," elif weather_next_day == 'cloudy':\n"," rain_followed_by_cloudy += 1\n"," else:\n"," rain_followed_by_rain += 1\n","\n","print('Days with rain were followed by:')\n","print('Sun:', rain_followed_by_sun, 'times')\n","print('Clouds:', rain_followed_by_cloudy, 'times')\n","print('Rain:', rain_followed_by_rain, 'times')\n","print()\n","\n","sun_followed_by_sun = 0\n","sun_followed_by_cloudy = 0\n","sun_followed_by_rain = 0\n","\n","for index, weather in enumerate(weather_this_month):\n"," not_last = index < len(weather_this_month) - 1\n"," if weather == 'sun' and not_last:\n"," weather_next_day = weather_this_month[index + 1]\n"," if weather_next_day == 'sun':\n"," sun_followed_by_sun += 1\n"," elif weather_next_day == 'cloudy':\n"," sun_followed_by_cloudy += 1\n"," else:\n"," sun_followed_by_rain += 1\n","\n","print('Days with sun were followed by:')\n","print('Sun:', sun_followed_by_sun, 'times')\n","print('Clouds:', sun_followed_by_cloudy, 'times')\n","print('Rain:', sun_followed_by_rain, 'times')\n","print()\n","\n","sun_preceded_by_sun = 0\n","sun_preceded_by_cloudy = 0\n","sun_preceded_by_rain = 0\n","\n","\n","for index, weather in enumerate(weather_this_month):\n"," not_first = index > 0\n"," if weather == 'sun' and not_first:\n"," weather_prev_day = weather_this_month[index - 1]\n"," if weather_prev_day == 'sun':\n"," sun_preceded_by_sun += 1\n"," elif weather_prev_day == 'cloudy':\n"," sun_preceded_by_cloudy += 1\n"," else:\n"," sun_preceded_by_rain += 1\n","\n","print('Days with sun were preceded by:')\n","print('Sun:', sun_preceded_by_sun, 'times')\n","print('Clouds:', sun_preceded_by_cloudy, 'times')\n","print('Rain:', sun_preceded_by_rain, 'times')\n","print()\n","\n","# check if everything works\n","assert rain_followed_by_sun == 1\n","assert rain_followed_by_cloudy == 4\n","assert rain_followed_by_rain\n","\n","assert sun_followed_by_sun == 4\n","assert sun_followed_by_cloudy == 4\n","assert sun_followed_by_rain == 1\n","\n","assert sun_preceded_by_sun == 4\n","assert sun_preceded_by_cloudy == 5\n","assert sun_preceded_by_rain == 1\n"],"metadata":{"id":"mdNug4ct5645"},"execution_count":null,"outputs":[]}]} \ No newline at end of file diff --git a/lessons/08 debugging.ipynb b/lessons/08 debugging.ipynb new file mode 100644 index 0000000..c4d86b2 --- /dev/null +++ b/lessons/08 debugging.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 8: Debugging\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [7. Functions](https://colab.research.google.com/drive/1APhegD_KpLRFn5bC6Ater2wFpT8_Opfr)\n","\n","### This module\n","\n","- How to see exactly what is going on in your program.\n","- Using this to solve problems with code."],"metadata":{"id":"fBBVyNmi8Fo0"}},{"cell_type":"markdown","source":["## Stepping with the debugger\n","\n","The following \"magic line\", which you can insert anywhere in your code (preferably inside a function), will create a *breakpoint*:\n","\n","```py\n","import pdb; pdb.set_trace()\n","```\n","\n","> ⚠️ In notebooks, you *need* to put the breakpoint inside a function. Standalone Python also allows them outside of functions.\n","\n","> 💡 There exist other ways to set breakpoints, some of which look less like magic. The one shown here works in all situations.\n","\n","When Python encounters a breakpoint, it pauses execution of the program and hands control to you. You \"enter the debugger\". This enables you to see what is going on inside the program. Some useful commands to remember:\n","\n","- `l` or `list`: show the code around the current line.\n","- `p ` or `print `: show the value of the variable with the given ``.\n","- `pp `: *pretty* print a value (nice for long strings and for data structures).\n","- `n` or `next`: execute the current line and stop at the next line.\n","- `s` or `step`: step into the next function call and stop at its first line.\n","- `r` or `return`: finish executing the current function and stop at the line after its call.\n","- `c` or `cont` or `continue`: resume the program until the next breakpoint, or until the end.\n","- `help`: show the list with available commands.\n","\n","Demonstration below!"],"metadata":{"id":"y0FX-JxubjAb"}},{"cell_type":"code","source":["def scream(name):\n"," \"\"\" Using at least one bang (!), make `name` at least 10 chars long. \"\"\"\n"," # import pdb; pdb.set_trace()\n"," name = name + '!'\n"," while len(name) < 10:\n"," name = name + '!'\n"," return name\n","\n","name = 'Julian'\n","exclamation = scream(name)\n","print(exclamation)"],"metadata":{"id":"rDx9b5MJhR7X"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 8.1: Debugging"],"metadata":{"id":"V5a4AtnAAMc2"}},{"cell_type":"markdown","source":["### 1. Building muscle memory\n","\n","In the definition of `scream` above, uncomment the breakpoint and step through the code. Make the debugger print two different values of `name`, then allow it to complete the program until the end."],"metadata":{"id":"5fI43xswHUXJ"}},{"cell_type":"markdown","source":["### 2. Known bugs\n","\n","Each of the code blocks below has a function, a `print` statement and an assertion. The assertion should pass, but it fails because of a bug in the function. For each code block, take the following steps:\n","\n","1. Read the code. Can you predict what will be printed and why the assertion will fail?\n","2. Run the code. Are you surprised? Can you explain the result?\n","3. Uncomment the breakpoint. Step through the code and make very sure that you understand what is going wrong.\n","4. Fix the broken function and check that the assertion now passes."],"metadata":{"id":"6OXyDh8tASN_"}},{"cell_type":"code","source":["def echo(word):\n"," \"\"\" Make the given word sound like an echo. \"\"\"\n"," # import pdb; pdb.set_trace()\n"," repeated = word + ',' + word\n"," tail_off = repeated + '...'\n"," return tail_off\n","\n","my_echo = echo('Mees')\n","print(my_echo)\n","assert my_echo == 'Mees, Mees...'"],"metadata":{"id":"Z_oXfbLeI6mK"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# Remember that letters have a numeric ordinal?\n","# We can use these to convert a lowercase to\n","# uppercase and vice versa!\n","uppercase_offset = ord('A') - ord('a')\n","\n","def uppercase(lowercase_letter):\n"," \"\"\" Convert a lowercase letter to uppercase. \"\"\"\n"," # import pdb; pdb.set_trace()\n"," lowercase_ordinal = ord(lowercase_letter)\n"," uppercase_ordinal = lowercase_ordinal - uppercase_offset\n"," uppercase_letter = chr(uppercase_ordinal)\n"," return uppercase_letter\n","\n","upper_a = uppercase('a')\n","print(upper_a)\n","assert upper_a == 'A'"],"metadata":{"id":"mxcdaX6SNFdl"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### 3. Unknown bugs\n","\n","Like in the previous exercises, the following code blocks have a function with a bug and an assertion. However, the assertion passes, because it does not demonstrate the bug. For each code block, take the following steps:\n","\n","1. Run the code and see for yourself that the assertion passes.\n","2. Read the code. Do you have any suspicion of what might be wrong? Do not change the code yet.\n","3. Add more assertions until you discover one that should pass, but doesn't. If you had a suspicion in step 2, try to confirm it with your new assertions. If you had no suspicion yet (or if you cannot comfirm it), it is also fine to \"blind guess\".\n","4. Once you have found an assertion that fails, comment out all other assertions, so only the problematic one will run.\n","5. By your own judgment, insert a breakpoint in the code that should help you to diagnose the bug. Step through the code with the debugger until you fully understand the bug.\n","6. Outcomment your breakpoint and fix the bug. **Tip:** you may reuse code from previous exercises, if you think this would be useful.\n","7. Uncomment all assertions that you previously outcommented, so that all assertions are checked when you run the code block.\n","8. Run the code block and verify that your fixed version of the function passes all the assertions."],"metadata":{"id":"CqsSkFb_H7Sk"}},{"cell_type":"code","source":["# Python has a built-in function for reversing strings,\n","# so normally you would not need to write it yourself.\n","\n","def reverse_string(text):\n"," \"\"\" Given any string, return a reversed copy. \"\"\"\n"," reversed = text[0]\n"," for next_letter in text[1:]:\n"," reversed = next_letter + reversed\n"," return reversed\n","\n","assert reverse_string('abc') == 'cba'\n"],"metadata":{"id":"6Nm0bcBINyNk"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["vowels = 'aeiouy'\n","\n","def count_vowels(text):\n"," \"\"\" Given any string, return the number of vowels. \"\"\"\n"," count = 0\n"," for character in text:\n"," if character in vowels:\n"," count = count + 1\n"," return count\n","\n","assert count_vowels('The quick fox jumps over the lazy dog.') == 11"],"metadata":{"id":"vooRS00TQNSP"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 8.2: Bonus"],"metadata":{"id":"O0Piet3Y-T6B"}},{"cell_type":"markdown","source":["### 1. Gnome sort\n","\n","Gnome sort is possibly the simplest way to sort a list. It can be understood by imagining that a gnome (indicated below by the `^`) is standing next to the list.\n","\n","```\n","-------------\n","| 2 | 3 | 1 |\n","-------------\n"," ^\n","```\n","\n","The gnome looks at the element closest to herself, as well as at the element to the right of it (here `2` and `3`). When those elements are already sorted, the gnome walks one element to the right and looks again:\n","\n","```\n","-------------\n","| 2 | 3 | 1 |\n","-------------\n"," ^\n","```\n","\n","When the current element and the one right of it are *not* sorted, like here, the gnome swaps those elements and walks one place to the left:\n","\n","```\n","-------------\n","| 2 | 1 | 3 |\n","-------------\n"," ^\n","```\n","\n","The gnome continues doing this, taking care not to walk off the left edge of the list:\n","\n","```\n","-------------\n","| 1 | 2 | 3 |\n","-------------\n"," ^\n","```\n","\n","```\n","-------------\n","| 1 | 2 | 3 |\n","-------------\n"," ^\n","```\n","\n","```\n","-------------\n","| 1 | 2 | 3 |\n","-------------\n"," ^\n","```\n","\n","When there is no more element to the right, the gnome stops. If we make sure to start the gnome at the leftmost element of the list, this will sort the entire list.\n","\n","Below, we implemented gnome sort in Python, but we made one mistake. The program never finishes. Step with the debugger to find the mistake.\n","\n","> ⚠️ If you need to sort something \"for real\", Python has ready-to-use solutions, so you do not normally need to write your own sorting code!"],"metadata":{"id":"833NNleFrsro"}},{"cell_type":"code","source":["shuffled = ['banana', 'apricot', 'date', 'cherry', 'date']\n","alphabetical = ['apricot', 'banana', 'cherry', 'date', 'date']\n","\n","def gnome_sort(items):\n"," \"\"\" Sort `items` by changing the list in place. Not efficient. \"\"\"\n"," stop = len(items) - 1\n"," index = 0\n"," while index < stop:\n"," here = items[index]\n"," right = items[index + 1]\n"," if here < right:\n"," index = index + 1\n"," else:\n"," items[index:(index + 2)] = [right, here]\n"," index = max(0, index - 1)\n","\n","gnome_sort(shuffled)\n","\n","print(shuffled)\n","assert shuffled == alphabetical"],"metadata":{"id":"TcfxzJ_Bn971"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### 2. Debugging your own algorithm\n","\n","Write a completely new function (or multiple) that does something useful. For inspiration, here are some suggestions:\n","\n","- Compute the average word length in a text.\n","- Given a string, return `True` if it is a palindrome and `False` otherwise. A palindrome is a string that reads the same if you reverse it. For example, `'abcba'` and `'ab cc ba'` are palindromes, `'abcabc'` is not.\n","- In a list of strings, find the first one that does not contain the word `'the'`.\n","\n","If you feel these examples are too complicated, a simpler algorithm is also fine.\n","\n","Once you have written your function(s), add multiple assertions to check that your code works as you intended. Run your code and see whether you have any failing assertions.\n","\n","If all of your assertions pass, try adding more assertions and see whether you can still find a bug. It is very uncommon for new code to work correctly on the first try! If it seems you have written perfect code on the first try, give yourself a pat on the shoulder, then pick a more complicated algorithm. You need to create code with a bug!\n","\n","Once you have written code with a failing assertion, step with the debugger to understand why the assertion is failing. Fix the bug only after you fully understand the cause. Finally, check that all your assertions pass after the fix. If you still have failing assertions, step with the debugger again. Repeat until all assertions pass."],"metadata":{"id":"bDpSj4jmTe-G"}},{"cell_type":"code","source":["# maybe some test data here\n","\n","# your own function(s) here\n","\n","# your own assertions here"],"metadata":{"id":"TjsG6HmVanqq"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[9. String manipulation](https://colab.research.google.com/drive/1Z7NNMxqHTSMoUadH3pVL6Bg6oii4qUoQ)"],"metadata":{"id":"QBPQVbY_aoLt"}}]} \ No newline at end of file diff --git a/lessons/09 string manipulation.ipynb b/lessons/09 string manipulation.ipynb new file mode 100644 index 0000000..4cda023 --- /dev/null +++ b/lessons/09 string manipulation.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 9: String manipulation\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [8. Debugging](https://colab.research.google.com/drive/1yQskT6SyKvXtXewx5kCla2NOmasgP8Vi)\n","\n","### This module\n","\n","- String utilities\n","- Formatting strings"],"metadata":{"id":"7_SeGArbg7Ou"}},{"cell_type":"markdown","source":["## String utilities\n","Python provides functions for common string operations. When working with text, these are very useful. Try to learn them by heart!"],"metadata":{"id":"oadzHVRYh1PN"}},{"cell_type":"markdown","source":["### Counting characters\n","\n","Strings are *iterables*, just like lists. We can use this information to quickly give us the length (number of characters) of a string:\n","`len(string)`"],"metadata":{"id":"3KZGnQuWiM1X"}},{"cell_type":"code","source":["print(len('Matilda'))\n","print(len('The Catcher in the Rye'))"],"metadata":{"id":"u-gFos5wii5k"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Check for substrings\n","Again wielding the knowledge about strings being *iterables*, we can use the `in` keyword to check if some sequence occurs in the string:\n","`substring in string`"],"metadata":{"id":"r0ZiGq36ipEo"}},{"cell_type":"code","source":["print('a' in 'Matilda')\n","print('til' in 'Matilda')\n","print('in' in 'The Catcher in the Rye')"],"metadata":{"id":"yOOOzh3WjCGc"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Casing\n","Convert a string to lowercase or uppercase:\n","\n","`string.lower()` and `string.upper()`"],"metadata":{"id":"A4Wfxuj_jRAW"}},{"cell_type":"code","source":["print('Matilda'.upper())\n","print('The Catcher in the Rye'.lower())"],"metadata":{"id":"uErzYzBHjbND"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Replacement\n","Replace certain sequences with another sequence:\n","\n","`string.replace(replacement)`"],"metadata":{"id":"AsVvV-dtjxSD"}},{"cell_type":"code","source":["catcher = 'The Catcher in the Rye'\n","replaced = catcher.replace('e', '3')\n","print(replaced)\n","\n","# optional parameter 'count'\n","replaced_max = catcher.replace('e', '3', 1)\n","print(replaced_max)"],"metadata":{"id":"2iIwX0phj4Wt"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Converting to list\n","There are two ways to convert a string into a list:\n","- `list(string)`\n","- `string.split(separator)`\n","\n","The latter is more flexible, because it allows you to choose on which character the string should be split."],"metadata":{"id":"OQ07Frl4j_H_"}},{"cell_type":"code","source":["catcher = 'The Catcher in the Rye'\n","tabbed_catcher = catcher.replace(' ', '\\t') # here we replace spaces by the tab character\n","sentence = 'This is some sentence that we wish to split into words.'\n","\n","# use list()\n","print(list(catcher))\n","\n","# using string.split()\n","# default: split on any whitespace\n","print(catcher.split())\n","print(tabbed_catcher.split())\n","print(sentence.split())\n","\n","# optional parameter: separator\n","list_string = 'jelte,julian,berit'\n","print(list_string.split(','))\n","\n","# any separator works, separator is not included in the result:\n","print(list_string.split('e'))"],"metadata":{"id":"xtsuwTrikrpk"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Join an iterable into a string\n","The reverse of splitting is ofcourse also possible: take each element of an *iterable* (such as a list), and glue them together into a string. You can choose which character to put between each element:\n","\n","`string.join(iterable)`"],"metadata":{"id":"UM5FtDPBlBGx"}},{"cell_type":"code","source":["words = ['The', 'Catcher', 'in', 'the', 'Rye']\n","\n","# choose a string that should be put between the words\n","print(' '.join(words))\n","print(','.join(words))\n","print(''.join(words))\n","\n"],"metadata":{"id":"CqxglgPOlDfe"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# split and join are opposites\n","sep = ' '\n","title = 'The Catcher in the Rye'\n","split_title = title.split(sep)\n","join_title = sep.join(split_title)\n","assert join_title == title"],"metadata":{"id":"z7p9kwjBlakE"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 9.1: String utilities\n","In each of the code blocks below, try to predict what will be printed, then run the code. If your guess was incorrect, try to figure out why the result is different. If your guess was correct, celebrate!"],"metadata":{"id":"5hIj-tbVleEq"}},{"cell_type":"code","source":["print(len('two'))"],"metadata":{"id":"02q-FgvVlxEj"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print(len(''))"],"metadata":{"id":"cvCrnnn9l-oH"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["assert 'A' in 'Matilda'"],"metadata":{"id":"UlWWF0k7mA62"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["assert 'A' in 'Matilda'.upper()"],"metadata":{"id":"Ui3gmvCNmHfB"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["name = 'Matilda'\n","assert name.upper() == 'MATILDA'"],"metadata":{"id":"1tDEnzrumNdO"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["name = 'Matilda'\n","assert name.upper().lower() == 'Matilda'"],"metadata":{"id":"BUpf6LglmZ4n"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('Matilda'.replace('ilda', 'ild4'))"],"metadata":{"id":"sgfEH2jImlwz"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('Matilda'.replace('a', 4))"],"metadata":{"id":"BEE94VVBmf7T"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["list_of_words = ['I', 'ate', 'a', 'banana']\n","sentence = 'I ate a banana'\n","\n","assert sentence.split() == list_of_words"],"metadata":{"id":"BVKc0bQAnGYq"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["list_of_words = ['I', 'ate', 'a', 'banana']\n","sentence = 'I ate a banana'\n","\n","assert ''.join(list_of_words) == sentence"],"metadata":{"id":"R4U_8kVtmpHE"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 9.2: Additional utilities\n","For each of the string functions below, find out what they do. If they take any parameters, describe what these do:\n","- `string.startswith()`\n","- `string.endswith()`\n","- `string.strip()`\n","- `string.lstrip()`\n","- `string.rstrip()`\n","- `string.title()`\n","- `string.find()`\n","- `string.split(',', x)` (describe what 'x' does. It should be a number)\n","\n"],"metadata":{"id":"mRATbQdclrcX"}},{"cell_type":"markdown","source":["## String formatting\n","We have seen a (not very convenient) way of building strings:"],"metadata":{"id":"8YAcMdHpnuKw"}},{"cell_type":"code","source":["name = 'Julian'\n","shoutout = 'Hey ' + name + '!'\n","print(shoutout)"],"metadata":{"id":"pl5hfOYmnzF2"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Luckily, there is a better (easier, more flexible) way: `string.format()`:\n","- create a string with *placeholders*: `{}`\n","- fill these placeholders with some value"],"metadata":{"id":"SjWVj2R5n1XR"}},{"cell_type":"code","source":["shoutout_template = 'Hey {}!'\n","print(shoutout_template)\n","\n","filled_template = shoutout_template.format('Jelte')\n","print(filled_template)\n","\n","names = ['Julian', 'Jelte', 'Mees']\n","for name in names:\n"," print(shoutout_template.format(name))"],"metadata":{"id":"EQ9u1CX6n_TN"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Multiple placeholders\n","Not limited to one placeholder, you can have an arbitrary amount"],"metadata":{"id":"B1_gS-UaoEy0"}},{"cell_type":"code","source":["shoutout_template = 'Hey {}! {}'\n","name = 'Julian'\n","followup = 'How are you?'\n","\n","print(shoutout_template.format(name, followup))\n","print(shoutout_template.format(name))\n","print(shoutout_template.format(name, followup, 'Where are you going?'))"],"metadata":{"id":"8KMQfVXGoHq5"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Named placeholders\n","Can also give placeholders names, and supply named parameters to `string.format()`."],"metadata":{"id":"3lMa3IDjoMZP"}},{"cell_type":"code","source":["shoutout_template = 'Hey {name}! {followup}'\n","julian = 'Julian'\n","question = 'How are you?'\n","\n","print(shoutout_template.format(name=julian, followup=question))\n","print(shoutout_template.format(followup=question, name=julian))\n","print(shoutout_template.format(followup=julian, name=question))"],"metadata":{"id":"re9x0TNLoM4Q"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 9.3: String formatting\n","In each of the code blocks below, try to predict what will be printed, then run the code. If your guess was incorrect, try to figure out why the result is different. If your guess was correct, celebrate!"],"metadata":{"id":"avcqgDAAoq-w"}},{"cell_type":"code","source":["print('hey {}')"],"metadata":{"id":"BIa0VOX_owF4"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('hey {Julian}')"],"metadata":{"id":"81GUitOZo0l2"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('hey {}'.format('Julian'))"],"metadata":{"id":"96Dq4eSCpAji"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('hey {Julian}'.format('Julian'))"],"metadata":{"id":"h43fjzPco4V_"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["print('hey {name}'.format('Julian'))"],"metadata":{"id":"wA18AIPKpFAH"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[10 - Dictionaries](https://colab.research.google.com/drive/16mecEPkVGUBIFoHIALO7dE8qv7PynHL9)"],"metadata":{"id":"y5FcFvgypMfE"}}]} \ No newline at end of file diff --git a/lessons/10 - Dictionaries.ipynb b/lessons/10 - Dictionaries.ipynb new file mode 100644 index 0000000..5c2a8d0 --- /dev/null +++ b/lessons/10 - Dictionaries.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Dictionaries\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [9. String manipulation](https://colab.research.google.com/drive/1Z7NNMxqHTSMoUadH3pVL6Bg6oii4qUoQ)\n","\n","### This module\n","\n","- Learn about _dictionaries_, a useful way of storing and looking up data"],"metadata":{"id":"kjdcNtg3k8Aa"}},{"cell_type":"markdown","source":["## What are dictionaries?\n","\n","We have already seen one type of data structure, the _list_. Lists store values in a specific _order_, and we can retrieve values by their position in the list."],"metadata":{"id":"CtgPyDQ6lkT4"}},{"cell_type":"code","source":["fruits = ['apple', 'banana', 'orange']\n","\n","assert fruits is not ['banana', 'apple', 'orange'] # order matters!\n","\n","print(fruits[1])"],"metadata":{"id":"OKs8GP5zk9bM"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["What if we want to store some extra information about each type of fruit? That is where dictionaries come in handy. Here I save the colour of each fruit."],"metadata":{"id":"OOyTxS6_mv2o"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}"],"metadata":{"id":"d0SFY-fil7-l"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Some vocabulary: `'apple'`, `'banana'` and `'orange'` are _keys_ of the dictionary, while `'red'`, `'yellow'` and `'orange'` are _values_. Keys and values come in pairs: `'red'` is the value for the key `'apple'`. We'll see what we can do with this in a bit.\n","\n","Dictionaries need not contain strings. The values of a dictionary can be anything you want. The keys are a bit more restricted: strings, numbers, and tuples are fine, but complex data structures like lists and other dictionaries are not."],"metadata":{"id":"RiNPElB7nj2F"}},{"cell_type":"code","source":["students_by_year = {2021: ['Julian', 'Jelte'], 2022: ['Julian', 'Jelte', 'Berit']}\n","\n","years_per_student = {'Jelte': [2021, 2022], 'Julian': [2021, 2022], 'Berit': 2022}\n","\n","# long dictionaries can be written on multiple lines, to keep it readable\n","dictionaries_by_topic = {\n"," 'fruit': fruit_colors,\n"," 'python course': [students_by_year, years_per_student]\n","}"],"metadata":{"id":"ao56gCSxnhkS"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# this will be rejected\n","shared_interests = {['Julian', 'Jelte']: ['cats', 'programming'], \n"," ['Jelte', 'Berit']: 'music'}"],"metadata":{"id":"JgfCNNoHn3uR"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["The keys of a dictionary should be **unique**. If you try to write something with a key that already exists, it will overwrite the old value."],"metadata":{"id":"1tYs_3xBqx2e"}},{"cell_type":"code","source":["unambiguous_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","ambiguous_colors = {'apple': 'green', 'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","assert ambiguous_colors == unambiguous_colors\n","\n","print(ambiguous_colors)"],"metadata":{"id":"TykfEB8iq4MQ"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Order does not matter for dictionaries!"],"metadata":{"id":"_3J4oaBAsTGa"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","fruit_colors_2 = {'banana': 'yellow', 'apple': 'red', 'orange': 'orange'}\n","\n","assert fruit_colors == fruit_colors_2"],"metadata":{"id":"pK0eYwsasBJ9"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["You can make emtpy dictionaries too."],"metadata":{"id":"L56hdp03r9Q6"}},{"cell_type":"code","source":["empty = {} # a dictionary with no keys / values\n","\n","new_dict = dict() #constructor function"],"metadata":{"id":"da-Re3sPsyYS"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Accessing\n","\n","With lists and tuples, we access elements with the index number. In dictionaries we access them by the key."],"metadata":{"id":"nksJpi6mqgXY"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","students_by_year = {2021: ['Julian', 'Jelte'], 2022: ['Julian', 'Jelte', 'Berit']}\n","\n","print(fruit_colors['apple'])\n","print(students_by_year[2021])"],"metadata":{"id":"SzxfzTANsjGN"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Assiging / reassigning\n","\n","You can also assign or reassign values by the key. If the key is _not_ in the dictionaryt yet, it creates the key-value pair."],"metadata":{"id":"yL7NrEzwtm_r"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","fruit_colors['apple'] = 'red or green'\n","print(fruit_colors)\n","\n","fruit_colors['kiwi'] = 'green'\n","print(fruit_colors)\n","\n","# be aware that misspelling a key creates a new entry\n","fruit_colors['bnaana'] = 'yellwo'\n","print(fruit_colors)"],"metadata":{"id":"HEOgD62xtPQj"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Updating\n","Dictionaries can be *updated* with another dictionary. This is a way to quickly add multiple key-value pairs:\n","\n","- `dictionary.update(other_dictionary)`\n","- this happens *in-place*, the function doesn't return anything"],"metadata":{"id":"zeJU8wt9uY2V"}},{"cell_type":"code","source":["students_by_year = {2021: ['Julian', 'Jelte'], 2022: ['Julian', 'Jelte', 'Berit']}\n","more_students = {2023: ['Jelte', 'Mees', 'Luka'], 2024: ['Hopefully a lot']}\n","\n","print(students_by_year.update(more_students))\n","print(students_by_year)"],"metadata":{"id":"pyxjqy31uWEs"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Deleting\n","To delete a key-value pair: `del dictionary[key]`"],"metadata":{"id":"FvGfwcVjuwIY"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","del fruit_colors['orange']\n","print(fruit_colors)"],"metadata":{"id":"72V_U4tUupnw"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Iterables\n","Dictionaries have a few useful functions:\n","- `dictionary.keys()` returns a list of all keys\n","- `dictionary.values()` returns a list of all values\n","- `dictionary.items()` returns a list of tuples: `(key, value)`"],"metadata":{"id":"-kH7Vw3WvgFj"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","\n","# which types of fruit do we have information about?\n","print(fruit_colors.keys())\n","\n","# which colors do we have?\n","print(fruit_colors.values())\n","\n","# what's in the dictionary?\n","print(fruit_colors.items())"],"metadata":{"id":"sNwzKYOAvk-d"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Checking contents\n","We can use the iterables above to check the contents of a dictionary."],"metadata":{"id":"3oBW4bxgv5JV"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","\n","print('banana' in fruit_colors.keys())\n","print('yellow' in fruit_colors.values())\n","\n","# shortcut for checking key:\n","print('banana' in fruit_colors)\n","\n","# check an entire key-value pair:\n","print(('banana', 'yellow') in fruit_colors.items())"],"metadata":{"id":"ESzsmJCXv7pl"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Alternative ways to access elements\n","- `dictionary.get(key)` returns value at key\n"," - returns `None` if they key does not exist\n"," - optional parameter: default return value\n","- `dictionary.pop(key)` returns value of key, and deletes key.\n"," - raises an error if the key does not exist\n"," - optional parameter: default return value"],"metadata":{"id":"x2nJsta6wRGQ"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","\n","print(fruit_colors.get('banana'))\n","print(fruit_colors.get('bnaana'))\n","print(fruit_colors.get('bnaana', 'yellow?'))\n","\n","print(fruit_colors.pop('banana'))\n","print(fruit_colors)\n","print(fruit_colors.pop('banana', 'wait, what was banana again?'))"],"metadata":{"id":"11lfiYMiwTct"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 10.1: Dictionaries"],"metadata":{"id":"1ezL-XhlvHBq"}},{"cell_type":"markdown","source":["1 . Below are two dictionaries containing information about different types of fruit. Print a nice message about each fruit stating its colour and price. For example, _An apple is red and costs € 2.50_, etc."],"metadata":{"id":"rxcz60KQximW"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","fruit_prices = {'apple': 2.50, 'banana': 2.10, 'orange': 1.50}\n","\n","# your code here..."],"metadata":{"id":"yn89oAAZu33C"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2 . Here is a longer lists of fruit colours. Write a function `count_fruits` which gets gets a colour as input and returns the number of fruits that have that colour (according to `lots_of_fruit`)."],"metadata":{"id":"Gtp5V9dE0LxK"}},{"cell_type":"code","source":["lots_of_fruit = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange',\n"," 'cucumber': 'green', 'kiwi': 'green', 'strawberry': 'red',\n"," 'pineapple': 'yellow','blackberry': 'black', 'cherry': 'red',\n"," 'gooseberry': 'green', 'raspberry': 'red', 'mandarin': 'orange',\n"," 'lemon': 'yellow', 'lime': 'green'}"],"metadata":{"id":"S7gCNyLCxdrO"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["\n","# your code here...\n","\n","# let's see if it works!\n","assert count_fruits('red') == 4\n","assert count_fruits('lavender') == 0"],"metadata":{"id":"nScDQipK35qN"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3 . The list `fruit_basket` contains a bunch of fruits. Can you make a dictionary `fruit_counts` which gives the amount for each fruit in `fruit_basket`? (Do not count the fruits by hand!)"],"metadata":{"id":"-Qp6R3Kp3GId"}},{"cell_type":"code","source":["fruit_basket = ['apple', 'banana', 'banana', 'banana', 'apple', 'orange',\n"," 'orange', 'grape', 'grape', 'grape', 'grape', 'grape', 'grape',\n"," 'grape', 'grape', 'grape', 'pear', 'apple', 'strawberry',\n"," 'strawberry', 'strawberry', 'orange']"],"metadata":{"id":"awf-lLQO3N1U"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# your code here..\n","\n","\n","# let's see if it works!\n","assert fruit_counts['apple'] == 3\n"],"metadata":{"id":"MDpIZpbm3-BG"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["4 . Here is a different list, which contains the words in a sentence. Can you use your code above to make a dictionary `word_counts` telling us how often each word occurs? (Tip: if you need to do very similar tasks, make a function!)\n","\n","Write a function that takes a dictionary like `word_counts` tells us the most commonly occuring item and the count. Note that there can be multiple items that occurred the most."],"metadata":{"id":"h-kJhTO951pc"}},{"cell_type":"code","source":["# the variable sent0 contains the first sentence of The Catcher in the Rye\n","# split into single words\n","sent0 = ['If', 'you', 'really', 'want', 'to', 'hear', 'about', 'it,', 'the', \n"," 'first', 'thing', 'you’ll', 'probably', 'want', 'to', 'know', 'is', \n"," 'where', 'I', 'was', 'born,', 'and', 'what', 'my', 'lousy', 'childhood', \n"," 'was', 'like,', 'and', 'how', 'my', 'parents', 'were', 'occupied', \n"," 'and', 'all', 'before', 'they', 'had', 'me,', 'and', 'all', 'that', \n"," 'David', 'Copperfield', 'kind', 'of', 'crap,', 'but', 'I', 'don’t', \n"," 'feel', 'like', 'going', 'into', 'it,', 'if', 'you', 'want', \n"," 'to', 'know', 'the', 'truth.']"],"metadata":{"id":"mdNug4ct5645"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# your code here..."],"metadata":{"id":"XGY3qSEk6B9j"},"execution_count":null,"outputs":[]}]} \ No newline at end of file diff --git a/lessons/11 working with files.ipynb b/lessons/11 working with files.ipynb new file mode 100644 index 0000000..7ebd6bd --- /dev/null +++ b/lessons/11 working with files.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyMB+UscaVxkKRr/LCtKDZnL"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 11: Working with files\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [10. dictionaries](https://colab.research.google.com/drive/16mecEPkVGUBIFoHIALO7dE8qv7PynHL9)\n","\n","### This module\n","\n","- Reading files\n","- Writing files\n","- Use existing code"],"metadata":{"id":"uHYIr4R9dWyQ"}},{"cell_type":"markdown","source":["## Reading files\n","It is not very desirable to keep data in your code. It clutters up, making the code harder to read. Also, we want to work with some interchangeable data, that exists outside of our code.\n","\n","Python provides an easy way to work with files."],"metadata":{"id":"MgaAMPDbdiTr"}},{"cell_type":"markdown","source":["### Read a file\n","- Provide a path to the file\n","- Open the file `open()`, this provides a *File Object*\n","- Work with the contents"],"metadata":{"id":"p9157kmNeAfI"}},{"cell_type":"code","source":["# Make sure the path is available to Python\n","# In notebooks, this means we need to upload the file\n","PATH = 'countries.csv'\n","\n","file = open(PATH)\n","type(file)\n","\n","contents = file.read()\n","print(type(contents))\n","print(contents)\n","\n","lines = file.readlines()\n","print(type(lines))\n","print(lines)\n"],"metadata":{"id":"kup_j23UeW71"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Sidenote: constants\n","Isn't the convention that variables are lowercased? \n","Not if they are *constants*:\n","- Variables that do not change during the progam\n","- Often represent some 'setting' or 'constant value'\n"," - `PATH = 'countries.csv'`\n"," - `PI = 3.14159265358979323846264338327950288419716939937510582097` \n"],"metadata":{"id":"96NQljy2ez-E"}},{"cell_type":"markdown","source":["## Closing files\n","- If a file is opened, it should also be closed (like a freezer)\n","- If not, nasty things can happen\n","- Call `.close()` on the File Object"],"metadata":{"id":"ZlbuEqiKftk-"}},{"cell_type":"code","source":["# Manually close\n","file = open(PATH)\n","data = file.read()\n","file.close()"],"metadata":{"id":"SzytvDuCgBiE"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["- Even better: use a *context manager*\n"," - opens the file\n"," - assigns it to a variable\n"," - and closes once you are done with it\n","- Use the `with as ` syntax"],"metadata":{"id":"9V_7uhwdgDXA"}},{"cell_type":"code","source":["with open(PATH) as file:\n"," data = file.read()\n","\n","print(data)"],"metadata":{"id":"a-Q7R8x4gby6"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Writing files\n","- Provide `mode` parameter with value `'w'` (write) to open a file in write mode\n"," - note that `mode` has a default value: `'r'` (read)\n","- On the file object, use `file.write()`\n","- If you want to write on a new line, make sure to append `'\\n'` (newline character)\n","- Alternatively, use `print(, file=`"],"metadata":{"id":"bbtncTLHhUaq"}},{"cell_type":"code","source":["WRITE_PATH = 'myfile.txt'\n","\n","with open(WRITE_PATH, mode='w') as file:\n"," file.write('Hello, world!\\n')\n"," file.write('This is a new file created by write.')\n","\n","with open(WRITE_PATH, mode='w') as file:\n"," print('Hello world!', file=file)\n"," print('This is a new file created by print.', file=file)"],"metadata":{"id":"lSmlpO2-hn6j"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Append to an existing file by using `mode='a'` (append)"],"metadata":{"id":"QVQvj4ztkhmj"}},{"cell_type":"code","source":["with open(WRITE_PATH, mode='a') as file:\n"," print('Another bit of text', file=file)"],"metadata":{"id":"NhD03dHgklBT"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 11.1 - Files\n","In the code block below, try to predict what will be printed, then run the code."],"metadata":{"id":"YC0q3Z4HiM5Z"}},{"cell_type":"code","source":["PATH = 'sample_data/california_housing_test.csv'\n","file = open(PATH)\n","print(file)\n","print(file.read())\n","print(file.readlines())\n","file.close()\n","print(file)"],"metadata":{"id":"vZtR4360i7kh"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Read the file `'sampledata/california_housing_test.csv'`, and print the first row containing data as a list.\n","\n","Are the data in the correct format? Try to fix it if not."],"metadata":{"id":"BXOkW2J7ldYK"}},{"cell_type":"code","source":[],"metadata":{"id":"eP_TfHcmlsce"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Using existing code\n","- People before you have worked with CSV files\n","- Someone probably wrote and published their code\n","- Available in *packages* and *libraries*\n","- `csv` *module* is available in the [standard library](https://docs.python.org/3.7/library/index.html). This library is *always* available in Python.\n","- Python is known for its strong ecosystem of packages\n","- Many libraries from outside the standard library are preinstalled in these Notebooks"],"metadata":{"id":"Phv4ave0mh5e"}},{"cell_type":"markdown","source":["### Importing existing code\n","Use the `import ` syntax to use an entire Python file in your own code"],"metadata":{"id":"TBgRxECDnTKW"}},{"cell_type":"code","source":["import csv\n","print(csv.reader)"],"metadata":{"id":"fXIBTOFDnVFU"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Alternatively, only import the parts your are interested in"],"metadata":{"id":"NxBU-xkZneT6"}},{"cell_type":"code","source":["from csv import reader\n","print(reader)"],"metadata":{"id":"Ykrw__BXni5z"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Working with the `csv` module\n","The `reader` function has some nice utilities that make it easy to read csv files"],"metadata":{"id":"dMIZr2o_nlch"}},{"cell_type":"code","source":["import csv\n","\n","def read_data():\n"," with open(PATH) as csv_file:\n"," reader = csv.reader(csv_file, delimiter=',')\n"," return list(reader)\n","\n","data = read_data()\n","print(data[0])\n","print(data[1])\n","print(data[10][3])"],"metadata":{"id":"05Smz2DbntnT"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Alternatively, use the `csv.DictReader` to read the file as a list of dictionaries."],"metadata":{"id":"TRHR32Bfn9tO"}},{"cell_type":"code","source":["import csv\n","\n","def read_data_dict():\n"," with open(PATH) as csv_file:\n"," reader = csv.DictReader(csv_file, delimiter=',')\n"," return list(reader)\n","\n","data = read_data_dict()\n","print(data[0])\n","print(data[1])\n","print(data[10]['name'])"],"metadata":{"id":"T67PXssOoICa"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 11.2: Bonus - working with csv datasets\n","> 💡 If you wish to perform an analysis on your own dataset in the upcoming sessions, make sure you complete this exercise. The code you write here can be reused in your own analysis.\n","\n","1. Upload your own dataset, or use `sample_data/california_housing_test.csv`\n"," 1. Read the data from the CSV file\n"," 2. Write functions that take the data as a parameter, and return the following items:\n"," - The last row\n"," - The last column\n"," - The first row. If this is a header row, try if you can come up with a way to separate it from the data rows.\n"," - Calculate the *harmonic mean* of a column containing numbers. Search the [standard library](https://docs.python.org/3.7/library/index.html) for a a relevant module containing the code to do so.\n"," 3. Add an extra column to the data (think of something that makes sense). Write the whole dataset to a new csv file."],"metadata":{"id":"h-mOS3pwoc1O"}}]} \ No newline at end of file diff --git a/lessons/Bonus Exercise data.ipynb b/lessons/Bonus Exercise data.ipynb new file mode 100644 index 0000000..c2633a8 --- /dev/null +++ b/lessons/Bonus Exercise data.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"authorship_tag":"ABX9TyPlTZNDb2yTw7vB3bqNYG48"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"code","source":["catcher_chapter1 = '''\n","If you really want to hear about it, the first thing you’ll probably want to know is where I was born, and what my lousy childhood was like, and how my parents were occupied and all before they had me, and all that David Copperfield kind of crap, but I don’t feel like going into it, if you want to know the truth. In the first place, that stuff bores me, and in the second place, my parents would have two hemorrhages apiece if I told anything pretty personal about them. They’re quitee touchy about anything like that, especially my father. They’re nice and all - I’m not saying that - but they’re also touchy as hell. Besides, I’m not going to tell you my whole goodam autobiography or anything. I’ll just tell you about this madman stuff that happened to me last Christmas just before I got pretty run-down and had to come out and take it easy. I mean that’s all I told D.B. about, and he’s my brother and all. He’s in Hollywood. That isn’t too far from this crumby place, and he comes over and visits me practically every week end. He’s going to drive me home when I go home next month maybe. He just got a Jaguar. One of those little English jobs that can do around two hundred miles an hour. It cost him damn near four thousand bucks. He’s got a lot of dough, now. He didn’t use to. He used to be just a regular writer, when he was home. He wrote thizs terrific book of short stories, The Secret Goldfish, in case you never heard of him. The best one in it was «‘The Secret Goldfish.’ It was about this little kid that wouldn’t let anybody look at his goldfish because he’d bought it with his own money. It killed me. Now he’s out in Hollywood, D.B., being a prostitute. If there’s one thing I hate, it’s the movies. Don’t even mention them to me.\n","Where I want to start is the day I left Pencey Prep. Pencey Prep is the school that’s in Agertown, Pennsylvania. You probably heard of it. You’ve probably seen the ads, anyway. They advertise in about a thousand magazines, always showing some hot-shot guy on a horse jumping over a fence. Like as if all you ever did at Pencey was play polo all the time. I never even once saw a horse anywhere near the place. And underneath the guy on the horse’s picture, it always says: ‘Since 1888 we have been molding boys into splendid, clear-thinking young men’. Strictly for the birds. They don’t do any damn more molding at Pencey than they do at any other school. And I didn’t know anybody there that was splendid and clear-thinking and all. Maybe two guys. If that many. And they probably came to Pencey that way.\n","Anyway, it was the Saturday of the football game with Saxon Hall. The game with Saxon Hall was supposed to be a very big deal around Pencey. It was the last game of the year, and you were supposed to commit suicide ou something if old Pencey didn’t win. I remember around three o’clock that afternoon I was standing way the hell on top of Thomsen Hill, right next to this crazy cannon that was in the Revolutionary War and all. You could see the whole field from there, and you could see the two teams bashing each other all over the place. You couldn’t see the granstand too hot, but you could hear them all yelling, deep and terrific on the Pencey side, because practically the whole school except me was there, and scrawny and faggy on the Saxon Hall side, because the visiting team hardly ever brought many people with them.\n","There were never many girls at all at the football games. Only seniors were allowed to bring girls with them. It was a terrible school, no matter how you looked at it. I like to be somewhere at least where you can see a few girls around once in a while, even if they’re only scratching their arms or blowing their noses or even just giggling or something. Old Selma Thurmer - she was the headmaster’s master - showed up at the games quite often, but she wasn’t exactly the type that drove you mad with desire. She was a pretty nice girl, though, I sat next to her once in the bus from Agerstown and we sort of struck up a conversation. I liked her. She had a big nose and her nails were all all bitten down and bleedy-looking and she had on those damn falsies that point all over the place, but you felt sort of sorry for her. Wha I liked about her, she didn’t give you a lot of horse manure about what a great guy her father was. She probably knew what a phony slob h e was.\n","The reason I was standing way up on Thomsen Hill, instead of down at the game, was because I’d just got back from New York with the fencing team. I was the goddam manager of the fencing team. Very big deal. We’d gone in to Newyork that morning for this fencing meet with McBurney School. Only, we didn’t have the meet. I left all the foils and equipment and stuff on the goddam subway. It wasn’t all my fault. I had to keep getting up to look at this map, so we’d know where to get off. So we got back to Pencey around two-thirty instead of around dinnertime. The whole team ostracized me the whole way back on the train. It was pretty funny, in a way.\n","The other reason I wasn’t down at the game was because I was on my way to say good-by to old Spencer, my history teacher. He had the grippe, and I figured I probably wouldn’t see him again till Christmas vacation started. He wrote me this note saying he wanted to see me before I went home. He knew I wasn’t coming back to Pencey.\n","I forgot to tell you about that. They kicked me out. I wasn’t supposed to come back after Christmas vacation, on account of I was flunking four subjects and not applying myself and all. They gave me frequent warning to start applying myself - especially around mid-terms, when my parents came up for a conference with old Thurmer - but I didn’t do it. So I got the ax. They give guys the ax quite frequently at Pencey. It has a very good academic rating, Pencey. It really does.\n","Anyway, it was December and all, and it was cold as a witch’s teat, especially on top of that stupid hill. I only had on my reversible and no gloves or anything. sThe week before that, somebody’d stolen my camel’s-hair coat right out of my room, with my fur-lined gloves right in the pocket and all. Pencey was full of crooks. Quite a few guys came from these very wealthy families, but it was full of crooks anyway. The more expensive a school is, the more crooks it has - I’m not kidding. Anyway, I kept standing next to that crazy cannon, looking down at the game and freezing my ass off. Only, I wasn’t watching the game too much. What I was really hanging around for, I was trying to feel some kind of a good-by. I mean I’ve left schools and places I didn’t even know I was leaving them. I don’t care if it’s a sad good-by or a bad good-by, but when I leave a place I live I like to know I’m leaving it. If you don’t, you feel even worse.\n","I was lucky. All of a sudden I thought of something that helped make me know I was getting the hell out. I suddenly remembered this time, in around October, that I and Robert Tichener and Paul Campbell were chucking a football around, in front of the academic building. there were nice guys, especially Tichener. It was just before dinner and it was getting pretty dark out, but we kept chucking the ball around anyway. It kept getting darker and darker, and we could hardly see the ball anyway. It kept getting darker and darker, and we could hardly see the ball any more, but we didn’t want to stop doing what we were doing. Finally we had to. This teacher that taught biology, Mr Zambesi, stuck his head out of this window in the academic building and told us to go back to the dorm and get ready for dinner. If I get a chance to remember that kind of stuff, I can get a good-by when I need one - at least, most of the time I can. As soon as I got it, I turned around and started running down the other side of the hill, toward old Spencer’s house. He didn’t live on the campus. He lived on Anthony Wayne Avenue.\n","I ran all the way to the main gate, and then I waited a second till I got my breath. I have no wind, if you want to know the truth. I’m quite a heavy smoker, for one thing - that is, I used to be. They made me cut it out. Another thing, I grew six and a half inches last year. That’s also how I practically got t.b. and came out here for all these goddam checkups and stuff. I’m pretty healthy, though.\n","Anyway, as soon as I got my breath back I ran accross Route 204. It was icy as hell and I damn near fell down. I don’t know what I was running for - I guess I just felt like it. After I got accross the road, I felt like I was sort of disappearing. It was that kind of a crazy afternoon, terricfically cold, and no sun out or anything, and you felt like you were disappearing every time you crossed a road.\n","Boy, I rang that doorbell fast when I got to old Spencer’s house. I was really frozen. My ears were hurting and I could hardly move my fingers at all. ‘C’mon, c’mon,’ I said right out loud, almost, ‘somebody open the door.’ Finally old Mrs Spencer opened it. They didn’t have a maid or anything, and they always opened the door themselves. They didn’t have too much dough.\n","‘Holden!’ Mrs Spencer said. ‘How lovely to see you! Come in, dear! Are youfrozen to death?’ I think she was glad to see me. She liked me. At least, I think she did.\n","Boy, did I get in that house fast. ‘How are you, Mrs Spencer?’ I said. ‘How’s Mr Spencer?’\n","‘Let me take your coat, dear,’ she said. She didn’t hear me ask her how Mr Spencer was. She was sort of deaf.\n","She hung up my coat in the hall closet, and I sort of brushed my hair back with my hand. I wear a crew cut quite frequently and I never have to comb it much. ‘How’ve you been, Mrs Spencer?’ I said again, only louder, so she’d hear me.\n","‘I’ve been just fine, Holden.’ She closed the closet door. ‘How have you been?’ The way she asked me, I knew right away old Spencer’d told her I’d been kicked out.\n","‘Fine,’ I said. ‘How’s Mr Spencer? He over his grippe yet?’\n","‘Over it! Holden, he’s behaving like a perfect - I don’t know what... He’s in his room, dear. Go right in.’\n","'''\n","\n","matilda_chapter1 = '''It's a funny thing about mothers and fathers. Even when their\n","own child is the most disgusting little blister you could ever\n","imagine, they still think that he or she is wonderful.\n","Some parents go further. They become so blinded by\n","adoration they manage to convince themselves their child has\n","qualities of genius.\n","Well, there is nothing very wrong with all this. It's the way\n","of the world. It is only when the parents begin telling us about\n","the brilliance of their own revolting offspring, that we start\n","shouting, \"Bring us a basin! We're going to be sick!\"\n","\n","School teachers suffer a good deal from having to listen to\n","this sort of twaddle from proud parents, but they usually get\n","their own back when the time comes to write the end-of-term\n","reports. If I were a teacher I would cook up some real\n","scorchers for the children of doting parents. \"Your son\n","Maximilian\", I would write, \"is a total wash-out. I hope you\n","have a family business you can push him into when he leaves\n","school because he sure as heck won't get a job anywhere else.\"\n","Or if I were feeling lyrical that day, I might write, \"It is a\n","curious truth that grasshoppers have their hearing-organs in \n","the sides of the abdomen. Your daughter Vanessa, judging by\n","what she's learnt this term, has no hearing-organs at all.\"\n","\n","I might even delve deeper into natural history and say,\n","\"The periodical cicada spends six years as a grub\n","underground, and no more than six days as a free creature of\n","sunlight and air. Your son Wilfred has spent six years as a\n","grub in this school and we are still waiting for him to emerge\n","from the chrysalis.\" A particularly poisonous little girl might\n","sting me into saying, \"Fiona has the same glacial beauty as an\n","iceberg, but unlike the iceberg she has absolutely nothing\n","below the surface.\" I\n","think I might enjoy writing end-of-term reports for the\n","stinkers in my class. But enough of that. We have to get on.\n","Occasionally one comes across parents who take the\n","opposite line, who show no interest at all in their children,\n","and these of course are far worse than the doting ones. Mr\n","and Mrs Wormwood were two such parents. They had a son\n","called Michael and a daughter called Matilda, and the parents\n","looked upon Matilda in particular as nothing more than a scab. A scab is something\n","you have to put up with until the time c\n","when you can pick it off and flick it away.\n","omes \n","Mr and Mrs Wormwood looked forward enormously to the\n","time when they could pick their little daughter off and flick\n","her away, preferably into the next county or even further than\n","that.\n","It is bad enough when parents treat ordinary children as\n","though they were scabs and bunions, but it becomes\n","somehow a lot worse when the child in\n","question is extraordinary, and by that I\n","mean sensitive and brilliant. Matilda was\n","both of these things, but above all she was\n","brilliant. Her mind was so nimble and she\n","was so quick to learn that her ability should\n","have been obvious even to the most half-witted of parents.\n","But Mr and Mrs Wormwood were both so gormless and so\n","wrapped up in their own silly little lives that they failed to\n","notice anything unusual about their daughter. To tell the\n","truth, I doubt they would have noticed had she crawled into\n","the house with a broken leg.\n","Matilda's brother Michael was a perfectly normal boy, but\n","the sister, as I said, was something to make your eyes pop. By\n","the age of one and a half her speech was perfect and she\n","knew as many words as most grown-ups. The parents, instead \n","of applauding her, called her a noisy chatterbox and told her\n","sharply that small girls should be seen and not heard.\n","By the time she was three, Matilda had taught herself to\n","read by studying newspapers and magazines that lay around\n","the house. At the age of four, she could read fast and well and\n","she naturally began hankering after books. The only book in\n","the whole of this enlightened household was something called\n","Easy Cooking belonging to her mother, and when she had\n","read this from cover to cover and had learnt all the recipes by\n","heart, she decided she wanted something more interesting.\n","\n","\"Daddy,\" she said, \"do you think you could buy me a\n","book?\"\n","\"A book?\" he said. \"What d'you want a flaming book for?\"\n","\"To read, Daddy.\"\n","\"What's wrong with the telly, for heaven's sake? We've got a\n","lovely telly with a twelve-inch screen and now you come\n","asking for a book! You're getting spoiled, my girl!\"\n","Nearly every weekday afternoon Matilda was left alone in\n","the house. Her brother (five years older than her) went to\n","school. Her father went to work and her mother went out\n","playing bingo in a town eight miles away. Mrs Wormwood\n","was hooked on bingo and played it five afternoons a week. On \n","the afternoon of the day when her father had refused to buy\n","her a book, Matilda set out all by herself to walk to the public\n","library in the village. When she arrived, she introduced\n","herself to the librarian, Mrs Phelps. She asked if she might sit\n","awhile and read a book. Mrs Phelps, slightly taken aback at\n","the arrival of such a tiny girl unacccompanied by a parent,\n","nevertheless told her she was very welcome.\n","\"Where are the children's books please?\" Matilda asked.\n","\"They're over there on those lower shelves,\" Mrs Phelps\n","told her. \"Would you like me to help you find a nice one with\n","lots of pictures in it?\"\n","\"No, thank you,\" Matilda said. \"I'm sure I can manage.\"\n","From then on, every afternoon, as soon as her mother had\n","left for bingo, Matilda would toddle down to the library. The\n","walk took only ten minutes and this allowed her two glorious\n","hours sitting quietly by herself in a cosy corner devouring one\n","book after another. When she had read every single children's\n","book in the place, she started wandering round in search of\n","something else.\n","Mrs Phelps, who had been watching her with fascination\n","for the past few weeks, now got up from her desk and went\n","over to her. \"Can I help you, Matilda?\" she asked. \n","\"I'm wondering what to read next,\" Matilda said. \"I've\n","finished all the children's books.\"\n","\"You mean you've looked at the pictures?\"\n","\"Yes, but I've read the books as well.\"\n","Mrs Phelps looked down at Matilda from her great height\n","and Matilda looked right back up at her.\n","\"I thought some were very poor,\" Matilda said, \"but others\n","were lovely. I liked The Secret Garden best of all. It was full of\n","mystery. The mystery of the room behind the closed door and\n","the mystery of the garden behind the big wall.\"\n","Mrs Phelps was stunned. ''Exactly how old are you,\n","Matilda?\" she asked.\n","\"Four years and three months,\" Matilda said.\n","Mrs Phelps was more stunned than ever, but she had the\n","sense not to show it. \"What sort of a book would you like to\n","read next?\" she asked.\n","Matilda said, \"I would like a really good one that grownups read. A famous one. I don't know any names.\"\n","Mrs Phelps looked along the shelves, taking her time. She\n","didn't quite know what to bring out. How, she asked herself,\n","does one choose a famous grown-up book for a four-year-old\n","girl? Her first thought was to pick a young teenager's\n","romance of the kind that is written for fifteen-year-old \n","schoolgirls, but for some reason she found herself instinctively walking past that particular shelf.\n","\"Try this,\" she said at last. \"It's very famous and very good.\n","If it's too long for you, just let me know and I'll find\n","something shorter and a bit easier.\"\n","\"Great Expectations,\" Matilda read, \"by Charles Dickens.\n","I'd love to try it.\"\n","I must be mad, Mrs Phelps told herself, but to Matilda she\n","said, \"Of course you may try it.\"\n","Over the next few afternoons Mrs Phelps could hardly take\n","her eyes from the small girl sitting for hour after hour in the\n","big armchair at the far end of the room with the book on her\n","lap. It was necessary to rest it on the lap because it was too\n","heavy for her to hold up, which meant she had to sit leaning\n","forward in order to read. And a strange sight it was, this tiny\n","dark-haired person sitting there with her feet nowhere near\n","touching the floor, totally absorbed in the wonderful\n","adventures of Pip and old Miss Havisham and her cobwebbed\n","house and by the spell of magic that Dickens the great storyteller had woven with his words. The only movement from\n","the reader was the lifting of the hand every now and then to\n","turn over a page, and Mrs Phelps always felt sad when the \n","time came for her to cross the floor and say; \"It's ten to five,\n","Matilda.\"\n","During the first week of Matilda's visits Mrs Phelps had\n","said to her, \"Does your mother walk you down here every day\n","and then take you home?\"\n","\"My mother goes to Aylesbury every afternoon to play\n","bingo,\" Matilda had said. \"She doesn't know I come here.\"\n","\"But that's surely not right,\" Mrs Phelps said. \"I think you'd\n","better ask her.\"\n","\"I'd rather not,\" Matilda said. \"She doesn't encourage\n","reading books. Nor does my father.\"\n","\"But what do they expect you to do every afternoon in an\n","empty house?\"\n","\"Just mooch around and watch the telly.\"\n","\"I see.\"\n","\"She doesn't really care what I do,\" Matilda said a little\n","sadly.\n","Mrs Phelps was concerned about the child's safety on the\n","walk through the fairly busy village High Street and the\n","crossing of the road, but she decided not to interfere.\n","Within a week, Matilda had finished Great Expectations\n","which in that edition contained four hundred and eleven \n","pages. \"I loved it,\" she said to Mrs Phelps. \"Has Mr Dickens\n","written any others?\"\n","\"A great number,\" said the astounded Mrs Phelps. \"Shall I\n","choose you another?\"\n","Over the next six months, under Mrs Phelps's\n","watchful and compassionate eye, Matilda read the following\n","books:\n","\n","Nicholas Nickleby by Charles Dickens\n","Oliver Twist by Charles Dickens\n","Jane Eyre by Charlotte Bronte\n","Pride and Prejudice by Jane Austen\n","Tess of the D'Urbervilles by Thomas Hardy\n","Gone to Earth by Mary Webb\n","Kim by Rudyard Kipling\n","The Invisible Man by H. G. Wells\n","The Old Man and the Sea by Ernest Hemingway\n","The Sound and the Fury by William Faulkner\n","The Grapes of Wrath by John Steinbeck\n","The Good Companions by J. B. Priestley\n","Brighton Rock by Graham Greene\n","Animal Farm by George Orwell\n"," \n","It was a formidable list and by now Mrs Phelps was filled\n","with wonder and excitement, but it was probably a good thing\n","that she did not allow herself to be completely carried away\n","by it all. Almost anyone else witnessing the achievements of\n","this small child would have been tempted to make a great fuss\n","and shout the news all over the village and beyond, but not so\n","Mrs Phelps. She was someone who minded her own business\n","and had long since discovered it was seldom worth while to\n","interfere with other people's children.\n","\"Mr Hemingway says a lot of things I don't understand,\"\n","Matilda said to her. \"Especially about men and women. But I\n","loved it all the same. The way he tells it I feel I am right there\n","on the spot watching it all happen.\"\n","''A fine writer will always make you feel that,\" Mrs Phelps\n","said. \"And don't worry about the bits you can't understand.\n","Sit back and allow the words to wash around you, like music.\"\n","\"I will, I will.\"\n","\"Did you know\", Mrs Phelps said, \"that public libraries like\n","this allow you to borrow books and take them home?\"\n","\"I didn't know that,\" Matilda said. \"Could I do it?\"\n","\"Of course,\" Mrs Phelps said. \"When you have chosen the\n","book you want, bring it to me so I can make a note of it and \n","it's yours for two weeks. You can take more than one if you\n","wish.\"\n","\n","From then on, Matilda would visit the library only once a\n","week in order to take out new books and return the old ones.\n","Her own small bedroom now became her reading-room and\n","there she would sit and read most afternoons, often with a\n","mug of hot chocolate beside her. She was not quite tall\n","enough to reach things around the kitchen, but she kept a\n","small box in the outhouse which she brought in and stood on\n","in order to get whatever she wanted. Mostly it was hot\n","chocolate she made, warming the milk in a saucepan on the\n","stove before mixing it. Occasionally she made Bovril or\n","Ovaltine. It was pleasant to take a hot drink up to her room\n","and have it beside her as she sat in her silent room reading in\n","the empty house in the afternoons. The books transported her\n","into new worlds and introduced her to amazing people who\n","lived exciting lives. She went on olden-day sailing ships with\n","Joseph Conrad. She went to Africa with Ernest Hemingway\n","and to India with Rudyard Kipling. She travelled all over the\n","world while sitting in her little room in an English village.\n","'''\n","\n","ij_chapter1 = '''I am seated in an office, surrounded by heads and bodies. My posture is consciously congruent to the shape of my hard chair.\n","This is a cold room in University Administration, wood-walled, Remington-hung, double-windowed against the November heat,\n","insulated from Administrative sounds by the reception area outside, at which Uncle Charles, Mr. deLint and I were lately received.\n","I am in here.\n","Three faces have resolved into place above summer-weight sportcoats and half-Windsors across a polished pine conference\n","table shiny with the spidered light of an Arizona noon. These are three Deans — of Admissions, Academic Affairs, Athletic\n","Affairs. I do not know which face belongs to whom.\n","I believe I appear neutral, maybe even pleasant, though I've been coached to err on the side of neutrality and not attempt what\n","would feel to me like a pleasant expression or smile.\n","I have committed to crossing my legs I hope carefully, ankle on knee, hands together in the lap of my slacks. My fingers are\n","mated into a mirrored series of what manifests, to me, as the letter X. The interview room's other personnel include: the\n","University's Director of Composition, its varsity tennis coach, and Academy prorector Mr. A. deLint. C.T. is beside me; the others\n","sit, stand and stand, respectively, at the periphery of my focus. The tennis coach jingles pocket-change. There is something\n","vaguely digestive about the room's odor. The high-traction sole of my complimentary Nike sneaker runs parallel to the wobbling\n","loafer of my mother's half-brother, here in his capacity as Headmaster, sitting in the chair to what I hope is my immediate right,\n","also facing Deans.\n","The Dean at left, a lean yellowish man whose fixed smile nevertheless has the impermanent quality of something stamped\n","into uncooperative material, is a personality-type I've come lately to appreciate, the type who delays need of any response from\n","me by relating my side of the story for me, to me. Passed a packet of computer-sheets by the shaggy lion of a Dean at center, he is\n","speaking more or less to these pages, smiling down.\n","'You are Harold Incandenza, eighteen, date of secondary-school graduation approximately one month from now, attending the\n","Enfield Tennis Academy, Enfield, Massachusetts, a boarding school, where you reside.' His reading glasses are rectangular, courtshaped, the sidelines at top and bottom. 'You are, according to Coach White and Dean [unintelligible], a regionally, nationally,\n","and continentally ranked junior tennis player, a potential O.N.A.N.C.A.A. athlete of substantial promise, recruited by Coach\n","White via correspondence with Dr. Tavis here commencing .. . February of this year.' The top page is removed and brought\n","around neatly to the bottom of the sheaf, at intervals. 'You have been in residence at the Enfield Tennis Academy since age\n","seven.’\n","I am debating whether to risk scratching the right side of my jaw, where there is a wen.\n","'Coach White informs our offices that he holds the Enfield Tennis Academy's program and achievements in high regard, that\n","the University of Arizona tennis squad has profited from the prior matriculation of several former E.T.A. alumni, one of whom\n","was one Mr. Aubrey F. deLint, who appears also to be with you here today. Coach White and his staff have given us —’\n","The yellow administrator's usage is on the whole undistinguished, though I have to admit he's made himself understood. The\n","Director of Composition seems to have more than the normal number of eyebrows. The Dean at right is looking at my face a bit\n","strangely.\n","Uncle Charles is saying that though he can anticipate that the Deans might be predisposed to weigh what he avers as coming\n","from his possible appearance as a kind of cheerleader for E.T.A., he can assure the assembled Deans that all this is true, and that\n","the Academy has presently in residence no fewer than a third of the continent's top thirty juniors, in age brackets all across the\n","board, and that I here, who go by 'Hal,' usually, am 'right up there among the very cream.' Right and center Deans smile\n","professionally; the heads of deLint and the coach incline as the Dean at left clears his throat:\n","'— belief that you could well make, even as a freshman, a real contribution to this University's varsity tennis program. We are\n","pleased,' he either says or reads, removing a page, 'that a competition of some major sort here has brought you down and given us\n","the chance to sit down and chat together about your application and potential recruitment and matriculation and scholarship.’\n","'I've been asked to add that Hal here is seeded third, Boys' 18-and-Under Singles, in the prestigious WhataBurger Southwest\n","Junior Invitational out at the Randolph Tennis Center —' says what I infer is Athletic Affairs, his cocked head showing a freckled\n","scalp.\n","'Out at Randolph Park, near the outstanding El Con Marriott,' C.T. inserts, 'a venue the whole contingent's been vocal about\n","finding absolutely top-hole thus far, which —’\n","'Just so, Chuck, and that according to Chuck here Hal has already justified his seed, he's reached the semifinals as of this\n","morning's apparently impressive win, and that he'll be playing out at the Center again tomorrow, against the winner of a\n","quarterfinal game tonight, and so will be playing tomorrow at I believe scheduled for 0830 —’\n","'Try to get under way before the godawful heat out there. Though of course a dry heat.’\n","'— and has apparently already qualified for this winter's Continental Indoors, up in Edmonton, Kirk tells me —' cocking\n","further to look up and left at the varsity coach, whose smile's teeth are radiant against a violent sunburn — 'Which is something\n","indeed.' He smiles, looking at me. 'Did we get all that right Hal.’\n","C.T. has crossed his arms casually; their triceps' flesh is webbed with mottle in the air-conditioned sunlight. 'You sure did.\n","Bill.' He smiles. The two halves of his mustache never quite match. 'And let me say if I may that Hal's excited, excited to be\n","invited for the third year running to the Invitational again, to be back here in a community he has real affection for, to visit with\n","your alumni and coaching staff, to have already justified his high seed in this week's not unstiff competition, to as they say still be\n","in it without the fat woman in the Viking hat having sung, so to speak, but of course most of all to have a chance to meet you\n","gentlemen and have a look at the facilities here. Everything here is absolutely top-slot, from what he's seen.’\n","There is a silence. DeLint shifts his back against the room's panelling and recenters his weight. My uncle beams and \n","straightens a straight watchband. 62.5% of the room's faces are directed my way, pleasantly expectant. My chest bumps like a\n","dryer with shoes in it. I compose what I project will be seen as a smile. I turn this way and that, slightly, sort of directing the\n","expression to everyone in the room.\n","There is a new silence. The yellow Dean's eyebrows go circumflex. The two other Deans look to the Director of Composition.\n","The tennis coach has moved to stand at the broad window, feeling at the back of his crewcut. Uncle Charles strokes the forearm\n","above his watch. Sharp curved palm-shadows move slightly over the pine table's shine, the one head's shadow a black moon.\n","'Is Hal all right, Chuck?' Athletic Affairs asks. 'Hal just seemed to ... well, grimace. Is he in pain? Are you in pain, son?’\n","'Hal's right as rain,' smiles my uncle, soothing the air with a casual hand. 'Just a bit of a let's call it maybe a facial tic, slightly,\n","at all the adrenaline of being here on your impressive campus, justifying his seed so far without dropping a set, receiving that\n","official written offer of not only waivers but a living allowance from Coach White here, on Pac 10 letterhead, being ready in all\n","probability to sign a National Letter of Intent right here and now this very day, he's indicated to me.' C.T. looks to me, his look\n","horribly mild. I do the safe thing, relaxing every muscle in my face, emptying out all expression. I stare carefully into the\n","Kekuléan knot of the middle Dean's necktie.\n","My silent response to the expectant silence begins to affect the air of the room, the bits of dust and sportcoat-lint stirred\n","around by the AC's vents dancing jaggedly in the slanted plane of windowlight, the air over the table like the sparkling space just\n","above a fresh-poured seltzer. The coach, in a slight accent neither British nor Australian, is telling C.T. that the whole applicationinterface process, while usually just a pleasant formality, is probably best accentuated by letting the applicant speak up for\n","himself. Right and center Deans have inclined together in soft conference, forming a kind of tepee of skin and hair. I presume it's\n","probably facilitate that the tennis coach mistook for accentuate, though accelerate, while clunkier than facilitate, is from a phonetic\n","perspective more sensible, as a mistake. The Dean with the flat yellow face has leaned forward, his lips drawn back from his teeth\n","in what I see as concern. His hands come together on the conference table's surface. His own fingers look like they mate as my\n","own four-X series dissolves and I hold tight to the sides of my chair.\n","We need candidly to chat re potential problems with my application, they and I, he is beginning to say. He makes a reference\n","to candor and its value.\n","'The issues my office faces with the application materials on file from you, Hal, involve some test scores.' He glances down at\n","a colorful sheet of standardized scores in the trench his arms have made. 'The Admissions staff is looking at standardized test\n","scores from you that are, as I'm sure you know and can explain, are, shall we say ... subnormal.' I'm to explain.\n","It's clear that this really pretty sincere yellow Dean at left is Admissions. And surely the little aviarian figure at right is\n","Athletics, then, because the facial creases of the shaggy middle Dean are now pursed in a kind of distanced affront, an I'm-eatingsomething-that-makes-me-really-appreciate-the-presence-of-whatever-I'm-drinking-along-with-it look that spells professionally\n","Academic reservations. An uncomplicated loyalty to standards, then, at center. My uncle looks to Athletics as if puzzled. He shifts\n","slightly in his chair.\n","The incongruity between Admissions's hand- and face-color is almost wild. '—verbal scores that are just quite a bit closer to\n","zero than we're comfortable with, as against a secondary-school transcript from the institution where both your mother and her\n","brother are administrators —' reading directly out of the sheaf inside his arms' ellipse — 'that this past year, yes, has fallen off a\n","bit, but by the word I mean \"fallen off\" to outstanding from three previous years of frankly incredible.’\n","'Off the charts.’\n","'Most institutions do not even have grades of A with multiple pluses after it,' says the Director of Composition, his expression\n","impossible to interpret.\n","'This kind of ... how shall I put it... incongruity,' Admissions says, his expression frank and concerned, 'I've got to tell you\n","sends up a red flag of potential concern during the admissions process.’\n","'We thus invite you to explain the appearance of incongruity if not outright shenanigans.' Students has a tiny piping voice\n","that's absurd coming out of a face this big.\n","'Surely by incredible you meant very very very impressive, as opposed to literally quote \"incredible,\" surely,' says C.T.,\n","seeming to watch the coach at the window massaging the back of his neck. The huge window gives out on nothing more than\n","dazzling sunlight and cracked earth with heat-shimmers over it.\n","'Then there is before us the matter of not the required two but nine separate application essays, some of which of nearly\n","monograph-length, each without exception being —' different sheet — 'the adjective various evalua-tors used was quote \"stellar\"\n","—’\n","Dir. of Comp.: 'I made in my assessment deliberate use of lapidary and effete.’\n","'— but in areas and with titles, I'm sure you recall quite well, Hal: \"Neoclassical Assumptions in Contemporary Prescriptive\n","Grammar,\" \"The Implications of Post-Fourier Transformations for a Holographically Mimetic Cinema,\" \"The Emergence of\n","Heroic Stasis in Broadcast Entertainment\" —’\n","' \"Montague Grammar and the Semantics of Physical Modality\"?’\n","' \"A Man Who Began to Suspect He Was Made of Glass\"?’\n","' \"Tertiary Symbolism in Justinian Erotica\"?’\n","Now showing broad expanses of recessed gum. 'Suffice to say that there's some frank and candid concern about the recipient\n","of these unfortunate test scores, though perhaps explainable test scores, being these essays' sole individual author.’\n","'I'm not sure Hal's sure just what's being implied here,' my uncle says. The Dean at center is fingering his lapels as he\n","interprets distasteful computed data.\n","'What the University is saying here is that from a strictly academic point of view there are admission problems that Hal needs\n","to try to help us iron out. A matriculant's first role at the University is and must be as a student. We couldn't admit a student we\n","have reason to suspect can't cut the mustard, no matter how much of an asset he might be on the field.’\n","'Dean Sawyer means the court, of course, Chuck,' Athletic Affairs says, head severely cocked so he's including the White\n","person behind him in the address somehow. 'Not to mention O.N.A.N.C.A.A. regulations and investigators always snuffling\n","around for some sort of whiff of the smell of impropriety.’ \n","The varsity tennis coach looks at his own watch.\n","'Assuming these board scores are accurate reflectors of true capacity in this case,' Academic Affairs says, his high voice\n","serious and sotto, still looking at the file before him as if it were a plate of something bad, Til tell you right now my opinion is it\n","wouldn't be fair. It wouldn't be fair to the other applicants. Wouldn't be fair to the University community.' He looks at me. 'And\n","it'd be especially unfair to Hal himself. Admitting a boy we see as simply an athletic asset would amount to just using that boy.\n","We're under myriad scrutiny to make sure we're not using anybody. Your board results, son, indicate that we could be accused of\n","using you.’\n","Uncle Charles is asking Coach White to ask the Dean of Athletic Affairs whether the weather over scores would be as heavy\n","if I were, say, a revenue-raising football prodigy. The familiar panic at feeling misperceived is rising, and my chest bumps and\n","thuds. I expend energy on remaining utterly silent in my chair, empty, my eyes two great pale zeros. People have promised to get\n","me through this.\n","Uncle C.T., though, has the pinched look of the cornered. His voice takes on an odd timbre when he's cornered, as if he were\n","shouting as he receded. 'Hal's grades at E.T.A., which is I should stress an Academy, not simply a camp or factory, accredited by\n","both the Commonwealth of Massachusetts and the North American Sports Academy Association, it's focused on the total needs of\n","the player and student, founded by a towering intellectual figure whom I hardly need name, here, and based by him on the\n","rigorous Oxbridge Quadrivium-Trivium curricular model, a school fully staffed and equipped, by a fully certified staff, should\n","show that my nephew here can cut just about any Pac 10 mustard that needs cutting, and that —’\n","DeLint is moving toward the tennis coach, who is shaking his head.\n","'— would be able to see a distinct flavor of minor-sport prejudice about this whole thing,' C.T. says, crossing and recrossing\n","his legs as I listen, composed and staring.\n","The room's carbonated silence is now hostile. T think it's time to let the actual applicant himself speak out on his own behalf,'\n","Academic Affairs says very quietly. 'This seems somehow impossible with you here, sir.’\n","Athletics smiles tiredly under a hand that massages the bridge of his nose. 'Maybe you'd excuse us for a moment and wait\n","outside, Chuck.’\n","'Coach White could accompany Mr. Tavis and his associate out to reception,' the yellow Dean says, smiling into my\n","unfocused eyes.\n","'— led to believe this had all been ironed out in advance, from the —' C.T. is saying as he and deLint are shown to the door.\n","The tennis coach extends a hypertrophied arm. Athletics says 'We're all friends and colleagues here.’\n","This is not working out. It strikes me that exit signs would look to a native speaker of Latin like red-lit signs that say HE\n","leaves. I would yield to the urge to bolt for the door ahead of them if I could know that bolting for the door is what the men in this\n","room would see. DeLint is murmuring something to the tennis coach. Sounds of keyboards, phone consoles as the door is briefly\n","opened, then firmly shut. I am alone among administrative heads.\n","'— offense intended to anyone,' Athletic Affairs is saying, his sportcoat tan and his necktie insigniated in tiny print — 'beyond\n","just physical abilities out there in play, which believe me we respect, want, believe me.’\n","'— question about it we wouldn't be so anxious to chat with you directly, see?’\n","'— that we've known in processing several prior applications through Coach White's office that the Enfield School is\n","operated, however impressively, by close relations of first your brother, who I can still remember the way White's predecessor\n","Maury Klamkin wooed that kid, so that grades' objectivity can be all too easily called into question —’\n","'By whomsoever's calling — N.A.A.U.P., ill-willed Pac 10 programs, O.N.A.N.C.A.A. —’\n","The essays are old ones, yes, but they are mine; de moi. But they are, yes, old, not quite on the application's instructed subject\n","of Most Meaningful Educational Experience Ever. If I'd done you one from the last year, it would look to you like some sort of\n","infant's random stabs on a keyboard, and to you, who use whomsoever as a subject. And in this new smaller company, the\n","Director of Composition seems abruptly to have actuated, emerged as both the Alpha of the pack here and way more effeminate\n","than he'd seemed at first, standing hip-shot with a hand on his waist, walking with a roll to his shoulders, jingling change as he\n","pulls up his pants as he slides into the chair still warm from C.T.'s bottom, crossing his legs in a way that inclines him well into\n","my personal space, so that I can see multiple eyebrow-tics and capillary webs in the oysters below his eyes and smell fabricsoftener and the remains of a breath-mint turned sour.\n","'. . . a bright, solid, but very shy boy, we know about your being very shy, Kirk White's told us what your athletically built if\n","rather stand-offish younger instructor told him,' the Director says softly, cupping what I feel to be a hand over my sportcoat's\n","biceps (surely not), 'who simply needs to swallow hard and trust and tell his side of the story to these gentlemen who bear no\n","maliciousness none at all but are doing our jobs and trying to look out for everyone's interests at the same time.’\n","I can picture deLint and White sitting with their elbows on their knees in the defecatory posture of all athletes at rest, deLint\n","staring at his huge thumbs, while C.T. in the reception area paces in a tight ellipse, speaking into his portable phone. I have been\n","coached for this like a Don before a RICO hearing. A neutral and affectless silence. The sort of all-defensive game Schtitt used to\n","have me play: the best defense: let everything bounce off you; do nothing. I'd tell you all you want and more, if the sounds I made\n","could be what you hear.\n","Athletics with his head out from under his wing: '— to avoid admission procedures that could be seen as primarily athleticsoriented. It could be a mess, son.’\n","'Bill means the appearance, not necessarily the real true facts of the matter, which you alone can fill in,' says the Director of\n","Composition.\n","'— the appearance of the high athletic ranking, the subnormal scores, the over-academic essays, the incredible grades\n","vortexing out of what could be seen as a nepotistic situation.’\n","The yellow Dean has leaned so far forward that his tie is going to have a horizontal dent from the table-edge, his face sallow\n","and kindly and no-shit-whatever:\n","'Look here, Mr. Incandenza, Hal, please just explain to me why we couldn't be accused of using you, son. Why nobody could \n","come and say to us, why, look here, University of Arizona, here you are using a boy for just his body, a boy so shy and withdrawn\n","he won't speak up for himself, a jock with doctored marks and a store-bought application.’\n","The Brewster's-Angle light of the tabletop appears as a rose flush behind my closed lids. I cannot make myself understood. 'I\n","am not just a jock,' I say slowly. Distinctly. 'My transcript for the last year might have been dickied a bit, maybe, but that was to\n","get me over a rough spot. The grades prior to that are de moi.' My eyes are closed; the room is silent. 'I cannot make myself\n","understood, now.' I am speaking slowly and distinctly. 'Call it something I ate.’\n","It's funny what you don't recall. Our first home, in the suburb of Weston, which I barely remember — my eldest brother Orin\n","says he can remember being in the home's backyard with our mother in the early spring, helping the Moms till some sort of garden\n","out of the cold yard. March or early April. The garden's area was a rough rectangle laid out with Popsicle sticks and twine. Orin\n","was removing rocks and hard clods from the Moms's path as she worked the rented Rototiller, a wheelbarrow-shaped, gas-driven\n","thing that roared and snorted and bucked and he remembers seemed to propel the Moms rather than vice versa, the Moms very tall\n","and having to stoop painfully to hold on, her feet leaving drunken prints in the tilled earth. He remembers that in the middle of the\n","tilling I came tear-assing out the door and into the backyard wearing some sort of fuzzy red Pooh-wear, crying, holding out\n","something he said was really unpleasant-looking in my upturned palm. He says I was around five and crying and was vividly red\n","in the cold spring air. I was saying something over and over; he couldn't make it out until our mother saw me and shut down the\n","tiller, ears ringing, and came over to see what I was holding out. This turned out to have been a large patch of mold — Orin posits\n","from some dark corner of the Weston home's basement, which was warm from the furnace and flooded every spring. The patch\n","itself he describes as horrific: darkly green, glossy, vaguely hirsute, speckled with parasitic fungal points of yellow, orange, red.\n","Worse, they could see that the patch looked oddly incomplete, gnawed-on; and some of the nauseous stuff was smeared around\n","my open mouth. 'I ate this,' was what I was saying. I held the patch out to the Moms, who had her contacts out for the dirty work,\n","and at first, bending way down, saw only her crying child, hand out, proffering; and in that most maternal of reflexes she, who\n","feared and loathed more than anything spoilage and filth, reached to take whatever her baby held out — as in how many used\n","heavy Kleenex, spit-back candies, wads of chewed-out gum in how many theaters, airports, backseats, tournament lounges? O.\n","stood there, he says, hefting a cold clod, playing with the Velcro on his puffy coat, watching as the Moms, bent way down to me,\n","hand reaching, her lowering face with its presbyopic squint, suddenly stopped, froze, beginning to I.D. what it was I held out,\n","countenancing evidence of oral contact with same. He remembers her face as past describing. Her outstretched hand, still\n","Rototrembling, hung in the air before mine.\n","'I ate this,' I said.\n","'Pardon me?’\n","O. says he can only remember (sic) saying something caustic as he lim-boed a crick out of his back. He says he must have felt\n","a terrible impending anxiety. The Moms refused ever even to go into the damp basement. I had stopped crying, he remembers, and\n","simply stood there, the size and shape of a hydrant, in red PJ's with attached feet, holding out the mold, seriously, like the report of\n","some kind of audit.\n","O. says his memory diverges at this point, probably as a result of anxiety. In his first memory, the Moms's path around the\n","yard is a broad circle of hysteria:\n","'God!' she calls out.\n","'Help! My son ate this!' she yells in Orin's second and more fleshed-out recollection, yelling it over and over, holding the\n","speckled patch aloft in a pincer of fingers, running around and around the garden's rectangle while O. gaped at his first real sight\n","of adult hysteria. Suburban neighbors' heads appeared in windows and over the fences, looking. O. remembers me tripping over\n","the garden's laid-out twine, getting up dirty, crying, trying to follow.\n","'God! Help! My son ate this! Help!' she kept yelling, running a tight pattern just inside the square of string; and my brother\n","Orin remembers noting how even in hysterical trauma her flight-lines were plumb, her footprints Native-American-straight, her\n","turns, inside the ideogram of string, crisp and martial, crying 'My son ate this! Help!' and lapping me twice before the memory\n","recedes.\n","'My application's not bought,' I am telling them, calling into the darkness of the red cave that opens out before closed eyes. 'I\n","am not just a boy who plays tennis. I have an intricate history. Experiences and feelings. I'm complex.\n","'I read,' I say. 'I study and read. I bet I've read everything you've read. Don't think I haven't. I consume libraries. I wear out\n","spines and ROM-drives. I do things like get in a taxi and say, \"The library, and step on it.\" My instincts concerning syntax and\n","mechanics are better than your own, I can tell, with due respect.\n","'But it transcends the mechanics. I'm not a machine. I feel and believe. I have opinions. Some of them are interesting. I could,\n","if you'd let me, talk and talk. Let's talk about anything. I believe the influence of Kierkegaard on Camus is underestimated. I\n","believe Dennis Gabor may very well have been the Antichrist. I believe Hobbes is just Rousseau in a dark mirror. I believe, with\n","Hegel, that transcendence is absorption. I could interface you guys right under the table,' I say. 'I'm not just a creãtus,\n","manufactured, conditioned, bred for a function.’\n","I open my eyes. 'Please don't think I don't care.’\n","I look out. Directed my way is horror. I rise from the chair. I see jowls sagging, eyebrows high on trembling foreheads,\n","cheeks bright-white. The chair recedes below me.\n","'Sweet mother of Christ,' the Director says.\n","T'm fine,' I tell them, standing. From the yellow Dean's expression, there's a brutal wind blowing from my direction.\n","Academics' face has gone instantly old. Eight eyes have become blank discs that stare at whatever they see.\n","'Good God,' whispers Athletics.\n","'Please don't worry,' I say. 'I can explain.' I soothe the air with a casual hand.\n","Both my arms are pinioned from behind by the Director of Comp., who wrestles me roughly down, on me with all his weight.\n","I taste floor.\n","'What's wrong?’\n","I say 'Nothing is wrong.’ \n","'''"],"metadata":{"id":"7gksh6WLMy2q"},"execution_count":null,"outputs":[]}]} \ No newline at end of file diff --git a/lessons/Extra exercises day 1.ipynb b/lessons/Extra exercises day 1.ipynb new file mode 100644 index 0000000..e4e73a8 --- /dev/null +++ b/lessons/Extra exercises day 1.ipynb @@ -0,0 +1,521 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hierbij wat extra opdrachtjes voor de modules van dag 1!" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Types\n", + "## Exercise A\n", + "useful for after 1.4\n", + "\n", + "1. Create one variable each for every following type (replace None with an example):\n", + " - Integer (`int`)\n", + " - Floating point (`float`)\n", + " - Boolean (`bool`)\n", + " - String (`str`)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "example_int = None\n", + "example_float = None\n", + "example_bool = None\n", + "example_string = None" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Did you know that you can check the type of a variable in Python? If you are ever unsure of the type of a variable, use the `type()` function to check, e.g.:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "print(type(1))\n", + "print(type(1.0))\n", + "print(type(False))\n", + "print(type('one'))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Now try and check the types of the examples you just declared using the method above:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [], + "source": [ + "## Space for exercise" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python is a 'dynamically typed' language, which means that the type of a variable can vary based on its context or user coercion. For example, you can coerce an integer to a float by declaring:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2 \n", + "2.0 \n" + ] + } + ], + "source": [ + "example_integer = 2 # declare example integer\n", + "print(example_integer, type(example_integer)) #print the integer and its type\n", + "\n", + "coerced_float = float(example_integer)\n", + "print(coerced_float, type(coerced_float))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can coerce these types manually or Python sometimes does it automatically, for example when you try and execute operations on a variable that requires a certain type. For instance, if you try to add the integer and float above, the result of that operation will be a float. Python automatically coerces the integer to a float to complete the addition.\n", + "\n", + "3. For this exercise, try to perform some operations on these variables below. Which types can be automatically added together? And what type is the result of their operation? What happens when you try a different operation, such as subtraction?" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.0 \n" + ] + } + ], + "source": [ + "ex_int = 1\n", + "ex_float = 2.0\n", + "ex_string = 'three'\n", + "ex_bool = True\n", + "\n", + "ex_result = ex_int + ex_float # example operation\n", + "print(ex_result, type(ex_result))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Lists\n", + "## Exercise B\n", + "Let's make some lists! \n", + "1. Start by declaring an empty list (`empty_list = []`)." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": {}, + "outputs": [], + "source": [ + "my_list = None" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can check the length of the list with the `len()` function:" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "ename": "TypeError", + "evalue": "object of type 'NoneType' has no len()", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mTypeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[20], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[39mprint\u001b[39m(\u001b[39mlen\u001b[39;49m(my_list))\n", + "\u001b[0;31mTypeError\u001b[0m: object of type 'NoneType' has no len()" + ] + } + ], + "source": [ + "print(len(my_list))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Now, add some elements to your list. Then check the length of the list again!" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "## Space for exercise" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Loops\n", + "## Exercise C" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Now that you have your list, let's walk through it and print every element in it. Hint: use the `for` loop." + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": {}, + "outputs": [], + "source": [ + "## Space for exercise" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Instead of simply printing the elements, see if you can print the result of an operation with each element (for example, print the element + 1). Alternatively, see if you can print the type of each element in the list." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [], + "source": [ + "## Space for exercise" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Logical Operators\n", + "## Exercise D\n", + "Python allows the use of several logical operators, so to get you in the mindset of a computer, see if you can determine whether an expression is going to return `True` or `False`. After you have given your answer, run the code in the cell to see if you were correct!" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# Declaration of the variables used in the exercise\n", + "n1 = 1\n", + "n2 = 2\n", + "n3 = 3.4\n", + "n4 = 4.5\n", + "s1 = 'Hello'\n", + "s2 = 'World'\n", + "s3 = 'Hallo'\n", + "s4 = 'Wereld'\n", + "l1 = [n1, n2, n3, n4]\n", + "l2 = [s1, s2, s3, s4]" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 1\n", + "n1 == n2" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 2\n", + "n1 + n2 == 3" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 3\n", + "n1 + n3 != 3.4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 4\n", + "s1 + s2 == \"Hello World\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 5\n", + "s3 == \"hallo\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 6\n", + "len(l1) == len(l2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 7\n", + "len(s3) == len(s1)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "##Example 8\n", + "for item in l2:\n", + " print(len(item) == 5)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "2cc67e3a9982c67c9491f847535e93961a1a3bd6725cdcb43113c9880de5dac3" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/lessons/Project - text analysis.ipynb b/lessons/Project - text analysis.ipynb new file mode 100644 index 0000000..b734990 --- /dev/null +++ b/lessons/Project - text analysis.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyPdQ81CO+C9Rw0GWjNMy5CU"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Project - Text analysis\n","In this series of exercises you will develop a text analysis tool. The steps roughly simulate real-life Digital Humanities projects:\n","- Obtaining data\n","- Cleaning data\n","- Running analyses\n","\n"],"metadata":{"id":"kIc3b-0fqM6n"}},{"cell_type":"markdown","source":["> 💡 The exercises are very useful and fun if you would like to analyse textual data. The code you write here can be reused in your own analysis.\n","\n","> ⚠️ The exercises are difficult and may take you some time to complete. Consider them a bonus, study them at home, and don't be hestitant to contact the instructors, during or after the course. If you are not interested in text-analysis, ask the instructors for similarly challenging projects on a different topic, or pursue your own ideas!\n"],"metadata":{"id":"OSpUjXmAqJI9"}},{"cell_type":"markdown","source":["## Exercise 1: Cleaning interpunction\n","Implement the function `clean_interpunction` in a way that satisfies the docstrings and assertions"],"metadata":{"id":"v1MTwBNTpTcN"}},{"cell_type":"code","source":["def clean_interpunction(string):\n"," \"\"\"Pads words and sentence-ending interpunction with a space.\n"," Other interpunction should be removed.\n","\n"," The following characters are considered sentence-ending interpunction:\n"," - .\n"," - ?\n"," - !\n","\n"," Other interpunction that should be removed:\n"," - ,\n"," - ;\n"," - :\n"," \"\"\"\n"," output_string = None # replace this line by your own lines of code\n"," return output_string\n","\n","simple_sent = 'A sentence.'\n","complex_sent = 'A sentence, with a dependent clause.'\n","assert clean_interpunction(simple_sent) == 'A sentence .'\n","assert clean_interpunction(complex_sent) == 'A sentence with a dependent clause .'\n","print('All cases passed! The function works.')"],"metadata":{"id":"fOZBq4OLp2Lz"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 2: only_periods\n","Add an optional parameter named `only_periods` to `clean_interpunction`. \n","When this parameter is `True`, all sentence-ending interpunction should be changed to a period. \n","The use of this will become clear in the next exercise."],"metadata":{"id":"U8QVnwgwqTR6"}},{"cell_type":"code","source":["def clean_interpunction(string, only_periods=None):\n"," \"\"\"Pads words and sentence-ending interpunction with a space.\n"," Other interpunction should be removed.\n"," If only_periods is True, replace all sentence ending interpunction by a period.\n","\n"," The following characters are considered sentence-ending interpunction:\n"," - .\n"," - ?\n"," - !\n","\n"," Other interpunction that should be removed:\n"," - ,\n"," - ;\n"," - :\n"," \"\"\"\n"," output_string = None # replace this line by your own lines of code\n"," return output_string\n","\n","simple_sent = 'A sentence?'\n","complex_sent = 'A sentence, with a dependent clause!'\n","assert clean_interpunction(simple_sent) == 'A sentence ?'\n","assert clean_interpunction(complex_sent) == 'A sentence with a dependent clause !'\n","assert clean_interpunction(simple_sent, only_periods=True) == 'A sentence .'\n","assert clean_interpunction(complex_sent, only_periods=True) == 'A sentence with a dependent clause .'\n","print('All cases passed! The function works.')"],"metadata":{"id":"TdLKVbsvqhGb"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 3: Split into sentences\n","Using the results of the previous exercises, implement a function that satisfies the docstring and assertions:"],"metadata":{"id":"f5q3jw66q3EG"}},{"cell_type":"code","source":["def split_sentences(text):\n"," \"\"\"Takes a single string and splits it into sentences.\n"," Sentences are lists containing words (as strings).\n"," Sentences are split on periods.\n"," Other interpunction is removed.\n","\n"," Returns a nested list of sentences and words\n"," \"\"\"\n"," # your code here\n"," # use your implementation of clean_interpunction\n"," sentences = None\n","\n"," # return the nested list\n"," return sentences\n","\n","\n","\n","text = 'The novel details two days in the life of 16-year-old Holden Caulfield after he has been expelled from prep school. Confused and disillusioned, Holden searches for truth and rails against the “phoniness” of the adult world.'\n","expected = [['The', 'novel', 'details', 'two', 'days', 'in', 'the', 'life', 'of', '16-year-old', 'Holden', 'Caulfield', 'after', 'he', 'has', 'been', 'expelled', 'from', 'prep', 'school'], \n"," ['Confused', 'and', 'disillusioned', 'Holden', 'searches', 'for', 'truth', 'and', 'rails', 'against', 'the', '“phoniness”', 'of', 'the', 'adult', 'world'], \n"," ]\n","\n","# If no errors occur, you solved it correctly!\n","split_text = split_sentences(text)\n","assert len(split_text) == 2\n","assert split_text == expected"],"metadata":{"id":"5lTZXUgwq6lW"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 4 - Putting it all together"],"metadata":{"id":"Um-nFxcTq1WA"}},{"cell_type":"markdown","source":["### The data\n","In the `class materials` section of the [Teams channel](https://teams.microsoft.com/l/channel/19%3aAlr7pcE2v9p1eaKT1BtNxJAB9mgCFT1olZvAMswJlEc1%40thread.tacv2/Algemeen?groupId=7fd15384-6748-4852-8646-d96963fb3524&tenantId=d72758a0-a446-4e0f-a0aa-4bf95a4a10e7) you will find three `.txt`files:\n","\n","\n","- `catcher_chapter1.txt`, containing the first chapter of The Catcher in the Rye by J.D. Salinger\n","- `matilda_chapter1.txt`, containing the first chapter of Matilda by Roald Dahl\n","- `ij_chapter1.txt`, containing a part of the first chapter (the chapters are way too long) of Inifite Jest by David Foster Wallace.\n","\n","Write some code that loads the whole content of each of these files into its corresponding variable, see code cell below.\n","\n","We will use these variables in the rest of the notebook. Make sure you've executed this cell at least once.\n"],"metadata":{"id":"YNbDTnBrheRq"}},{"cell_type":"code","source":["catcher_chapter1 = ''\n","matilda_chapter1 = ''\n","ij_chapter1 = ''"],"metadata":{"id":"q_58MJYQadJO"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["### Writing functions\n","Implement a few function to use in the final analysis:\n","\n","1. Implement a function that counts the total number of words given a string containing a full text.\n","2. Implement a function that calculates the average sentence length of a text. The sentence length is defined as the number of words in a sentence. Use your implementation of `split_sentences`.1\n","3. Implement a function that calculates the average word length of a text. Again, use your implementation of `split sentences`.1\n","4. Bonus: implement a function that calculates the [automated readability index](https://en.wikipedia.org/wiki/Automated_readability_index) of a text.\n","\n","1 *You can and may combine 2. and 3. into a single function that returns two values.*\n","\n","\n","\n"],"metadata":{"id":"EuaRmuhwhTIZ"}},{"cell_type":"markdown","source":["### Output\n","Implement a function that calls 1-3 (and optionally 4) for each of the novels, and outputs their results. Try to format it in a nice way, so that it is clear what the output is."],"metadata":{"id":"SSnrAH0xjUx8"}}]} \ No newline at end of file diff --git a/solutions/01 introduction solutions.ipynb b/solutions/01 introduction solutions.ipynb new file mode 100644 index 0000000..e81b287 --- /dev/null +++ b/solutions/01 introduction solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyOdt4EUgMll2VGl6yXOOeib"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 1: Introduction\n","\n","## Exercise solutions\n","\n","[Module 1](https://colab.research.google.com/drive/1i4wJpUIr77Fh1renWNjt00Bd51NbC1nB)\n","\n","## CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)"],"metadata":{"id":"Buvh9v-iYeOO"}},{"cell_type":"markdown","source":["## Exercise 1.1: Try it out"],"metadata":{"id":"pKIEfocbMaIR"}},{"cell_type":"code","source":["print(1)\n","1"],"metadata":{"id":"6hlNxRNNM1fV","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680706108778,"user_tz":-120,"elapsed":213,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"1e442ffe-2c24-468e-8f23-4dde9dae23ad"},"execution_count":4,"outputs":[{"output_type":"stream","name":"stdout","text":["1\n"]},{"output_type":"execute_result","data":{"text/plain":["1"]},"metadata":{},"execution_count":4}]},{"cell_type":"code","source":["print('oops')\n","'oops'"],"metadata":{"id":"VIm6FdRIM6OE","colab":{"base_uri":"https://localhost:8080/","height":52},"executionInfo":{"status":"ok","timestamp":1680705583794,"user_tz":-120,"elapsed":7,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"14982304-6483-4d06-f313-134443868ad9"},"execution_count":1,"outputs":[{"output_type":"stream","name":"stdout","text":["oops\n"]},{"output_type":"execute_result","data":{"text/plain":["'oops'"],"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"}},"metadata":{},"execution_count":1}]},{"cell_type":"markdown","source":["The slight surprise in the above output is that `'oops'` is first printed without quotes, and then with quotes. `print` is meant to present data in a human-friendly way, so it strips quotes from text values (which we call strings). Bare values, on the other hand, are shown in the way in which you would type them into Python."],"metadata":{"id":"Yz1P17hS3Dnj"}},{"cell_type":"code","source":["print()"],"metadata":{"id":"_MN48xz5NAya","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680705926915,"user_tz":-120,"elapsed":226,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"58a646e7-26cf-4eed-97fd-37bd06d300f1"},"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["\n"]}]},{"cell_type":"markdown","source":["You are allowed to call `print` without any value. This prints a newline."],"metadata":{"id":"yP3jC8AZ4Kyk"}},{"cell_type":"code","source":["print('apricot')\n","print('banana')\n","print('cherry')"],"metadata":{"id":"g9WKeIA2NVIA","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680706112032,"user_tz":-120,"elapsed":222,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"e9ca8138-4998-47b1-e2c9-3332e4e968e5"},"execution_count":5,"outputs":[{"output_type":"stream","name":"stdout","text":["apricot\n","banana\n","cherry\n"]}]},{"cell_type":"code","source":["'apricot'\n","'banana'\n","'cherry'"],"metadata":{"id":"NCbCfbHaNafJ","colab":{"base_uri":"https://localhost:8080/","height":38},"executionInfo":{"status":"ok","timestamp":1680597375941,"user_tz":-120,"elapsed":237,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"db68067b-3cba-4534-ea4d-f22b424fd253"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["'cherry'"],"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"}},"metadata":{},"execution_count":7}]},{"cell_type":"markdown","source":["Normally, a bare value by itself is never shown. It is a special \"service\" of notebooks that the last value in a code block is shown. This is why we see only `'cherry'` and not `'apricot'` or `'banana'`."],"metadata":{"id":"snD4bhFA4VTx"}},{"cell_type":"code","source":["# apricot\n","# banana\n","# cherry"],"metadata":{"id":"-ZuiJ92yNqpi","executionInfo":{"status":"ok","timestamp":1680706039219,"user_tz":-120,"elapsed":223,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}}},"execution_count":3,"outputs":[]},{"cell_type":"markdown","source":["Python ignores comments. From the perspective of Python, this code block is empty, so there is no output."],"metadata":{"id":"qYUevKdW4uEc"}},{"cell_type":"code","source":["print('apricot')\n","'banana'\n","# cherry"],"metadata":{"id":"b9bTbrNSNwwn","colab":{"base_uri":"https://localhost:8080/","height":52},"executionInfo":{"status":"ok","timestamp":1680706115343,"user_tz":-120,"elapsed":185,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"7229da45-10dc-4df7-9f14-d1c91b2f639f"},"execution_count":6,"outputs":[{"output_type":"stream","name":"stdout","text":["apricot\n"]},{"output_type":"execute_result","data":{"text/plain":["'banana'"],"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"}},"metadata":{},"execution_count":6}]},{"cell_type":"code","source":["# apricot\n","'banana'\n","print('cherry')"],"metadata":{"id":"GYmcSm6iOAiA","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680597832375,"user_tz":-120,"elapsed":15,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"13ce5d1a-2a9f-44e2-cb38-4736ed7db735"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["cherry\n"]}]},{"cell_type":"markdown","source":["`'banana'` is not the last value in the code block, so it is not shown. `print('cherry')` has no value of itself (although it causes output); this is why we see only `cherry` and not this:\n","\n","```\n","cherry\n","'cherry'\n","```"],"metadata":{"id":"Nk_csoK1456t"}},{"cell_type":"code","source":["print('apricot')\n","'banana'\n","pass"],"metadata":{"id":"rbjHe9KbOzFb","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680598076019,"user_tz":-120,"elapsed":292,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"9491cf85-fc36-4d10-dba3-b32ea38d8cdf"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["apricot\n"]}]},{"cell_type":"markdown","source":["`'banana'` is not shown here, because it is not the last value in the code block. While `pass` does not do anything, Python still considers it code. It is not ignored like a comment."],"metadata":{"id":"S9Jrnq4E5qPX"}},{"cell_type":"code","source":["print(pass)"],"metadata":{"id":"V1GiIP_ZNK8H","colab":{"base_uri":"https://localhost:8080/","height":135},"executionInfo":{"status":"error","timestamp":1680598126605,"user_tz":-120,"elapsed":370,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"c5c40560-3aa0-4fe1-d4fe-7a18d48ee139"},"execution_count":null,"outputs":[{"output_type":"error","ename":"SyntaxError","evalue":"ignored","traceback":["\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print(pass)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m invalid syntax\n"]}]},{"cell_type":"markdown","source":["Our very first error! The error tells us that you cannot put a `pass` inside a `print`. The reason for that is that `pass` is not a value (but a statement)."],"metadata":{"id":"8Op9FLDB6HEZ"}},{"cell_type":"code","source":["print(#oops)"],"metadata":{"id":"sNNoSfndOSiw","colab":{"base_uri":"https://localhost:8080/","height":135},"executionInfo":{"status":"error","timestamp":1680598147401,"user_tz":-120,"elapsed":286,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"11ca5bd8-3235-4980-9b67-0a191d6515b3"},"execution_count":null,"outputs":[{"output_type":"error","ename":"SyntaxError","evalue":"ignored","traceback":["\u001b[0;36m File \u001b[0;32m\"\"\u001b[0;36m, line \u001b[0;32m1\u001b[0m\n\u001b[0;31m print(#oops)\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mSyntaxError\u001b[0m\u001b[0;31m:\u001b[0m unexpected EOF while parsing\n"]}]},{"cell_type":"markdown","source":["EOF stands for \"end of file\", with \"file\" here referring to the code block. Python reads `print(` and then ignores the rest of the line because of the comment. Every `(` should have a matching `)`, so Python is surprised that the code ends without that matching `)` (which it ignored because it is inside the comment)."],"metadata":{"id":"4WV_vzIu6ZXo"}},{"cell_type":"code","source":["print('apricot', 'banana')"],"metadata":{"id":"6IZS1NUuTdOX","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680598226349,"user_tz":-120,"elapsed":312,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"04fd0ec0-61eb-4604-f9cd-0b66fb0d82bd"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["apricot banana\n"]}]},{"cell_type":"markdown","source":["You are allowed to pass more than one value to `print`. By default, it puts spaces between them. You can change the space into something else as follows:\n","\n","```py\n","# Use a comma instead of a space\n","print('apricot', 'banana', sep=',')\n","\n","# Glue values together directly (no separator)\n","print('apricot', 'banana', sep='')\n","```\n","\n","Use can use any separator you like, even very long strings."],"metadata":{"id":"G_aPWTsL64wW"}},{"cell_type":"markdown","source":["## Exercise 1.2: Hello, world!"],"metadata":{"id":"Tr3wPlHMeBCI"}},{"cell_type":"code","source":["# The following would work!\n","# (but only in a notebook)\n","'Hello, world!'"],"metadata":{"id":"jN7WTVOOSq2C"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["# This is slightly better.\n","print('Hello, world!')"],"metadata":{"id":"qNjQXYFc7wfF"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[2. Values and expressions](https://colab.research.google.com/drive/17K6C_EZoeGtRxoTbYQvygFEdpWgQ2QFp) - [solutions](https://colab.research.google.com/drive/1JKeNehBZ9hhHXPdVunQ_r9cv-lLR9Byy)"],"metadata":{"id":"zI0ohEpPUwpC"}}]} \ No newline at end of file diff --git a/solutions/02 values and expressions solutions.ipynb b/solutions/02 values and expressions solutions.ipynb new file mode 100644 index 0000000..138a960 --- /dev/null +++ b/solutions/02 values and expressions solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyPhSPWbSkxQNLvGfLg7Ov8q"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 2: Values and expressions\n","\n","### Exercise solutions\n","\n","[Module 2](https://colab.research.google.com/drive/17K6C_EZoeGtRxoTbYQvygFEdpWgQ2QFp)\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [1. Introduction](https://colab.research.google.com/drive/1i4wJpUIr77Fh1renWNjt00Bd51NbC1nB) - [solutions](https://colab.research.google.com/drive/1RIwG7hA-Ymjcm1dmSW6wA_hu1clDNrAd)"],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## Exercise 2.1: Variables and state\n","\n","In each of the code blocks below, try to predict what will be printed, then run the code. If your guess was incorrect, try to figure out why the result is different. If your guess was correct, celebrate!"],"metadata":{"id":"pDU1uK2Igmki"}},{"cell_type":"code","source":["flavor = 'vanilla'\n","print(flavor)"],"metadata":{"id":"FydkKnx_hUPq","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680606359445,"user_tz":-120,"elapsed":420,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"0cce4013-6c8a-44a9-ecc8-6720dcfcb047"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["vanilla\n"]}]},{"cell_type":"code","source":["temperature = 70\n","print(flavor)"],"metadata":{"id":"LTWods50h-Ij","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680606363219,"user_tz":-120,"elapsed":402,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"41e65fc2-80ff-45ea-dfd1-8109e8d96b95"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["vanilla\n"]}]},{"cell_type":"markdown","source":["The variable `flavor` was retained from the previous code block. The variable `temperature` is not used here."],"metadata":{"id":"pmnKAg7H95BW"}},{"cell_type":"code","source":["print(temperature)\n","temperature = 35\n","print(temperature)"],"metadata":{"id":"l2vT4L7piGRf","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680606385469,"user_tz":-120,"elapsed":450,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"472eeb4a-fe6e-4696-9817-0a481a153d5a"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["70\n","35\n"]}]},{"cell_type":"markdown","source":["`temperature` is first printed as it was retained from the previous code block. Then, it is reassigned and printed again."],"metadata":{"id":"ElhEcRIB-EsA"}},{"cell_type":"code","source":["dog_name = 'Bobby'\n","cat_name = 'Garfield'\n","dog_name = cat_name\n","cat_name = dog_name\n","print(dog_name)\n","print(cat_name)"],"metadata":{"id":"k1Z_yWLXiWy7","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680606390493,"user_tz":-120,"elapsed":230,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"41a6d3ad-c50e-4bd4-f347-07eae4f8fae9"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["Garfield\n","Garfield\n"]}]},{"cell_type":"markdown","source":["On line 3, it is important to realize that `dog_name` gets *the value of* `cat_name`. There is no permanent tie between the variables. After line 3, both variables have the same value. Hence, `cat_name` cannot change into anything else on line 4. The program has effectively forgotten the value `'Bobby'`."],"metadata":{"id":"iFkF67zp-LJk"}},{"cell_type":"markdown","source":["Before running the following code, try to explain why it does *not* output `chocolate`."],"metadata":{"id":"BZ50KykuAYPs"}},{"cell_type":"code","source":["sweet = 'chocolate'\n","savory = 'cheese'\n","dessert = 'sweet'\n","print(dessert)"],"metadata":{"id":"X3xHg6K4Aicn","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680606431330,"user_tz":-120,"elapsed":202,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"5a5e974b-cb7a-466b-f900-b8b586080212"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["sweet\n"]}]},{"cell_type":"markdown","source":["On line 3, `'sweet'` is quoted, so Python considers it a string. It does not recognize it as a variable, even though we also defined a variable with that name on line 1."],"metadata":{"id":"1qb27-Rf-wIH"}},{"cell_type":"markdown","source":["In each of the following lines of code, replace `None` by a value of your choice. Make it such that `my_int` is an integer, `my_float` is a float, `my_bool` is a boolean and `my_string` is a string."],"metadata":{"id":"0az3tNK7WD3G"}},{"cell_type":"code","source":["my_int = 42\n","my_float = .5\n","my_bool = True\n","my_string = \"I'm starving\""],"metadata":{"id":"lY-M8mfSXDfG"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 2.2: Bonus"],"metadata":{"id":"dvNIQh7KYuJb"}},{"cell_type":"markdown","source":["How could you verify in code whether the variables you wrote above have the correct type? Write this code below.\n","\n","Hint: scroll back to the section [Difference between types](#scrollTo=Difference_between_types)."],"metadata":{"id":"GI9fyUO8XOcp"}},{"cell_type":"code","source":["print(type(my_int))\n","print(type(my_float))\n","print(type(my_bool))\n","print(type(my_string))"],"metadata":{"id":"Om6z53RXYBoS","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680606693012,"user_tz":-120,"elapsed":223,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"3f66fabe-bd2c-4046-d165-b6dc475ffcc2"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["\n","\n","\n","\n"]}]},{"cell_type":"markdown","source":["In the code block below, replace the question mark `?` by a variable name. Make it such that the final output is `'Hooray!'`."],"metadata":{"id":"h6UKIMXCj3w9"}},{"cell_type":"code","source":["cheer = 'Hooray!'\n","alarm = 'Oh no!'\n","anthem = 'Wilhelmus van Nassauwe'\n","alarm = anthem\n","alarm = cheer # alarm instead of ?\n","cheer = anthem\n","anthem = alarm\n","print(anthem)"],"metadata":{"id":"3MI6_DY7ku30","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680606893191,"user_tz":-120,"elapsed":247,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"6a605092-cca4-41c3-dfa3-0196c98be37b"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["Hooray!\n"]}]},{"cell_type":"markdown","source":["## Exercise 2.3: Expressions\n","\n"],"metadata":{"id":"z_bXvnya5J2_"}},{"cell_type":"markdown","source":["1. Try to predict the value of each of the following code blocks. Can you explain any surprises?"],"metadata":{"id":"j9xhznQlbCBf"}},{"cell_type":"code","source":["1 + 1"],"metadata":{"id":"0QcMB4xwbSfL","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680609962892,"user_tz":-120,"elapsed":415,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"609a5c45-cd77-4aaa-c33e-928263e14c41"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["2"]},"metadata":{},"execution_count":92}]},{"cell_type":"code","source":["1 * 1"],"metadata":{"id":"eHKN9kP9bWkm","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680609965892,"user_tz":-120,"elapsed":10,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"9b17e8cc-3a5a-4ac4-db2f-1454eae873af"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["1"]},"metadata":{},"execution_count":93}]},{"cell_type":"code","source":["a = 1\n","b = 2\n","a + b"],"metadata":{"id":"uINoRNNbbXwJ","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680609969742,"user_tz":-120,"elapsed":323,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"1b281881-5bbc-476e-e38c-bda84855665d"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["3"]},"metadata":{},"execution_count":94}]},{"cell_type":"code","source":["c = b\n","a * b * c"],"metadata":{"id":"4xyWkYlnbc_8","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680609971809,"user_tz":-120,"elapsed":15,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"9b2dae89-2331-47de-83a5-4ac63e71a06d"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["4"]},"metadata":{},"execution_count":95}]},{"cell_type":"code","source":["'hakuna' + 'matata'"],"metadata":{"id":"7tW2T4mebljv","colab":{"base_uri":"https://localhost:8080/","height":38},"executionInfo":{"status":"ok","timestamp":1680609976922,"user_tz":-120,"elapsed":408,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"404d4cac-d77d-40f8-c6bc-b6f4fcf0e125"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["'hakunamatata'"],"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"}},"metadata":{},"execution_count":96}]},{"cell_type":"markdown","source":["If we had done `print('hakuna', 'matata')`, it would have output `hakuna matata`, with a space between the words. When we concatenate strings using `+`, Python does not take that liberty, so if we actually want to separate words with spaces, we have to add them ourselves."],"metadata":{"id":"wG4N61Jz_WJV"}},{"cell_type":"code","source":["liquid = 'water~'\n","liquid * 3"],"metadata":{"id":"uEdPHIhBb2Mw","colab":{"base_uri":"https://localhost:8080/","height":38},"executionInfo":{"status":"ok","timestamp":1680609981027,"user_tz":-120,"elapsed":332,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"fc706353-8980-4baa-fc4b-cca736f757e9"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["'water~water~water~'"],"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"}},"metadata":{},"execution_count":97}]},{"cell_type":"code","source":["5 - 2 - 1"],"metadata":{"id":"-D7BB50Qceo2","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680609983171,"user_tz":-120,"elapsed":236,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"1169bc24-b2d3-41d5-b190-7e1135e3d93a"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["2"]},"metadata":{},"execution_count":98}]},{"cell_type":"code","source":["5 - (2 - 1)"],"metadata":{"id":"OQUGr5rGck3m","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680609985039,"user_tz":-120,"elapsed":237,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"95e07168-7633-4cc0-f961-d8beb34e5612"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["4"]},"metadata":{},"execution_count":99}]},{"cell_type":"markdown","source":["The above result is different from the previous, because Python evaluates minus operators (and most other operators) left-to-right by default."],"metadata":{"id":"btuLZMUG_xfJ"}},{"cell_type":"code","source":["income = 100\n","tax = 20\n","net_income = income - tax\n","tax = 15\n","net_income"],"metadata":{"id":"Jc8fawaIdCD5","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680609988715,"user_tz":-120,"elapsed":212,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"7d524d26-14c3-439a-e78f-914552814109"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["80"]},"metadata":{},"execution_count":100}]},{"cell_type":"markdown","source":["On line 3, we set `net_income` to the outcome of *the value of* `income` minus *the value of* `tax`, which are respectively `100` and `20` at that point. `net_income` then keeps its value (`80`) until we change it directly. Hence, line 4 does not change anything about `net_income`. If we wanted to update `net_income`, we would have to run line 3 again."],"metadata":{"id":"w08CSKAhADsd"}},{"cell_type":"markdown","source":["2. In the code block below, change the values of `character` and `multiplier` so that the output becomes `'Goooood!'`."],"metadata":{"id":"TlLkcRv-droI"}},{"cell_type":"code","source":["character = 'o'\n","multiplier = 5\n","\n","begin = 'G'\n","middle = character * multiplier\n","end = 'd!'\n","\n","begin + middle + end"],"metadata":{"id":"pYZUkeDJenob","colab":{"base_uri":"https://localhost:8080/","height":38},"executionInfo":{"status":"ok","timestamp":1680610076844,"user_tz":-120,"elapsed":406,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"97c1b7a5-adf1-4112-b0b4-9a7a826855de"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["'Goooood!'"],"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"}},"metadata":{},"execution_count":101}]},{"cell_type":"markdown","source":["3. Rewrite your Hello world-program:\n"," - Build the \"hello, world!\" string using multiple variables.\n"," - Make the program say \"hello, world!\" 3 times, each time on a new line"],"metadata":{"id":"G8X4n_a8a5tl"}},{"cell_type":"code","source":["# This works:\n","hello = 'Hello, '\n","world = 'world!\\n'\n","variable = hello + world\n","print(3 * variable)\n","\n","# This works, too:\n","slogan = '''Hello, world!\n","'''\n","result = 3 * slogan\n","print(result)\n","\n","# This would also work, but uses no variables:\n","print('Hello, world!\\n' * 3)"],"metadata":{"id":"nDUVvhDEfIVI","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680708229954,"user_tz":-120,"elapsed":8,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"8be0c0dd-dc1e-48cc-bfae-5b3c2520efed"},"execution_count":1,"outputs":[{"output_type":"stream","name":"stdout","text":["Hello, world!\n","Hello, world!\n","Hello, world!\n","\n","Hello, world!\n","Hello, world!\n","Hello, world!\n","\n","Hello, world!\n","Hello, world!\n","Hello, world!\n","\n"]}]},{"cell_type":"markdown","source":["## Exercise 2.4: Bonus"],"metadata":{"id":"3HCqdTj2fVPK"}},{"cell_type":"markdown","source":["1. Find out and describe what the following operators do:\n"," - `%` (e.g. `10 % 2`)\n"," - `//` (e.g. `10 // 2`)\n"," - `**` (e.g. `10 ** 2`)\n"," - Tip: write the expressions using variables. Change the variables and see how it affects the outcome."],"metadata":{"id":"EKFdkLkWa8EY"}},{"cell_type":"code","source":["# Regarding %, you will quickly see a pattern if you set\n","# the right operand to 3 and try a series of consecutive\n","# numbers as the left operand:\n","\n","10 % 3 == 1\n","11 % 3 == 2\n","12 % 3 == 0\n","13 % 3 == 1\n","14 % 3 == 2\n","15 % 3 == 0\n","16 % 3 == 1\n","17 % 3 == 2\n","18 % 3 == 0\n","\n","# Conclusion: % calculates the remainder of division.\n","\n","# // is like / (division), but rounded down to an integer.\n","10 / 3 == 3.33333333333333333\n","10 // 3 == 3\n","5 / 4 == 1.25\n","5 // 4 == 1\n","\n","# In general, the following equation is always true if\n","# a and b are integers:\n","(a // b) * b + a % b == a\n","\n","# a ** b raises a to the power of b.\n","3 ** 2 == 3 * 3 == 9\n","3 ** 3 == 3 * 3 * 3 == 27\n","3 ** 4 == 3 * 3 * 3 * 3 == 81"],"metadata":{"id":"V59a7vpDfzO2"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["2. Predict what will be printed on each line in the following code block, then run the code to check your answer. If you made any mistakes, try to figure out what is causing the difference."],"metadata":{"id":"o0WYIAUla-AX"}},{"cell_type":"code","source":["word = 'stylometry'\n","repeats = 3\n","extra = 2\n","\n","print((word * repeats) + str(extra))\n","# Evaluated in this order:\n","word == 'stylometry'\n","repeats == 3\n","'stylometry' * 3 == 'stylometrystylometrystylometry'\n","str(extra) == '2'\n","'stylometrystylometrystylometry' + '2' == 'stylometrystylometrystylometry2'\n","\n","print(word * (repeats + extra))\n","# Evaluated in this order:\n","word == 'stylometry'\n","repeats + extra == 5\n","'stylometry' * 5 == 'stylometrystylometrystylometrystylometrystylometry'\n","\n","print(word * repeats + str(extra))\n","# Evaluated in the same way as line 5, just without parentheses.\n","# The * operator takes precedence over the + operator by default.\n","\n","print((word + str(extra)) * repeats)\n","# Evaluated in this order:\n","word == 'stylometry'\n","str(extra) == '2'\n","word + str(extra) == 'stylometry2'\n","repeats == 3\n","'stylometry2' * 3 == 'stylometry2stylometry2stylometry2'\n","\n","print(word + str(extra * repeats))\n","# Evaluated in this order:\n","word == 'stylometry'\n","extra == 2\n","repeats == 3\n","2 * 3 == 6\n","str(6) == '6'\n","'stylometry' + '6' == 'stylometry6'\n","\n","print(word + str(extra) * repeats)\n","# Evaluated in this order:\n","word == 'stylometry'\n","extra == 2\n","str(2) == '2'\n","repeats == 3\n","# * operator takes precedence over +, so right subexpression first.\n","'2' * 3 == '222'\n","'stylometry' + '222' == 'stylometry222'"],"metadata":{"id":"Z9Vd9pdIUzT5","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680709009778,"user_tz":-120,"elapsed":202,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"1cde1422-5f7f-460f-c537-5393acf5bb2a"},"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["stylometrystylometrystylometry2\n","stylometrystylometrystylometrystylometrystylometry\n","stylometrystylometrystylometry2\n","stylometry2stylometry2stylometry2\n","stylometry6\n","stylometry222\n"]}]},{"cell_type":"markdown","source":["3. Using just the variables `word`, `repeats` and `extra` from the previous code block, write a single big expression that evaluates to `'stylometry555stylometry'`."],"metadata":{"id":"DRObBQZHgsIG"}},{"cell_type":"code","source":["word + str(extra + repeats) * repeats + word\n","# (you can add parentheses, as long as you evaluate the * before the +)"],"metadata":{"id":"uLuiUk10gqwM"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 2.5: boolean expressions"],"metadata":{"id":"pvrcgKU18OrJ"}},{"cell_type":"markdown","source":["1. Predict for each boolean expression below: `True` or `False`? If any of your predictions is incorrect, try to find the reason."],"metadata":{"id":"sWdnjezoil9j"}},{"cell_type":"code","source":["name = 'Jelte'\n","height = 2\n","\n","name * height == 'Jelte Jelte'\n","# False because string repetition does not add spaces\n","\n","height < 2\n","# a number can never be less than itself\n","\n","2 <= height\n","# ... but a number is always less than or equal to itself\n","\n","1 < height <= 2\n","# Python allows you to compare the same expression on two sides\n","\n","2 <= height < 1\n","# Both comparison must be true for the whole expression to be True\n","\n","name <= 'Julian'\n","# Lexicographical comparison: 'Julian' is greater because\n","# 'u' comes after 'e'.\n","\n","height * 3 + 1 >= height\n","# * and + take precedence over >=, so the evaluation goes in this order:\n","height * 3 == 6\n","6 + 1 == 7\n","height == 2\n","(7 >= 2) == True"],"metadata":{"id":"RpSvrom3Z8fQ","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680614316115,"user_tz":-120,"elapsed":394,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"d3c6bb57-e8c1-4891-c01d-850fd504e1f5"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["True"]},"metadata":{},"execution_count":148}]},{"cell_type":"markdown","source":["2. Run the code block below. Did you expect this result? Can you explain it?"],"metadata":{"id":"zJiaGIlZBN_P"}},{"cell_type":"code","source":["1 == True\n","\n","# 1 and True are literally the same value.\n","# More interesting equalities and inequalities:\n","\n","0 == False\n","2 != True\n","None != False"],"metadata":{"id":"_PrnFf2lioMB","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680614442403,"user_tz":-120,"elapsed":208,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"9db936a2-9182-402b-bf50-207b3366496a"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["True"]},"metadata":{},"execution_count":155}]},{"cell_type":"markdown","source":["3. Replace one value in each of the following expressions so the expression becomes `True`."],"metadata":{"id":"q8QviA70kdQE"}},{"cell_type":"code","source":["3 > height\n","0 == 0\n","'Julian' < 'Julian' * 2\n","name < 2 * name"],"metadata":{"id":"qDQ9Ob5Zkrqm","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680614593732,"user_tz":-120,"elapsed":320,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"af8cc847-7dbe-4ba7-fd7b-406e47d7b69d"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["True"]},"metadata":{},"execution_count":165}]},{"cell_type":"markdown","source":["4. Replace one operator in each of the following expressions so the expression becomes `True`."],"metadata":{"id":"YbdV7SQVmDVV"}},{"cell_type":"code","source":["5 > 4\n","2 - 1 == 1\n","3 + 3 == 3 * 2"],"metadata":{"id":"hzjXIwkAmChv","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680614702559,"user_tz":-120,"elapsed":254,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"a1592d3e-971f-4c75-b496-13e6875e1a55"},"execution_count":null,"outputs":[{"output_type":"execute_result","data":{"text/plain":["True"]},"metadata":{},"execution_count":171}]},{"cell_type":"markdown","source":["5. The *Groot woordenboek van de Nederlandse taal* by Van Dale publishers, colloquially known as \"De dikke Van Dale\", is a three-tome Dutch dictionary. The first tome contains words starting a–i, the second j–q and the third r–z. In the code block below, write an expression that will tell you whether `word` should be in the second tome. Try different values of `word` to verify that your solution is correct. You do not need to check whether the word is actually Dutch!"],"metadata":{"id":"SwyAMDzDn2_X"}},{"cell_type":"code","source":["word = 'archaïsch' # try also 'idee', 'j', 'quasi', 'r', 'ziezo'\n","\n","# is it in the FIRST tome?\n","word < 'j'\n","\n","# is it in the THIRD tome?\n","word >= 'r'\n","\n","# is it in the SECOND tome? (opposites of the previous expressions)\n","word >= 'j'\n","word < 'r'\n","\n","# combining both conditions in a single expression\n","'j' <= word < 'r'"],"metadata":{"id":"lmCGfx_DqMWe","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680710351970,"user_tz":-120,"elapsed":193,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"77da4795-3001-4582-ce37-58d289b7a181"},"execution_count":3,"outputs":[{"output_type":"execute_result","data":{"text/plain":["False"]},"metadata":{},"execution_count":3}]},{"cell_type":"markdown","source":["## Next module\n","\n","[3. Conditionals](https://colab.research.google.com/drive/1KkZ2fS75o7giccQJakRhyvYBV7JdFnVw) - [solutions](https://colab.research.google.com/drive/1Nvvjc3fGnMg2tWvfw2W1gVn2oKKbWzGI)"],"metadata":{"id":"jXSxbjf4q6q5"}}]} \ No newline at end of file diff --git a/solutions/03 conditionals solutions.ipynb b/solutions/03 conditionals solutions.ipynb new file mode 100644 index 0000000..2e8fa46 --- /dev/null +++ b/solutions/03 conditionals solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyN+nbIqsypUJCun9Hzkloun"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 3: Conditionals\n","\n","### Exercise solutions\n","\n","[Module 3](https://colab.research.google.com/drive/1KkZ2fS75o7giccQJakRhyvYBV7JdFnVw)\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [2. Values and expressions](https://colab.research.google.com/drive/17K6C_EZoeGtRxoTbYQvygFEdpWgQ2QFp) - [solutions](https://colab.research.google.com/drive/1JKeNehBZ9hhHXPdVunQ_r9cv-lLR9Byy)"],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## Exercise 3.1: if/elif/else"],"metadata":{"id":"tvXa9KWXAwge"}},{"cell_type":"markdown","source":["1. Try to predict the output of the following code blocks. Can you explain any surprises?"],"metadata":{"id":"pKBuViM9u7ZC"}},{"cell_type":"code","source":["if 3 <= 2:\n"," # The first print is not executed,\n"," # because it is inside the conditional and\n"," # the condition is False.\n"," print('What a strange day.')\n","\n","# The second print is executed, because it is\n","# outside of the conditional.\n","print('What a strange day.')\n","\n","# Therefore, we see the sentence once."],"metadata":{"id":"sEQyw2xJvzQN","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680618391562,"user_tz":-120,"elapsed":232,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"f38ca572-f203-48ea-875e-a1d5b6b89fc6"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["What a strange day.\n"]}]},{"cell_type":"code","source":["if None == 0:\n"," # The condition is False, so this code never runs.\n"," # The pass statement makes no difference.\n"," pass\n"," print('I got nothing to do.')"],"metadata":{"id":"FnCFfEb_v-0Y"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":["name = 'Julian'\n","\n","if name < 'Jelte':\n"," # This condition is False, so it does not execute.\n"," print('Alphabetically before Jelte')\n","elif name > 'Jelte':\n"," # This condition is True, so it does execute.\n"," print('Alphabetically after Jelte')\n","else:\n"," # One of the previous conditions was True, so\n"," # this block does not execute.\n"," print('Same name as Jelte')"],"metadata":{"id":"arta4ZQ0vDSC","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680618415623,"user_tz":-120,"elapsed":228,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"26955fab-9309-484f-c088-23bfc2d04480"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["Alphabetically after Jelte\n"]}]},{"cell_type":"markdown","source":["2. In the following code block, fill the condition in the `if` statement. If `value` is greater than `5`, `size` must be `'large'`; otherwise, `size` must be `'small'`. Change `value` a few times and rerun the code to check that your condition is correct."],"metadata":{"id":"4SVSiqHSu4WX"}},{"cell_type":"code","source":["value = 4\n","\n","if value > 5:\n"," size = 'large'\n","else:\n"," size = 'small'\n","\n","print(size)"],"metadata":{"id":"czmdFacjeUaL","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680618457948,"user_tz":-120,"elapsed":199,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"1d9e3543-af26-4b51-a511-3a575f11596f"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["small\n"]}]},{"cell_type":"markdown","source":["3. Write an `if`/`elif`/`else` statement like the previous, but with different cutoff points: if `value` is less than `4`, `size` must be `'small'`; if `value` is between `4` and `6` (inclusive), `size` must be `'medium'`; if `value` is greater than `6`, `size` must be `'large'`."],"metadata":{"id":"sEOwMi04e6WW"}},{"cell_type":"code","source":["value = 4\n","\n","# Option 1: multiple independent conditionals.\n","# This performs the same checks multiple times.\n","if value < 4:\n"," size = 'small'\n","if 4 <= value <= 6:\n"," size = 'medium'\n","if value > 6:\n"," size = 'large'\n","\n","# Option 2: a single if-elif-else. There is\n","# still a little bit of overlap between the first\n","# and the second condition.\n","if value < 4:\n"," size = 'small'\n","elif 4 <= value <= 6:\n"," size = 'medium'\n","else:\n"," size = 'large'\n","\n","# Option 3: a single if-elif-else, but now without\n","# any overlap between the conditions. We achieve this\n","# by changing the order in which we recognize the\n","# classifications. When the conditions are expensive\n","# to evaluate, this is generally the best option.\n","if value < 4:\n"," size = 'small'\n","elif value > 6:\n"," size = 'large'\n","else:\n"," size = 'medium'\n","\n","print(size)"],"metadata":{"id":"8HeaY6l9f9iA","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680618544259,"user_tz":-120,"elapsed":546,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"615a9d80-7dca-4e14-c9cc-2ee096f90f3f"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["medium\n"]}]},{"cell_type":"markdown","source":["4. Rewrite the conditional that checks if a letter is neither 'a' nor 'b', using a different notation."],"metadata":{"id":"TWzbez_2RUh4"}},{"cell_type":"code","source":["letter = 'c'\n","\n","# original\n","if not (letter == 'a' or letter == 'b'):\n"," print('neither a nor b')\n","\n","# a variant in which we change all operators\n","if letter != 'a' and letter != 'b':\n"," print('neither a nor b')\n","\n","# a variant using not\n","if not letter == 'a' and not letter == 'b':\n"," print('neither a nor b')\n","\n","# same as above, adding parentheses to clarify\n","# the order in which Python evaluates the operators\n","if (not (letter == 'a')) and (not (letter == 'b')):\n"," print('neither a nor b')"],"metadata":{"id":"XsIg1MD4JrPX","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680618957473,"user_tz":-120,"elapsed":10,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"87f54254-5a5f-47a4-bab8-7feb4703bf2f"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["neither a nor b\n"]}]},{"cell_type":"markdown","source":["## Exercise 3.2: Bonus"],"metadata":{"id":"-XEYQZJ1ya1j"}},{"cell_type":"markdown","source":["*FizzBuzz part 1* (advanced).\n","Write an `if`/`elif`/`else` statement that behaves as follows:\n","\n","- if `value` is divisible by 3 but not by 5, print `'Fizz'`;\n","- if `value` is divisible by 5 but not by 3, print `'Buzz'`;\n","- if `value` is divisible by 3 *and* by 5, print `'FizzBuzz'`;\n","- in all remaining cases, print `value`.\n","\n","Tip: use the result of [Exercise 2.4.1](https://colab.research.google.com/drive/17K6C_EZoeGtRxoTbYQvygFEdpWgQ2QFp#scrollTo=Exercise_2_4_Bonus)!"],"metadata":{"id":"POVFwRu_f91I"}},{"cell_type":"code","source":["value = 9\n","\n","# A straightforward variant, in which we literally\n","# translate the English description to Python code.\n","if value % 3 == 0 and value % 5 != 0:\n"," print('Fizz')\n","elif value % 5 == 0 and value % 3 != 0:\n"," print('Buzz')\n","elif value % 5 == 0 and value % 3 == 0:\n"," print('FizzBuzz')\n","else:\n"," print(value)\n","\n","# A more efficient variant, in which we use more \"tricks\":\n","# - We can start with an empty string and update it later.\n","result = ''\n","if value % 3 == 0:\n"," # - If value is divisible by 3, we ALWAYS want \"Fizz\",\n"," # even if value is ALSO divisible by 5.\n"," result = result + 'Fizz'\n","if value % 5 == 0:\n"," # - If value is divisible by 5, we can add \"Buzz\" to\n"," # the result regardless of whether it contains \"Fizz\".\n"," result = result + 'Buzz'\n","# - We use the short-circuiting behavior of and/or.\n","# - and: stop evaluating as soon as you find a False\n","# subexpression, because then the whole expression\n","# must be False as well.\n","# - or: stop evaluating as soon as you find a True\n","# subexpression, because then the whole expression\n","# must be True as well.\n","# If result is still the empty string, then it evaluates as\n","# False and we print value. Otherwise, or already knows that\n","# the expression will be True, so value is never evaluated\n","# and result is printed instead.\n","print(result or value)"],"metadata":{"id":"SZGeQtqEhiAK","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680782728257,"user_tz":-120,"elapsed":233,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"f067c099-61f7-4d68-851d-8e7db89ed04f"},"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["Fizz\n"]}]},{"cell_type":"markdown","source":["## Next module\n","\n","[4. Datastructures](https://colab.research.google.com/drive/1JxzmIzwcipnwFBntv0WZOlT-d2fUjoRF) - [solutions](https://colab.research.google.com/drive/1juOQFMlRmeVUfbKWy0wtZ9lWkSZmr2Gn)"],"metadata":{"id":"YBC4OfihzFho"}}]} \ No newline at end of file diff --git a/solutions/04 datastructures solutions.ipynb b/solutions/04 datastructures solutions.ipynb new file mode 100644 index 0000000..4ef1399 --- /dev/null +++ b/solutions/04 datastructures solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true,"authorship_tag":"ABX9TyOIQlgg0FQF3naGWr9eJVVL"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 4: Datastructures\n","\n","### Exercise solutions\n","\n","[Module 4](https://colab.research.google.com/drive/1JxzmIzwcipnwFBntv0WZOlT-d2fUjoRF)\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [3. Conditionals](https://colab.research.google.com/drive/1KkZ2fS75o7giccQJakRhyvYBV7JdFnVw) - [solutions](https://colab.research.google.com/drive/1Nvvjc3fGnMg2tWvfw2W1gVn2oKKbWzGI)"],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## Exercise 4.1: Lists\n","\n","1. For each of the `print` statements below, what do you expect is printed? Run the lines to check predictions"],"metadata":{"id":"70aMsClGPRy9"}},{"cell_type":"code","source":["countries = ['japan', 'hungary', 'maldives', 'gabon', 'bhutan']\n","\n","print(countries[0])\n","# Index 0 is the FIRST element of the list, so 'japan'.\n","\n","print(countries[-3])\n","# Third element from the end (where 'bhutan' is first),\n","# so 'maldives'.\n","\n","print(countries[0:1] + countries[2:4])\n","# In a slice, the first index is inclusive while the last\n","# index is exclusive. Hence, we have two sublists:\n","# 1. starting at the first element, up to but not including the second\n","# ['japan']\n","# 2. starting at the third element, up to but not including the fifth\n","# ['maldives', 'gabon']\n","# and then we concatenate those to ['japan', 'maldives', 'gabon'].\n","\n","more_countries = countries + ['mexico', 'haiti']\n","print(more_countries)\n","# By concatenating two lists, we create a new, longer list,\n","# with all elements of the original lists at the same level.\n","\n","countries.append(['mexico', 'haiti'])\n","print(countries)\n","# Appending a list to another list makes the former\n","# a nested single element of the latter."],"metadata":{"id":"KMUxwcSqPlU1","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1680783691341,"user_tz":-120,"elapsed":8,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"523705a3-8ae0-47ab-ace7-e48ed326a404"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["japan\n","maldives\n","['japan', 'maldives', 'gabon']\n","['japan', 'hungary', 'maldives', 'gabon', 'bhutan', 'mexico', 'haiti']\n","['japan', 'hungary', 'maldives', 'gabon', 'bhutan', ['mexico', 'haiti']]\n"]}]},{"cell_type":"markdown","source":["2. Transform the list below into `['jasmin', 'john', 'ravi']` in one line of code. \n","\n"],"metadata":{"id":"TyebsOIpU6hv"}},{"cell_type":"code","source":["students = ['jasmin', 'ravi', 'john']\n","\n","# Option 1: modify students in place by\n","# reassinging a slice of it.\n","students[1:3] = [students[2], students[1]]\n","\n","# Option 2: create a new list based on students.\n","new_students = students[:1] + students[2:] + students[1:2]\n","\n","# If you figured out stepped slices in the bonus exercise,\n","# you have a few more interesting options:\n","\n","# Variant of option 1\n","students[1:3] = students[:-3:-1]\n","\n","# Variant of option 2\n","new_students = students[:1] + students[:-3:-1]"],"metadata":{"id":"H8o6vsHKVKoq"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["3. For each of the print statements below, what do you expect is printed? Run the lines to check predictions."],"metadata":{"id":"HMU5X7XFWbCw"}},{"cell_type":"code","source":["random_fruit = 'pineapple'\n","fruits = ['apple', 'pear', random_fruit]\n","print(fruits)\n","# ['apple', 'pear', 'pineapple']\n","\n","random_fruit = 'blueberry'\n","print(fruits)\n","# Still the same. The value of random_fruit was\n","# copied into fruits on line 2, but there is no\n","# permanent tie between the variables.\n","\n","random_veggie = ['brussel sprouts']\n","veggies = ['broccoli', 'green beans', random_veggie]\n","print(veggies)\n","# There is a subtle difference with lines 1-3 here:\n","# the last element of veggies is not a string, but\n","# a nested list with a single string as element.\n","\n","random_veggie.append('kale')\n","print(veggies)\n","# BOOM! Somehow, veggies changed along with the content\n","# of the random_veggie list. How can that be?\n","# The reason is that lists are values that can change\n","# by themselves. If we had reassigned random_veggie with\n","# a new value, similar to lines 6-7, we would not have\n","# seen it in veggies:\n","\n","random_veggie = 'pumpkin'\n","print(veggies)"],"metadata":{"id":"u_RWc8wBWgMT"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 4.2: Bonus\n","\n","Below we introduce another parameter in the list slice. Try to explain what it does."],"metadata":{"id":"3BfUO-jKS_u1"}},{"cell_type":"code","source":["countries = ['japan', 'hungary', 'maldives', 'gabon', 'bhutan']\n","\n","print(countries[0:5:1])\n","# This does not behave differently from countries[0:5].\n","# From this, you could deduce that the third parameter is 1\n","# by default.\n","\n","print(countries[0:5:2])\n","# This skips every second country.\n","\n","print(countries[-1::-1])\n","# This prints countries in reverse.\n","\n","print(countries[-1::-2])\n","# This prints countries in reverse, skipping every second element.\n","\n","# Conclusion: the third parameter sets the step distance, which\n","# defaults to 1. If you give Python a slice [BEGIN:END:STEP], it\n","# visits the indices as follows:\n","# 1. Set the index to BEGIN.\n","# 2. If (STEP < 0 and index not after END) \n","# or (STEP >= 0 and index not before END): stop.\n","# 3. Visit the index in the given list or other iterable.\n","# 4. Set the index to index + STEP.\n","# 5. Repeat from step 2."],"metadata":{"id":"Y9oxyQb7TIPI"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["The piece of code below is supposed to recognize \"fancy\" words: words that are longer than 5 characters, contain at least one copy of the letter 'a' and start with an uppercase. However, the code is broken. It does not recognize any of our fancy example words.\n","\n","1. Change the value of `word` into each of the examples in the comments on the first two lines and then run the code. See for yourself that the code considers none of the example words fancy. Try some other words as well.\n","3. Try to understand why the code is giving the wrong result. Can you come up with a word that the code does consider fancy?\n","4. Repair the code so that it gives the right result for all examples, and any other words that you come up with."],"metadata":{"id":"Mb6CvHt3CaA0"}},{"cell_type":"markdown","source":["> In step 2, you should find two reasons for failure which we highlight in code comments below. Once you understand these reasons, you should be able to construct words that the code does consider fancy: they must have length greater than 5, an uppercase letter in the *second* position, and a *lowercase* `'a'`. For example `'aRthur'`.\n","\n","> This exercise holds an important lesson: you need to fully understand why code is broken, before you can fix it!"],"metadata":{"id":"n8q0tzvRpzWz"}},{"cell_type":"code","source":["# fancy: Alhambra, Arthur, Jasmine, Turandot\n","# not so fancy: Jeep, paper, Python, Ada\n","word = 'Alhambra'\n","\n","# The first subcondition was entirely correct.\n","lengthy = len(word) > 5\n","\n","# The second subcondition did not take into account\n","# that the 'a' might be uppercase.\n","has_a = 'a' in word\n","# Fix for this subcondition:\n","has_a = 'a' in word or 'A' in word\n","\n","# The third subcondition used the wrong index: 1 instead of 0.\n","first_uppercase = 'A' <= word[1] <= 'Z'\n","# Fix for this subcondition:\n","first_uppercase = 'A' <= word[0] <= 'Z'\n","\n","# The condition as a whole was formulated correctly.\n","if lengthy and has_a and first_uppercase:\n"," print('The word is fancy')\n","else:\n"," print('The word is not so fancy')"],"metadata":{"id":"QQyGzsqCCe3o"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[5. Assertions](https://colab.research.google.com/drive/1Nv6vgkH2zjJes7LXUCVhsDwFOGCtTbHM) - [solutions](https://colab.research.google.com/drive/1tqjXsHnnJeEAivrxqRoOSW9eNESCwLIK)"],"metadata":{"id":"HiEWGB1V1W4U"}}]} \ No newline at end of file diff --git a/solutions/05 assertions solutions.ipynb b/solutions/05 assertions solutions.ipynb new file mode 100644 index 0000000..92f27ab --- /dev/null +++ b/solutions/05 assertions solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[{"file_id":"1Nv6vgkH2zjJes7LXUCVhsDwFOGCtTbHM","timestamp":1681202721640}],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 5: Assertions\n","\n","### Exercise solutions\n","\n","[5. Assertions](https://colab.research.google.com/drive/1Nv6vgkH2zjJes7LXUCVhsDwFOGCtTbHM)\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [4. Datastructures](https://colab.research.google.com/drive/1JxzmIzwcipnwFBntv0WZOlT-d2fUjoRF) - [solutions](https://colab.research.google.com/drive/1juOQFMlRmeVUfbKWy0wtZ9lWkSZmr2Gn)"],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## Exercise 5.1: Assertions\n","In each of the code blocks below, try to predict what will be the output, then run the code. If your guess was incorrect, try to figure out why the result is different. If your guess was correct, celebrate!"],"metadata":{"id":"m_FYfvXbbZXe"}},{"cell_type":"code","source":["assert True\n","# The assertion passes, so no output!"],"metadata":{"id":"ztDylwg9biL5","executionInfo":{"status":"ok","timestamp":1681309651463,"user_tz":-120,"elapsed":4,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}}},"execution_count":2,"outputs":[]},{"cell_type":"code","source":["assert False, \"The assertion fails because the value is False\""],"metadata":{"id":"0Uk4w2DBbxfD","colab":{"base_uri":"https://localhost:8080/","height":164},"executionInfo":{"status":"error","timestamp":1681309645640,"user_tz":-120,"elapsed":45,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"fd5ed9ba-c7ea-488a-b537-a6641517d2c0"},"execution_count":1,"outputs":[{"output_type":"error","ename":"AssertionError","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)","\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m\"The assertion fails because the value is False\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[0;31mAssertionError\u001b[0m: The assertion fails because the value is False"]}]},{"cell_type":"code","source":["assert \"True\"\n","\n","# You can think of assert as implicitly wrapping its argument in bool():\n","assert bool(\"True\")\n","# bool() converts anything that looks like \"empty\" or \"nothing\",\n","# such as the integer 0 (zero), None, the empty string and the empty list,\n","# to False, and everything else to True.\n","# Hence, the string \"True\" is converted to the boolean True, the assertion\n","# passes and there is no output."],"metadata":{"id":"orOWCpWVbzKf","executionInfo":{"status":"ok","timestamp":1681309654788,"user_tz":-120,"elapsed":874,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}}},"execution_count":3,"outputs":[]},{"cell_type":"code","source":["assert \"False\", \"The assertion fails because the value is False\"\n","# The string \"False\" is nonempty, so bool() converts it to True\n","# (which, yes, is very confusing!). Hence, the assertion passes\n","# and we see no output.\n","\n","# For comparison, the empty string results in a failing assertion:\n","assert bool(\"\"), \"The assertion fails because the value is False\"\n","# while a string with just a space passes:\n","assert bool(\" \"), \"The assertion fails because the value is False\""],"metadata":{"id":"F6NjZ7gOb05u","executionInfo":{"status":"ok","timestamp":1681310066688,"user_tz":-120,"elapsed":186,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}}},"execution_count":4,"outputs":[]},{"cell_type":"code","source":["assert 1\n","# bool(1) is True, so pass, so no output"],"metadata":{"id":"KB_YkNSIb2KT","executionInfo":{"status":"ok","timestamp":1681310068748,"user_tz":-120,"elapsed":309,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}}},"execution_count":5,"outputs":[]},{"cell_type":"code","source":["assert 1 == True, \"The number 1 is not True\"\n","# As we saw in module 2, 1 is indeed the same value as True"],"metadata":{"id":"1iUK81Nvb3Ri","executionInfo":{"status":"ok","timestamp":1681310100358,"user_tz":-120,"elapsed":191,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}}},"execution_count":7,"outputs":[]},{"cell_type":"code","source":["assert 0\n","# bool(0) is False, so fail, so we see an AssertionError.\n","# The AssertionError lacks a description because we did not\n","# provide one."],"metadata":{"id":"Tje6e-Jgb4rn","colab":{"base_uri":"https://localhost:8080/","height":164},"executionInfo":{"status":"error","timestamp":1681310102072,"user_tz":-120,"elapsed":10,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"2ffb1ccc-c2ce-4625-baea-c02403cdf947"},"execution_count":8,"outputs":[{"output_type":"error","ename":"AssertionError","evalue":"ignored","traceback":["\u001b[0;31m---------------------------------------------------------------------------\u001b[0m","\u001b[0;31mAssertionError\u001b[0m Traceback (most recent call last)","\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;32massert\u001b[0m \u001b[0;36m0\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m","\u001b[0;31mAssertionError\u001b[0m: "]}]},{"cell_type":"markdown","source":["## Exercise 5.2: Bonus - Test-driven development"],"metadata":{"id":"xgqh3r7Bcj_F"}},{"cell_type":"markdown","source":["In the code block below, change the value for `b`, and create an expression for `c` using `a` and `b` so that the assert statements succeed.\n"],"metadata":{"id":"TMWSMWg7dQqB"}},{"cell_type":"code","source":["# One possible solution\n","a = 12\n","b = 30\n","\n","c = b - a\n","\n","# Another possible solution\n","a = 12\n","b = 24\n","\n","c = (a + b) / 2\n","\n","assert a < b, 'a should be smaller than b'\n","assert a != b, 'a and b should not be equal'\n","assert c == 18, 'c should be 18'"],"metadata":{"id":"Q_yIUKSRdVjF","executionInfo":{"status":"ok","timestamp":1681310291983,"user_tz":-120,"elapsed":195,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}}},"execution_count":13,"outputs":[]},{"cell_type":"markdown","source":["In the code block below, change `students` so that it satisfies the `assert` statements. Also, add messages to the assert statements that explain what they test (in human language)."],"metadata":{"id":"1u_bBUpSfQr5"}},{"cell_type":"code","source":["students = ['bert', 'ernie', 'pino']\n","\n","\n","assert len(students) == 3, 'We need three student names'\n","assert students[0] < students[1] < students[2], 'The students must be sorted'"],"metadata":{"id":"UOp8NFVOfR6Z","executionInfo":{"status":"ok","timestamp":1681310446308,"user_tz":-120,"elapsed":428,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}}},"execution_count":14,"outputs":[]},{"cell_type":"markdown","source":["## Next module\n","\n","[6. Loops](https://colab.research.google.com/drive/1AZY4ESmsKKMvbalBDLlMrezAM5NzXXxV) - [solutions](https://colab.research.google.com/drive/1vy2gKHtBUMk60u2bmCYlcqmhIFpI2PI-)"],"metadata":{"id":"JaaguG-D3k_i"}}]} \ No newline at end of file diff --git a/solutions/06 Loops - Solutions.ipynb b/solutions/06 Loops - Solutions.ipynb new file mode 100644 index 0000000..e09e500 --- /dev/null +++ b/solutions/06 Loops - Solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# CDH course \"Programming in Python\"\n","\n","### Exercise Solutions\n","[Solutions](https://colab.research.google.com/drive/1vy2gKHtBUMk60u2bmCYlcqmhIFpI2PI-#scrollTo=fqMJHzNk5yXQ)\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [5. Assertions](https://colab.research.google.com/drive/1Nv6vgkH2zjJes7LXUCVhsDwFOGCtTbHM?usp=share_link) - [solutions](https://colab.research.google.com/drive/1tqjXsHnnJeEAivrxqRoOSW9eNESCwLIK)"],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## Exercise 1: basic `for` loops\n","\n","1. Make a small change to the following code block (copied from above), so that it prints the `full_text` only at the end, when it is complete."],"metadata":{"id":"0Gun_3cX1ey8"}},{"cell_type":"code","source":["words = ['A', 'very', 'short', 'sentence']\n","full_text = ''\n","\n","for word in words:\n"," full_text = full_text + word + ' '\n"," # print(word)\n","print(full_text)"],"metadata":{"id":"nMF8WE3F19HC","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681144232455,"user_tz":-120,"elapsed":5,"user":{"displayName":"Mees van Stiphout","userId":"10520931415894572279"}},"outputId":"7e9843ae-f3d5-43f1-b0a4-64a3c2c309c7"},"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["A\n","very\n","short\n","sentence\n","A very short sentence \n"]}]},{"cell_type":"markdown","source":["2. Using a `for` loop, create a copy of the list of fruits below that has the fruits in the reverse order. Change the contents of the list on the first line to check that your solution is general."],"metadata":{"id":"8zB10pLC2ZaT"}},{"cell_type":"code","source":["fruits = ['apricot', 'banana', 'cherry', 'date']\n","\n","# insert your code here\n","# SHOULD output ['date', 'cherry', 'banana', 'apricot']\n","\n","#solution 1:\n","reverse_fruits = []\n","for fruit in fruits[-1::-1]:\n"," reverse_fruits.append(fruit)\n","print(reverse_fruits)\n","\n","#solution 2:\n","reverse_fruits = []\n","for fruit in fruits:\n"," reverse_fruits = [fruit] + reverse_fruits\n","print(reverse_fruits)\n","\n","#solution 3:\n","reverse_fruits = []\n","for fruit in fruits:\n"," reverse_fruits[0:0] = [fruit]\n","print(reverse_fruits)\n","\n","#solution 4:\n","reverse_fruits = []\n","position = -1\n","for fruit in fruits:\n"," reverse_fruits.append(fruits[position])\n"," position = position - 1\n","print(reverse_fruits)\n","\n","#solution 5:\n","reverse_fruits = []\n","position = len(fruits) - 1\n","for fruit in fruits:\n"," reverse_fruits.append(fruits[position])\n"," position = position - 1\n","print(reverse_fruits)\n"],"metadata":{"id":"bAwZ_ipU28AY","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681311205916,"user_tz":-120,"elapsed":208,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"34d5cb4c-d675-413e-adb6-9d3f7bc41908"},"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["['date', 'cherry', 'banana', 'apricot']\n","['date', 'cherry', 'banana', 'apricot']\n","['date', 'cherry', 'banana', 'apricot']\n","['date', 'cherry', 'banana', 'apricot']\n","['date', 'cherry', 'banana', 'apricot']\n"]}]},{"cell_type":"markdown","source":["## Exercise 2: more loops"],"metadata":{"id":"-K0CvNkOLEYE"}},{"cell_type":"markdown","source":["1. The code block below is written to help you explore what kind of \"stuff\" comes out of `range` and `enumerate`. Read the code from top to bottom. What stands out to you? Why do you think it was written this way?"],"metadata":{"id":"Qj9LsMfw-RMT"}},{"cell_type":"markdown","source":["> Things that you might notice:\n","> \n","> - It is possible to call `range` with one, two or three arguments.\n","> - `enumerate` is always called with only one argument.\n","> - Some noticed that you can write the string `'pirate'` and pass it directly to `enumerate`, without storing the string in a variable first. This is a good observation, and it is possible with all values and functions in general!\n","> - The program is counting iterations. The variable `iteration_count` is initially set to `0`, incremented at every loop iteration and finally printed at the end.\n","> - When the `iteration_count` is greater than `2`, the loop does not print the current `value`. In other words, the program only prints the first two values in each iterable.\n","> - The program prints the type of the first value in the iterable only.\n","> \n","> Reasons:\n","> \n","> - All the various versions of `miracle` are there to illustrate the behavior of `range` and `enumerate`.\n","> - We print the type of the iterable as a whole at the start, so you can see what kind of value comes out of the call to `range` or `enumerate`.\n","> - We keep track of the number of iterations so you can see how many values are produced by the iterable. We could have used `enumerate` for this, but this would be confusing, since the behavior of `enumerate` itself is the topic of this exercise. Therefore, we use custom logic with the `iteration_count` variable instead.\n","> - We only print the first two values in the iterable because this is enough to see a pattern. If we printed all of them, it could potentially produce a lot of output.\n","> - We only print the type of the first value, on the assumption that all values in the iterable have the same type.\n","\n"],"metadata":{"id":"otBq-xEi-SiC"}},{"cell_type":"markdown","source":["2. Run the code block for each example value of `miracle`. Based on the results, describe in your own words what `range` and `enumerate` do."],"metadata":{"id":"EjmxzbeY-USj"}},{"cell_type":"markdown","source":["> Possible elements of a good answer for `range`:\n","> \n","> - If you pass only one value, this sets the exclusive end. It generates whole numbers from `0` (zero) up to but not including the end.\n","> - If you pass two values, the first sets the inclusive start and the second sets the exclusive end.\n","> - If you pass three values, the first sets the inclusive start, the second the exclusive end and the third a step size.\n","> - If you omit the step size (so you pass only one or two arguments), it defaults to `1`.\n","> - A negative step size causes the range to count \"backwards\" (from high numbers to low numbers).\n","> - You are not allowed to pass floats; the function only supports integers.\n","> \n","> Possible elements of a good answer for `enumerate`:\n","> \n","> - It requires another iterable as argument (we see a list, a string and a range in the examples).\n","> - The same values from the input iterable also appear in the output iterable, but wrapped in a tuple.\n","> - In the output iterable, every tuple has a numerical index in addition to the corresponding value from the input iterable.\n","> - The numerical index is the first element of the tuple, while the value is the second element.\n","> - The numerical indices start at `0` (zero).\n"],"metadata":{"id":"ZyllJHKCBtoy"}},{"cell_type":"code","source":["basket = ['apricot', 'banana', 'cherry', 'date']\n","\n","miracle = range(100)\n","# miracle = range(2, 11)\n","# miracle = range(2, 11, 3)\n","# miracle = range(11, 2, -2)\n","# miracle = range(0.1, 1.0, 0.1)\n","# miracle = enumerate(basket)\n","# miracle = enumerate('pirate')\n","# miracle = enumerate(range(10))\n","\n","print('type of miracle:', type(miracle))\n","\n","iteration_count = 0\n","for value in miracle:\n"," iteration_count = iteration_count + 1\n"," if iteration_count > 2:\n"," continue\n"," elif iteration_count == 1:\n"," print('type of first iteration:', type(value))\n"," print('value of current iteration:', value)\n","\n","print('number of iterations:', iteration_count)"],"metadata":{"id":"7gappYcLOrsu","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681311440820,"user_tz":-120,"elapsed":189,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"039590e8-bbae-4ad4-c622-95110c3e9a8d"},"execution_count":3,"outputs":[{"output_type":"stream","name":"stdout","text":["type of miracle: \n","type of first iteration: \n","value of current iteration: 0\n","value of current iteration: 1\n","number of iterations: 100\n"]}]},{"cell_type":"markdown","source":["3. The `input` function, demonstrated below, lets you ask the human user for a string and then store it in a variable. Write a program that keeps asking the user for words until the word is `'stop'`. For each word, report to the user how many characters it contains."],"metadata":{"id":"2Haq4E95bN6T"}},{"cell_type":"code","source":["#solution 1:\n","word = ''\n","while word != 'stop':\n"," word = input('Please give me a word: ')\n"," print('you wrote', word)\n"," print('the length is', len(word))\n","\n","#solution 2:\n","while True:\n"," word = input('Please give me a word: ')\n"," if word == 'stop':\n"," break\n"," print('you wrote', word)\n"," print('the length is', len(word))"],"metadata":{"id":"0k_YQbBccyC_","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681313320536,"user_tz":-120,"elapsed":6762,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"ef5102e8-4248-47f3-a59c-87a5958b41db"},"execution_count":6,"outputs":[{"name":"stdout","output_type":"stream","text":["Please give me a word: banana\n","you wrote banana\n","the length is 6\n","Please give me a word: cherry\n","you wrote cherry\n","the length is 6\n","Please give me a word: stop\n"]}]},{"cell_type":"markdown","source":["4. *FizzBuzz part 2* (advanced). Look back at your solution to exercise 5.3 from day 1 (*FizzBuzz part 1*). Now write a program that does the following: for each integer from `1` up to and including `100`, print `Fizz`, `Buzz`, `FizzBuzz` or the number itself, following the same rules as before. Separate the words and numbers by commas. Add a newline after every tenth number, so you print ten lines in total. The first line should start like `1, 2, Fizz, 4, Buzz, Fizz, ...` and the last line should be `91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz, `."],"metadata":{"id":"uyqbuhKsUlhG"}},{"cell_type":"code","source":["# Variant 1\n","\n","for n in range(1, 101):\n"," if n % 15 == 0:\n"," print('FizzBuzz', end=', ')\n"," elif n % 3 == 0:\n"," print('Fizz', end=', ')\n"," elif n % 5 == 0:\n"," print('Buzz', end=', ')\n"," else:\n"," print(n, end=', ')\n"," if n % 10 == 0:\n"," print()\n","\n","# Variant 2\n","\n","numbers = range(1, 101)\n","for number in numbers:\n"," if not number % 15:\n"," output = 'FizzBuzz'\n"," elif not number % 3:\n"," output = 'Fizz'\n"," elif not number % 5:\n"," output = 'Buzz'\n"," else:\n"," output = number\n"," if not number % 10:\n"," print(output, end=',\\n')\n"," else:\n"," print(output, end=', ')\n"],"metadata":{"id":"BUeMXIQXaKna","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681313256562,"user_tz":-120,"elapsed":1068,"user":{"displayName":"Julian Gonggrijp","userId":"06467962548183964912"}},"outputId":"0c5ddcc6-e2d0-40bb-9456-892f751320b6"},"execution_count":5,"outputs":[{"output_type":"stream","name":"stdout","text":["1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz, Buzz,\n","11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19, Buzz,\n","Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29, FizzBuzz,\n","31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz, Buzz,\n","41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49, Buzz,\n","Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59, FizzBuzz,\n","61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz, Buzz,\n","71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79, Buzz,\n","Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89, FizzBuzz,\n","91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz, Buzz,\n"]}]},{"cell_type":"markdown","source":["## Next module\n","\n","[7. Functions](https://colab.research.google.com/drive/1APhegD_KpLRFn5bC6Ater2wFpT8_Opfr)"],"metadata":{"id":"0eGibfk04LI0"}}]} \ No newline at end of file diff --git a/solutions/07 Functions solutions.ipynb b/solutions/07 Functions solutions.ipynb new file mode 100644 index 0000000..c4f3bfe --- /dev/null +++ b/solutions/07 Functions solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[{"file_id":"1APhegD_KpLRFn5bC6Ater2wFpT8_Opfr","timestamp":1681904575537}],"toc_visible":true},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Module 7: Functions\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [6. Loops](https://colab.research.google.com/drive/1AZY4ESmsKKMvbalBDLlMrezAM5NzXXxV)\n","\n","### This module\n","\n","- Storing code in a variable so you can reuse it.\n","- Being explicit about the purpose of your code."],"metadata":{"id":"fqMJHzNk5yXQ"}},{"cell_type":"markdown","source":["## Exercise 7.1: functions"],"metadata":{"id":"aPFGhEVz40JP"}},{"cell_type":"markdown","source":["1. We have seen several standard functions during the course, such as `ord` and `len`. List as many as you can from memory. Try to list the types of the parameters and return values of each function as well. Do any of these functions have side effects?"],"metadata":{"id":"hfcz-cSEKZWW"}},{"cell_type":"markdown","source":["Some examples:\n","- `ord`: Has 1 parameter: a string of 1 character. The return value is an integer. No side effects.\n","- `len`: Has 1 parameter: a list, tuple or other iterable. The return value is an integer. No side effects.\n","- `input`: Has 1 optional parameter `prompt`, which should be a string. The function has a side effect, which is to wait for the user to type something. Its return value is a string (namely the text that you have entered)."],"metadata":{"id":"ZG0lv6MhVP8L"}},{"cell_type":"markdown","source":["2. For exercise purposes, code in the following blocks may call `print` inside a function and omit a docstring. Predict the output, then run the code to see whether your prediction was right. Try to explain any discrepancies."],"metadata":{"id":"BUnMsiUzKbws"}},{"cell_type":"code","source":["def greet(name):\n"," return 'Hello, ' + name + '!'\n","\n","print(greet('Berit'))"],"metadata":{"id":"_3va9jT5O0H7","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681904959646,"user_tz":-120,"elapsed":366,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"0187c43c-58c4-45c6-935f-a22d2bf5c864"},"execution_count":2,"outputs":[{"output_type":"stream","name":"stdout","text":["Hello, Berit!\n"]}]},{"cell_type":"code","source":["name = 'Luka'\n","\n","def exclaim(name):\n"," print(name + '!')\n","\n","# nothing happens: we have created a function but we haven't called it!"],"metadata":{"id":"vdTIwoGxM_JV","executionInfo":{"status":"ok","timestamp":1681905000500,"user_tz":-120,"elapsed":5,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":4,"outputs":[]},{"cell_type":"code","source":["def false():\n"," return True\n","\n","print(False)\n","\n","# we are printing the literal value `False`, which is not the same as our function `false` (all lower case)\n","# Capitalisation matters in python!"],"metadata":{"id":"30fv8SAMOblV","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681905065618,"user_tz":-120,"elapsed":5,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"99fd2054-9609-4646-c321-2f4513b6cc5f"},"execution_count":5,"outputs":[{"output_type":"stream","name":"stdout","text":["False\n"]}]},{"cell_type":"code","source":["length = 5\n","width = 2\n","\n","def calculate_area():\n"," area = length * width\n","\n","print(calculate_area())\n","\n","# calculate_area calculates something, but it does not make a return statement.\n","# So the returned value of `calculate_area()` is None"],"metadata":{"id":"ongrNaZFNNmV","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681905150776,"user_tz":-120,"elapsed":13,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"45d7e513-7157-4c54-ab92-c4380fb59f02"},"execution_count":8,"outputs":[{"output_type":"stream","name":"stdout","text":["None\n"]}]},{"cell_type":"code","source":["def question(name):\n"," return 'Who is ' + name + '?'\n","\n","question('Jelte')"],"metadata":{"id":"MSkOCMMyNoUO","colab":{"base_uri":"https://localhost:8080/","height":35},"executionInfo":{"status":"ok","timestamp":1681905166543,"user_tz":-120,"elapsed":378,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"a9fca128-9415-4ef7-97cb-1546e36f67db"},"execution_count":9,"outputs":[{"output_type":"execute_result","data":{"text/plain":["'Who is Jelte?'"],"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"}},"metadata":{},"execution_count":9}]},{"cell_type":"code","source":["def add(left, right):\n"," return left + right\n","\n","print(add('sweet', 'addition') * add(1, 1))\n","\n","# add('sweet', 'addition') will return 'sweet' + addition', which concatenates\n","# the strings to 'sweetaddition'\n","\n","# add(1, 1) becomes 1 + 1, so 2\n","\n","# then 'sweetaddition' * 2 means \"repeat 'sweetaddition' twice\"\n","# hence 'sweetadditionsweetaddition'"],"metadata":{"id":"72DDRhD5OQ0g","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681905320174,"user_tz":-120,"elapsed":6,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"3cd844dd-d4ca-4418-db9e-8c3065a9d3b7"},"execution_count":11,"outputs":[{"output_type":"stream","name":"stdout","text":["sweetadditionsweetaddition\n"]}]},{"cell_type":"code","source":["# I've added some comments to each print statement, to explain what's happening and in what order.\n","\n","name = 'Julian'\n","age = 36\n","\n","print(name) # 1st print\n","\n","# make a function. the code in the body will not be executed until we call the function below.\n","def example(name):\n"," print(name) # 5th print: we are printing the *parameter* `name` that we\n"," # passed on to the function when we called it, which is 'Jelte'. There is a \n"," # global parameter which is also called `name` (with value 'Julian'), but\n"," # the parameter takes precedence.\n"," \n"," name = 'Berit' # update the value of the *parameter*\n","\n"," print(name) # 6th print: print the new value of the parameter\n","\n"," print(age) # 7th print: print age. There is no `age` variable specific\n"," # to the function, so we refer to the global variable (36)\n","\n","print(name) # 2nd print: name is unchanged. `name = 'Berit'` was part of the\n","# function body, it's not yet executed\n","\n","print(example) # 3rd print: we are printing the function itself, not the\n","# returned value!\n","\n","print(name) # 4th print: name is still unchanged.\n","\n","example('Jelte') # we are running the function here, and now we will execute the\n","# print statements within its body\n","\n","print(name) # 8th print: the function `example` did some stuff with its\n","# parameter called name, but did not do anything with the global variable name.\n","# So `name` is still 'Julian'\n","\n","print(age) # 9th print\n","\n"],"metadata":{"id":"L0GlJecf8ntf","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681906368916,"user_tz":-120,"elapsed":360,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"893d9d77-378d-4d5c-8a17-fa14fdbd0322"},"execution_count":15,"outputs":[{"output_type":"stream","name":"stdout","text":["Julian\n","Julian\n","\n","Julian\n","Jelte\n","Berit\n","36\n","Julian\n","36\n"]}]},{"cell_type":"markdown","source":["3. In each of the following code blocks, write a docstring for the function, then add assertions and run the block to check that your documentation is correct."],"metadata":{"id":"Rwvwlpp0-Hrt"}},{"cell_type":"code","source":["def odd(number):\n"," '''\n"," Checks whether a number is odd\n","\n"," Input should be an integer. Output is a boolean, True if the number is not\n"," divisible by two.\n"," '''\n"," return number % 2 == 1\n","\n","assert odd(1) == True\n","assert odd(6) == False\n","assert odd(0) == False"],"metadata":{"id":"ajcRnvzQQ9c5","executionInfo":{"status":"ok","timestamp":1681906464925,"user_tz":-120,"elapsed":366,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":19,"outputs":[]},{"cell_type":"code","source":["def magic(word):\n"," '''\n"," Checks that the input is a nonempty string and starts with a capital letter.\n","\n"," Input can be of any type: anything other than a string will return False.\n"," For strings, checks that the string is not empty and the first character\n"," is an uppercase latin character. \n"," '''\n"," if not word or type(word) != str:\n"," return False\n"," if 'A' <= word[0] <= 'Z':\n"," return True\n"," return False\n","\n","assert magic(123) == False\n","assert magic('Hello python programmers!') == True\n","assert magic('python python python') == False\n","assert magic('🤔') == False\n","assert magic('') == False"],"metadata":{"id":"giU_bIKrRME4","executionInfo":{"status":"ok","timestamp":1681906766119,"user_tz":-120,"elapsed":393,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":23,"outputs":[]},{"cell_type":"code","source":["def join_commas(words):\n"," '''\n"," Joins a iterable of strings into a single string, with ', ' between each item.\n","\n"," Input should be an iterable of strings with at least 1 item.\n"," '''\n"," first, *rest = list(words)\n"," text = first\n"," for word in rest:\n"," text = text + ', ' + word\n"," return text\n","\n","assert join_commas(['a', 'b', 'c']) == 'a, b, c'\n","assert join_commas(['a']) == 'a'\n","assert join_commas(('a', 'b', 'c')) == 'a, b, c'"],"metadata":{"id":"pAChbRWn-SKS","executionInfo":{"status":"ok","timestamp":1681907208099,"user_tz":-120,"elapsed":8,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":28,"outputs":[]},{"cell_type":"markdown","source":["4. Write a function `is_number` that takes one argument. If the argument is a number, it should return `True`; otherwise, it should return `False`. Make sure to include a docstring!"],"metadata":{"id":"mc9RtAeATiHw"}},{"cell_type":"code","source":["# Your definition of is_number here\n","\n","def is_number(value):\n"," '''\n"," Checks if the input is a number (int or float)\n"," '''\n","\n"," number_types = [int, float]\n"," return type(value) in number_types\n","\n","# The following lines will check your solution (no output is good)\n","assert is_number(0)\n","assert is_number(10)\n","assert is_number(0.5)\n","assert is_number(8 / 5)\n","assert not is_number(None)\n","assert not is_number('dear')\n","assert not is_number('123')"],"metadata":{"id":"Ap33-rF-UbsB","executionInfo":{"status":"ok","timestamp":1681907269669,"user_tz":-120,"elapsed":399,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":29,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.2: bonus"],"metadata":{"id":"apA7o120TYRl"}},{"cell_type":"markdown","source":["1. Write a function `last_a_index` that, given a string, returns the **last** index of the letter `'a'` in the string. If there is no `'a'` in the string, the function should return `None`."],"metadata":{"id":"nM43w3VlB3-O"}},{"cell_type":"code","source":["# Define last_a_index here\n","\n","def last_a_index(text):\n"," '''\n"," Gives the index of the last 'a' in the string.\n","\n"," If there is no 'a' in the string, returns None\n"," '''\n","\n"," a_index = None\n","\n"," for (index, character) in enumerate(text):\n"," if character == 'a':\n"," a_index = index\n"," \n"," return a_index\n","\n","assert last_a_index('banana') == 5\n","assert last_a_index('cherry') == None\n","assert last_a_index('Once upon a time, there was a dragon') == 32"],"metadata":{"id":"I5s4_a53ENJC","executionInfo":{"status":"ok","timestamp":1681907469796,"user_tz":-120,"elapsed":10,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":32,"outputs":[]},{"cell_type":"markdown","source":["2. Write a function `replace` with three string arguments: `text`, `query` and `replacement`. It should return a copy of `text` in which all occurrences of `query` are replaced by `replacement`. For example, `replace('small', 'a', 'e')` should return `'smell'`. You may assume that `query` is always a single character. For an additional challenge, you can try to also handle multi-character query strings. For ultimate challenge, try to think of a way to handle the empty string!"],"metadata":{"id":"z4z3-dOaVROx"}},{"cell_type":"code","source":["# Define replace here\n","\n","# solution one: does not work with multi-character strings\n","def replace(text, query, replacement):\n"," '''\n"," Replace each occurence of a character in a string\n"," \n"," Input:\n"," - text: a string in which you want to replace something\n"," - query: the character you wish to replace\n"," - replacement: the string that should replace `query`\n"," '''\n","\n"," replaced = ''\n","\n"," for character in text:\n"," if character == query:\n"," replaced = replaced + replacement\n"," else:\n"," replaced = replaced + character\n"," \n"," return replaced\n","\n","assert replace('small', 'a', 'e') == 'smell'\n","assert replace('banana', 'a', 'o') == 'bonono'\n","assert replace('cherry', 'a', 'x') == 'cherry'"],"metadata":{"id":"kyQwfz-mYvfW","executionInfo":{"status":"ok","timestamp":1681907653952,"user_tz":-120,"elapsed":2,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":34,"outputs":[]},{"cell_type":"code","source":["# solution 2: handle multi-character strings and empty strings\n","\n","# There no clear answer for what should happen in the case of empty strings!\n","# It's a question that does not really make sense: replace every insstance of\n","# nothing?\n","\n","# Here we just return `None` when query is empty. You could also return the\n","# original string.\n","\n","def replace(text, query, replacement):\n"," '''\n"," Replace each occurence of a substring in a string\n"," \n"," Input:\n"," - text: a string in which you want to replace something\n"," - query: the string you wish to replace\n"," - replacement: the string that should replace `query`\n","\n"," If the query is empty, returns None.\n"," '''\n","\n"," if not query:\n"," return None\n"," \n"," size = len(query)\n"," new_text = '' # where we build our new text\n"," position = 0 # our position as we move through the text\n","\n"," while position < len(text):\n"," possible_match = text[position:position+size] # slice of text from here, the same size as the query\n"," if possible_match == query: #if this matches...\n"," new_text += replacement # put the replacement in our new string\n"," position += size # and skip ahead until after this slice\n"," else:\n"," # if it doesn't match, move ahead by one character\n"," new_text += text[position]\n"," position += 1\n"," \n"," return new_text\n"," \n","\n","assert replace('small', 'a', 'e') == 'smell'\n","assert replace('banana', 'a', 'o') == 'bonono'\n","assert replace('cherry', 'a', 'x') == 'cherry'\n","assert replace('small', '', '?') == None\n","assert replace('banana', 'an', 'ab') == 'bababa'\n","assert replace('banana', 'banana', 'apple') == 'apple' \n","assert replace('banana', 'e', 'o') == 'banana'"],"metadata":{"id":"2ajcWTx1gi2r","executionInfo":{"status":"ok","timestamp":1681908669621,"user_tz":-120,"elapsed":350,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":41,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.3: function tricks"],"metadata":{"id":"1xUD2ZNjcqEZ"}},{"cell_type":"markdown","source":["1. In each of the code blocks below, predict the output, check your prediction by running the code, and try to explain any surprises."],"metadata":{"id":"hxRC5Nx-cyM4"}},{"cell_type":"code","source":["def welcome(name=None):\n"," if name is None:\n"," return 'Welcome to my office. How can I help you?'\n"," return 'Please make yourself at home, ' + name + '!'\n","\n","print(welcome()) # default option\n","print(welcome('Mees'))"],"metadata":{"id":"HPxio0q6c-M9","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681908707519,"user_tz":-120,"elapsed":392,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"8542c5de-15ae-4841-b438-1211d999241f"},"execution_count":43,"outputs":[{"output_type":"stream","name":"stdout","text":["Welcome to my office. How can I help you?\n","Please make yourself at home, Mees!\n"]}]},{"cell_type":"code","source":["def table(number):\n"," return number, number * 2, number * 3 #return three numbers\n","\n","first, second, third = table(5) # table(5) is (5, 10, 15) ; unpack these into three variables\n","\n","print(third) #print the third"],"metadata":{"id":"NxXqK4ROdxva","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681908774383,"user_tz":-120,"elapsed":6,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"08744e41-cbe2-4c45-9566-9174466aaf88"},"execution_count":45,"outputs":[{"output_type":"stream","name":"stdout","text":["15\n"]}]},{"cell_type":"code","source":["def contact(name, job):\n"," return 'For ' + job + ', contact ' + name + '.'\n","\n","contact_line = contact(job='naming', name='Job') # we use named arguments, so we can supply `name` and `job` in any order\n","print(contact_line)"],"metadata":{"id":"EVCf3w9qfBCU","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681908875617,"user_tz":-120,"elapsed":14,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"8883c815-c80f-4f0a-f185-4d6d935e54cb"},"execution_count":48,"outputs":[{"output_type":"stream","name":"stdout","text":["For naming, contact Job.\n"]}]},{"cell_type":"code","source":["def exclaim(name):\n"," return name + '!'\n","\n","def request(name):\n"," return name + '?'\n","\n","def tell(how):\n"," return 'As my mother would say: ' + how('Julian')\n","\n","print(tell(request))\n","\n","# tell(request) will return `'As my mother would say: ' + how('Julian')`\n","# `how` is whatever we pass on as the argument to `tell`, in this case the function `request`\n","# so we can fill in `how('Julian')` as `request('Julian')`\n","# now we can look at the body of `request` to see what it does (it puts a\n","# question mark behind the name)"],"metadata":{"id":"OUSpe-hPl6-G","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681909054548,"user_tz":-120,"elapsed":4,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"fa03386e-6570-43ce-a65b-424d5cbfb193"},"execution_count":50,"outputs":[{"output_type":"stream","name":"stdout","text":["As my mother would say: Julian?\n"]}]},{"cell_type":"code","source":["def make_enumerate(separator):\n"," def enumerate(items):\n"," if not len(items):\n"," return ''\n"," result = items[0]\n"," for item in items[1:]:\n"," result = result + separator + item\n"," return result\n"," return enumerate\n","\n","with_semicolon = make_enumerate('; ')\n","fruits = with_semicolon(['apricot', 'banana', 'cherry'])\n","print(fruits)\n","\n","# with_semicolon is the output of make_enumerate: another function.\n","# This function takes a list of strings as input and joins them with a semicolon\n","# between them. we can then call `with_semicolon` on the list of fruits."],"metadata":{"id":"uSN17qnvmoWv","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681909174217,"user_tz":-120,"elapsed":9,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"f36d7049-e723-4036-e0b3-4b48a9b2103f"},"execution_count":52,"outputs":[{"output_type":"stream","name":"stdout","text":["apricot; banana; cherry\n"]}]},{"cell_type":"markdown","source":["2. In each of the following code blocks, something is missing in the function definition. Add the missing element."],"metadata":{"id":"CKma4p6Egkwb"}},{"cell_type":"code","source":["def combine(left, right):\n"," \"\"\" Compute the sum and the product of the arguments. \"\"\"\n"," sum = left + right\n"," product = left * right\n"," return sum, product #return both the sum and the product\n","\n","assert combine(2, 3) == (5, 6)"],"metadata":{"id":"SaygnjMygwNF","executionInfo":{"status":"ok","timestamp":1681909191045,"user_tz":-120,"elapsed":6,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":53,"outputs":[]},{"cell_type":"code","source":["def announce_time(hour, minute=0): # minute should be optional, so we add a default value.\n"," \"\"\" Announce the time in a speaking clock manner. \"\"\"\n"," if minute < 10:\n"," minute = '0' + str(minute)\n"," time = str(hour) + ':' + str(minute)\n"," return 'At the next beep, the time will be ' + time + '. BEEP!'\n","\n","assert announce_time(12) == 'At the next beep, the time will be 12:00. BEEP!'"],"metadata":{"id":"GqIgTcG6hMuG","executionInfo":{"status":"ok","timestamp":1681909211878,"user_tz":-120,"elapsed":6,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":55,"outputs":[]},{"cell_type":"code","source":["def echo(value):\n"," print(value)\n"," return value\n","\n","assert echo('holiday') == 'holiday'"],"metadata":{"id":"nH77gJdOkS5b","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681909264360,"user_tz":-120,"elapsed":395,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"f70a5f41-1916-4deb-da38-248ea056a749"},"execution_count":56,"outputs":[{"output_type":"stream","name":"stdout","text":["holiday\n"]}]},{"cell_type":"markdown","source":["3. In the following code block, write a function `month`, which returns a string name for given numeric month. Month `1` is `'January'` and month `12` is `December`. When no argument is passed, it should default to the current month. **Tip:** you can avoid writing a big `if`/`elif`/`else` tree by using a list of month names and using the month number as a list index."],"metadata":{"id":"YG5XrO1PoIJx"}},{"cell_type":"code","source":["# You may pretend that it is forever April\n","current_month = 4\n","\n","months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']\n","\n","def month(number=current_month):\n"," '''\n"," Return the name of a month based on an number.\n","\n"," Input should be an integer between 1 and 12. Returns None if this is not the case.\n"," If no month number is given, defaults to April.\n","\n"," Returns a string with the name of the Month.\n"," '''\n","\n"," if type(number) is not int or number < 1 or number > 12:\n"," return None\n","\n"," index = number - 1\n"," return months[index]\n","\n","# Your definition of month here\n","\n","assert month(3) == 'March'\n","assert month(4) == 'April'\n","assert month(11) == 'November'\n","assert month() == 'April'"],"metadata":{"id":"TnuU_I0Tq9wQ","executionInfo":{"status":"ok","timestamp":1681911393494,"user_tz":-120,"elapsed":662,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":73,"outputs":[]},{"cell_type":"markdown","source":["4. In the following code block, write a function `weekday`, which is analogous to `month` in the previous exercise. Day `1` is `'Monday'` while day `0` and day `7` are both `'Sunday'`. Can you avoid writing the string `'Sunday'` twice in your code?"],"metadata":{"id":"WuRrElhUsD40"}},{"cell_type":"code","source":["# You may pretend it is forever Tuesday\n","current_weekday = 2\n","\n","weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']\n","\n","def weekday(number=current_weekday):\n"," '''\n"," Return the name of a weekday based on an number.\n","\n"," Input should be an integer between 0 and 7. Returns None if this is not the case.\n"," If no weekday number is given, defaults to Tuesday.\n","\n"," Returns a string with the name of the weekday. Day 1 is 'Monday' while day 0\n"," and day 7 are both 'Sunday'.\n"," '''\n"," if type(number) is not int or number < 0 or number > 7:\n"," return None\n"," \n"," index = (number - 1) % 7\n"," return weekdays[index]\n","\n","# Your definition of weekday here\n","\n","assert weekday() == 'Tuesday'\n","assert weekday(0) == 'Sunday'\n","assert weekday(7) == 'Sunday'\n","assert weekday(4) == 'Thursday'"],"metadata":{"id":"WUGQqmJysrqS","executionInfo":{"status":"ok","timestamp":1681911394923,"user_tz":-120,"elapsed":8,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":74,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.4: bonus"],"metadata":{"id":"ZvfEq3NctoOo"}},{"cell_type":"markdown","source":["1. In exercises 7.3.4 and 7.3.5, where you just implemented `month` and `weekday`, your code was likely very similar. How could you implement both functions without repeating yourself? Check your solution with assertions."],"metadata":{"id":"8au2fNRutw8i"}},{"cell_type":"code","source":["def make_namer(names, default):\n"," '''\n"," Make a function to give names (months, weekdays, etc) based on a number.\n","\n"," Input:\n"," - A list of names (strings)\n"," - A default input value for the function\n","\n"," Returns a function that takes a number and returns the corresponding name.\n"," 1 is the first list in the name, etc.\n"," '''\n"," size = len(names)\n","\n"," def name(number=default):\n"," '''\n"," Gives the name corresponding to a number\n"," '''\n"," if type(number) is not int or number < 0 or number > size:\n"," return None\n"," \n"," index = (number - 1) % size\n"," return names[index]\n"," \n"," return name\n","\n","# now we can make our month and weekday functions based on make_namer\n","\n","current_month = 4\n","months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']\n","\n","current_weekday = 2\n","weekdays = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']\n","\n","month = make_namer(months, current_month)\n","weekday = make_namer(weekdays, current_weekday)\n","\n","# repeat the assert statements above to show everything still works\n","\n","assert month(3) == 'March'\n","assert month(4) == 'April'\n","assert month(11) == 'November'\n","assert month() == 'April'\n","\n","assert weekday() == 'Tuesday'\n","assert weekday(0) == 'Sunday'\n","assert weekday(7) == 'Sunday'\n","assert weekday(4) == 'Thursday'"],"metadata":{"id":"JFhOX_Z5uVfC","executionInfo":{"status":"ok","timestamp":1681911460720,"user_tz":-120,"elapsed":444,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":78,"outputs":[]},{"cell_type":"markdown","source":["2. Write a function `create_date_format`, which takes two arguments that determine how a date should be displayed. The first argument is function that transforms a weekday number to a string suitable for display, the second argument is a function that transforms a month number. Both arguments default to just displaying the number as-is. `create_date_format` returns a new function. The latter function takes any date defined by a year, month, day and weekday, and returns a string suitable for displaying that date as a whole."],"metadata":{"id":"Gx54DrgJuWKg"}},{"cell_type":"code","source":["# For this code block, you need to have `month` and `weekday`\n","# in your runtime from previous exercises.\n","\n","def create_date_format(weekday_formatter=str, month_formatter=str):\n"," '''\n"," Creates a function that formats dates.\n","\n"," Input:\n"," - weekday_formatter: a function that converts the day of the week (number) to a string\n"," - month_formatter: a function that converts the month (number) to a string\n","\n"," If these functions are not supplied, the month and day are shown as-is.\n","\n"," Output: A function that takes integers for the year, month, day of the\n"," month, and day of the week, and returns a string with the formatted date.\n"," '''\n","\n"," def format_date(year, month, day_of_month, day_of_week):\n"," '''\n"," Format a date in a nice string.\n"," '''\n","\n"," day_string = weekday_formatter(day_of_week)\n"," month_string = month_formatter(month)\n","\n"," nice_string = day_string + ', ' + month_string + ' ' + str(day_of_month) + ', ' + str(year)\n"," return nice_string\n"," \n"," return format_date\n","\n","# Your definition of create_date_format here\n","\n","wordy_format = create_date_format(weekday, month)\n","cryptic_format = create_date_format()\n","\n","assert wordy_format(2023, 4, 11, 2) == 'Tuesday, April 11, 2023'\n","assert cryptic_format(2023, 4, 11, 2) == '2, 4 11, 2023'"],"metadata":{"id":"0KyXFHEWwZ45","executionInfo":{"status":"ok","timestamp":1681912144802,"user_tz":-120,"elapsed":9,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":80,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 7.5: ultimate FizzBuzz (more bonus)\n","\n","1. Write two functions `fizz(number)` and `buzz(number)`. If `number` is divisible by 3, `fizz` should return the string `'Fizz'`; otherwise, it should return the empty string `''`. `buzz` should work like `fizz`, but for divisibility by 5 and the string `'Buzz'`."],"metadata":{"id":"b-p6Ct5_0I-x"}},{"cell_type":"code","source":["# Your solution here\n","\n","def fizz(number):\n"," '''\n"," Returns 'Fizz' if a number is divisible by 3, otherwise the empty string\n"," '''\n","\n"," if number % 3 == 0:\n"," return 'Fizz'\n"," else:\n"," return ''\n","\n","def buzz(number):\n"," '''\n"," Returns 'Buzz' if a number is divisible by 5, otherwise the empty string\n"," '''\n","\n"," if number % 5 == 0:\n"," return 'Buzz'\n"," else:\n"," return ''\n","\n","for number in [1, 2, 4, 5, 7, 8, 10, 11, 13, 14]:\n"," assert fizz(number) == '', str(number) + ' is not divisible by 3'\n","for number in [3, 6, 9, 12, 15, 18, 21, 24, 27]:\n"," assert fizz(number) == 'Fizz', str(number) + ' is divisible by 3'\n","for number in [1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14]:\n"," assert buzz(number) == '', str(number) + ' is not divisible by 5'\n","for number in [5, 10, 15, 20, 25, 30, 35, 40]:\n"," assert buzz(number) == 'Buzz', str(number) + ' is divisible by 5'"],"metadata":{"id":"407dPPK966R9","executionInfo":{"status":"ok","timestamp":1681912282529,"user_tz":-120,"elapsed":11,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":81,"outputs":[]},{"cell_type":"markdown","source":["2. Using your functions `fizz` and `buzz` from step 1, write the function `fizzbuzz(number)`, which implements the well-known rules from before, but with a slight **twist**:\n"," - If the number is divisible by 3 and 5, return `'FizzBuzz'`.\n"," - If the number is divisible by 3 but not by 5, return `'Fizz'`.\n"," - If the number is divisible by 5 but not by 3, return `'Buzz'`.\n"," - In all other cases, return the number itself **as a string**."],"metadata":{"id":"QCKc52-r9DrX"}},{"cell_type":"code","source":["# Your solution here\n","\n","def fizzbuzz(number):\n"," '''\n"," Turns a number into a fizzbuzz string.\n","\n"," - If the number is divisible by 3 and 5, returns 'FizzBuzz'.\n"," - If the number is divisible by 3 but not by 5, returns 'Fizz'.\n"," - If the number is divisible by 5 but not by 3, returns 'Buzz'.\n"," - In all other cases, returns the number itself as a string.\n"," '''\n","\n"," fizzbuzzed = fizz(number) + buzz(number)\n","\n"," if fizzbuzzed:\n"," return fizzbuzzed\n"," else:\n"," return str(number)\n","\n","for number in [1, 2, 4, 7, 8, 11, 13, 14]:\n"," assert fizzbuzz(number) == str(number), str(number)\n","for number in [3, 6, 9, 12, 18, 21, 24, 27]:\n"," assert fizzbuzz(number) == 'Fizz', str(number)\n","for number in [5, 10, 20, 25, 35, 40]:\n"," assert fizzbuzz(number) == 'Buzz', str(number)\n","for number in [15, 30, 45, 60, 75]:\n"," assert fizzbuzz(number) == 'FizzBuzz', str(number)"],"metadata":{"id":"NFADyIW3-7qt","executionInfo":{"status":"ok","timestamp":1681912437888,"user_tz":-120,"elapsed":3,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":83,"outputs":[]},{"cell_type":"markdown","source":["3. Write a function `chunk10(sequence)` that takes an iterable `sequence` and returns a list of lists: the first sublist contains the first ten elements of `sequence`, the second sublist contains the next ten elements of `sequence`, and so on. You may assume that the number of values in `sequence` is an exact multiple of 10."],"metadata":{"id":"o_3wq4agCCZH"}},{"cell_type":"code","source":["# Your solution here\n","\n","def chunk10(sequence):\n"," '''\n"," Splits a sequence into chunks of 10 elements\n"," '''\n","\n"," items = list(sequence)\n"," chunks = []\n","\n"," for position in range(0, len(sequence), 10):\n"," chunk = items[position: position + 10]\n"," chunks.append(chunk)\n"," \n"," return chunks\n","\n","assert chunk10('Jelte!!!!!') == [list('Jelte!!!!!')]\n","assert chunk10('Hey Julian, let us have lunch!') == [\n"," list('Hey Julian'),\n"," list(', let us h'),\n"," list('ave lunch!'),\n","]\n","assert chunk10(range(20)) == [list(range(10)), list(range(10, 20))]"],"metadata":{"id":"4c0A4kMfDdvt","executionInfo":{"status":"ok","timestamp":1681912825413,"user_tz":-120,"elapsed":8,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":88,"outputs":[]},{"cell_type":"markdown","source":["4. In step 1, you may have written definitions for `fizz` and `buzz` that look very similar to each other. Can you think of a way to avoid repeating the common elements?"],"metadata":{"id":"HBA4z4yVIhsn"}},{"cell_type":"code","source":["# Your solution here\n","\n","def fizz_or_buzz(number, message='Fizz', denominator=3):\n"," '''\n"," If number is divisible by denominator, return the message. Otherwise, return the empty string.\n"," '''\n"," if number % denominator == 0:\n"," return message\n"," else:\n"," return ''\n","\n","def fizz(number):\n"," return fizz_or_buzz(number)\n","\n","def buzz(number):\n"," return fizz_or_buzz(number, 'Buzz', 5)\n","\n","for number in [1, 2, 4, 5, 7, 8, 10, 11, 13, 14]:\n"," assert fizz(number) == '', str(number) + ' is not divisible by 3'\n","for number in [3, 6, 9, 12, 15, 18, 21, 24, 27]:\n"," assert fizz(number) == 'Fizz', str(number) + ' is divisible by 3'\n","for number in [1, 2, 3, 4, 6, 7, 8, 9, 11, 12, 13, 14]:\n"," assert buzz(number) == '', str(number) + ' is not divisible by 5'\n","for number in [5, 10, 15, 20, 25, 30, 35, 40]:\n"," assert buzz(number) == 'Buzz', str(number) + ' is divisible by 5'"],"metadata":{"id":"5g4BRdpLJLIc","executionInfo":{"status":"ok","timestamp":1681913046725,"user_tz":-120,"elapsed":9,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":91,"outputs":[]},{"cell_type":"markdown","source":["5. In exercise 7.1.3, you documented the function `join_commas`. We did not actually need to write that function, because it is built into Python, although it goes by the name `', '.join`. That notation also works with other strings, as we demonstrate below. We also remind you of `map`, which appeared in the lecture.

\n","Using these functions, as well as your own `fizzbuzz` from step 2 and your own `chunk10` from step 3, try to recreate (roughly) the same `FizzBuzz` output for the numbers 1 through 100 as in [exercise 6.2.4](https://colab.research.google.com/drive/1AZY4ESmsKKMvbalBDLlMrezAM5NzXXxV#scrollTo=uyqbuhKsUlhG), in as little code as you can."],"metadata":{"id":"BXzFYNGmPeO6"}},{"cell_type":"code","source":["# The following code is just for illustration.\n","# You do not need it in your solution.\n","fruits = ['apricot', 'banana', 'cherry']\n","print(', '.join(fruits))\n","print('\\n'.join(fruits))\n","numbers = list(range(10))\n","print(numbers)\n","strings = map(str, numbers)\n","print(list(strings))"],"metadata":{"id":"nDGUS26IMApD","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681913126765,"user_tz":-120,"elapsed":597,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"a78e10b9-f6d3-433f-f06c-d78ee65f65e4"},"execution_count":92,"outputs":[{"output_type":"stream","name":"stdout","text":["apricot, banana, cherry\n","apricot\n","banana\n","cherry\n","[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]\n","['0', '1', '2', '3', '4', '5', '6', '7', '8', '9']\n"]}]},{"cell_type":"code","source":["chunks = chunk10(range(100))\n","\n","for chunk in chunks:\n"," fizzbuzzed = map(fizzbuzz, chunk)\n"," print(', '.join(fizzbuzzed))"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"G87eCYM61P3a","executionInfo":{"status":"ok","timestamp":1681913265047,"user_tz":-120,"elapsed":12,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"23e8acb6-b66b-4871-e44a-8d37413bd1dc"},"execution_count":97,"outputs":[{"output_type":"stream","name":"stdout","text":["FizzBuzz, 1, 2, Fizz, 4, Buzz, Fizz, 7, 8, Fizz\n","Buzz, 11, Fizz, 13, 14, FizzBuzz, 16, 17, Fizz, 19\n","Buzz, Fizz, 22, 23, Fizz, Buzz, 26, Fizz, 28, 29\n","FizzBuzz, 31, 32, Fizz, 34, Buzz, Fizz, 37, 38, Fizz\n","Buzz, 41, Fizz, 43, 44, FizzBuzz, 46, 47, Fizz, 49\n","Buzz, Fizz, 52, 53, Fizz, Buzz, 56, Fizz, 58, 59\n","FizzBuzz, 61, 62, Fizz, 64, Buzz, Fizz, 67, 68, Fizz\n","Buzz, 71, Fizz, 73, 74, FizzBuzz, 76, 77, Fizz, 79\n","Buzz, Fizz, 82, 83, Fizz, Buzz, 86, Fizz, 88, 89\n","FizzBuzz, 91, 92, Fizz, 94, Buzz, Fizz, 97, 98, Fizz\n"]}]},{"cell_type":"markdown","source":["## Next module\n","\n","[8. Debugging](https://colab.research.google.com/drive/1yQskT6SyKvXtXewx5kCla2NOmasgP8Vi)"],"metadata":{"id":"Dntbbioh29xm"}}]} \ No newline at end of file diff --git a/solutions/09 string manipulation solutions.ipynb b/solutions/09 string manipulation solutions.ipynb new file mode 100644 index 0000000..34bc51d --- /dev/null +++ b/solutions/09 string manipulation solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"authorship_tag":"ABX9TyMi0JBuu4ELq/AQbr5Ws5LZ"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["## Exercise 9.1: String utilities\n","In each of the code blocks below, try to predict what will be printed, then run the code. If your guess was incorrect, try to figure out why the result is different. If your guess was correct, celebrate!"],"metadata":{"id":"5hIj-tbVleEq"}},{"cell_type":"code","source":["print(len('two'))"],"metadata":{"id":"02q-FgvVlxEj"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["A string is an iterable, the `len` is the amount of elements (characters)"],"metadata":{"id":"dZ8S2UialXke"}},{"cell_type":"code","source":["print(len(''))"],"metadata":{"id":"cvCrnnn9l-oH"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["An empty string (just like an empty list) has length of 0."],"metadata":{"id":"6vDjjHzIlcEY"}},{"cell_type":"code","source":["assert 'A' in 'Matilda'"],"metadata":{"id":"UlWWF0k7mA62"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Python is case sensitive. The capitalized `A` is not in the string."],"metadata":{"id":"K_daSu19liik"}},{"cell_type":"code","source":["assert 'A' in 'Matilda'.upper()"],"metadata":{"id":"Ui3gmvCNmHfB","executionInfo":{"status":"ok","timestamp":1681825113419,"user_tz":-120,"elapsed":356,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}}},"execution_count":10,"outputs":[]},{"cell_type":"markdown","source":["After capitalization of the whole string, `A` is in there."],"metadata":{"id":"i2bI-L6glqzO"}},{"cell_type":"code","source":["name = 'Matilda'\n","assert name.upper() == 'MATILDA'"],"metadata":{"id":"1tDEnzrumNdO","executionInfo":{"status":"ok","timestamp":1681825107244,"user_tz":-120,"elapsed":244,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}}},"execution_count":9,"outputs":[]},{"cell_type":"markdown","source":["This is the definition of `string.upper()`"],"metadata":{"id":"1pbJz3qElujM"}},{"cell_type":"code","source":["name = 'Matilda'\n","assert name.upper().lower() == 'Matilda'"],"metadata":{"id":"BUpf6LglmZ4n"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["This does not work. `Matilda.upper()` equals `'MATILDA'`. \n","\n","`'MATILDA'.lower()` equals `'matilda'`. The first captilal is lost in translation."],"metadata":{"id":"Rq3LXgkMlywN"}},{"cell_type":"code","source":["print('Matilda'.replace('ilda', 'ild4'))"],"metadata":{"id":"sgfEH2jImlwz"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["`string.replace()` is not limited to single characters"],"metadata":{"id":"GhUlBMfPmGb3"}},{"cell_type":"code","source":["print('Matilda'.replace('a', 4))"],"metadata":{"id":"BEE94VVBmf7T"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["We can only replace strings with other strings. `'Matilda'.replace('a', '4')` would work"],"metadata":{"id":"qsPQT5VGlNZ2"}},{"cell_type":"code","source":["list_of_words = ['I', 'ate', 'a', 'banana']\n","sentence = 'I ate a banana'\n","\n","assert sentence.split() == list_of_words"],"metadata":{"id":"BVKc0bQAnGYq","executionInfo":{"status":"ok","timestamp":1681824924342,"user_tz":-120,"elapsed":5,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}}},"execution_count":4,"outputs":[]},{"cell_type":"markdown","source":["`string.split()` splits on all whitespace characters by default"],"metadata":{"id":"xdueWI-yk_ME"}},{"cell_type":"code","source":["list_of_words = ['I', 'ate', 'a', 'banana']\n","sentence = 'I ate a banana'\n","\n","assert ''.join(list_of_words) == sentence"],"metadata":{"id":"R4U_8kVtmpHE"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["We join the words on the empty string, and not on a space. Thus, the resulting sentence contains all the words concatenated. "],"metadata":{"id":"ZpepgX5Lk0Mk"}},{"cell_type":"markdown","source":["## Exercise 9.2: Additional utilities\n","For each of the string functions below, find out what they do. If they take any parameters, describe what these do:\n","- `string.startswith()`\n","- `string.endswith()`\n","- `string.strip()`\n","- `string.lstrip()`\n","- `string.rstrip()`\n","- `string.title()`\n","- `string.find()`\n","- `string.split(',', x)` (describe what 'x' does. It should be a number)"],"metadata":{"id":"Xbi4ATS0mQzp"}},{"cell_type":"code","source":["# string.startswith(substring) checks if a string starts with a substring\n","assert 'matilda'.startswith('mat')\n","\n","# string.endswith(substring) checks if a string ends with a substring\n","assert 'matilda'.endswith('lda')\n","\n","# string.strip() removes whitespace from the start and end of a string\n","# as an optional parameter, takes a string and removes only characters in that string\n","assert ' matilda '.strip() == 'matilda'\n","assert '..matilda?'.strip('.,') == 'matilda?'\n","\n","# string.lstrip() and string.rstrip() work like string.split()\n","# but only for l(eft) and r(ight) part of the string\n","assert ' matilda '.rstrip() == ' matilda'\n","assert ' matilda '.lstrip() == 'matilda '\n","\n","# string.title() converts a string to title case: each word starts with a capital\n","assert 'MATILDA by roald DaHl'.title() == 'Matilda By Roald Dahl'\n","\n","# string.find(substring) returns the starting character of the substring\n","# if the substring is not found, return -1\n","assert 'matilda'.find('il') == 3\n","\n","# string.split(separator, x) splits a string x times\n","# after x splits have been made, the rest of the string is left intact\n","assert 'Matilda by Roald Dahl'.split(' ', 2) == ['Matilda', 'by', 'Roald Dahl']"],"metadata":{"id":"ZYHALHE7mU4-","executionInfo":{"status":"ok","timestamp":1681825855742,"user_tz":-120,"elapsed":231,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}}},"execution_count":22,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 9.3: String formatting\n","In each of the code blocks below, try to predict what will be printed, then run the code. If your guess was incorrect, try to figure out why the result is different. If your guess was correct, celebrate!"],"metadata":{"id":"avcqgDAAoq-w"}},{"cell_type":"code","source":["print('hey {}')"],"metadata":{"id":"BIa0VOX_owF4","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681825929769,"user_tz":-120,"elapsed":7,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}},"outputId":"ddc080fa-bf11-4064-c5f4-efcbef9b9a64"},"execution_count":23,"outputs":[{"output_type":"stream","name":"stdout","text":["hey {}\n"]}]},{"cell_type":"markdown","source":["Using `{}` in a string with `.format()` leaves the curly brackets untouched."],"metadata":{"id":"SDnzz_IYoqRP"}},{"cell_type":"code","source":["print('hey {Julian}')"],"metadata":{"id":"81GUitOZo0l2","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681825932026,"user_tz":-120,"elapsed":3,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}},"outputId":"6be221d0-52b7-47f9-8269-991811402ff7"},"execution_count":24,"outputs":[{"output_type":"stream","name":"stdout","text":["hey {Julian}\n"]}]},{"cell_type":"markdown","source":["Again, without `.format()`, the string is untouched"],"metadata":{"id":"-HFk3OAAoyyy"}},{"cell_type":"code","source":["print('hey {}'.format('Julian'))"],"metadata":{"id":"96Dq4eSCpAji","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681825967240,"user_tz":-120,"elapsed":267,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}},"outputId":"7e3086d7-4e02-4b98-d96e-d91257f65fb5"},"execution_count":25,"outputs":[{"output_type":"stream","name":"stdout","text":["hey Julian\n"]}]},{"cell_type":"markdown","source":["Calling `.format()` fills the placeholders"],"metadata":{"id":"OFmrf_lto6_k"}},{"cell_type":"code","source":["print('hey {Julian}'.format('Julian'))"],"metadata":{"id":"h43fjzPco4V_"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["This doesn't work, the names placeholder expects a named parameter.\n","\n","`'hey {Julian}'.format(Julian='julian')` would work"],"metadata":{"id":"XP3dKwEXpAir"}},{"cell_type":"code","source":["print('hey {name}'.format('Julian'))"],"metadata":{"id":"wA18AIPKpFAH"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["Same as above"],"metadata":{"id":"LI43JmY2pcIg"}}]} \ No newline at end of file diff --git a/solutions/10 - Dictionaries solutions.ipynb b/solutions/10 - Dictionaries solutions.ipynb new file mode 100644 index 0000000..fb8f923 --- /dev/null +++ b/solutions/10 - Dictionaries solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[{"file_id":"16mecEPkVGUBIFoHIALO7dE8qv7PynHL9","timestamp":1681824660733}]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["# Dictionaries\n","\n","### CDH course \"Programming in Python\"\n","\n","[index](https://colab.research.google.com/drive/1s05aR4wn2dU1C3se1oXfqKz2EY5ilrno)\n","\n","Previous module: [9. String manipulation](https://colab.research.google.com/drive/1Z7NNMxqHTSMoUadH3pVL6Bg6oii4qUoQ)\n","\n","### This module\n","\n","- Learn about _dictionaries_, a useful way of storing and looking up data"],"metadata":{"id":"kjdcNtg3k8Aa"}},{"cell_type":"markdown","source":["## Exercise 10.1: Dictionaries"],"metadata":{"id":"1ezL-XhlvHBq"}},{"cell_type":"markdown","source":["1 . Below are two dictionaries containing information about different types of fruit. Print a nice message about each fruit stating its colour and price. For example, _An apple is red and costs € 2.50_, etc."],"metadata":{"id":"rxcz60KQximW"}},{"cell_type":"code","source":["fruit_colors = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange'}\n","fruit_prices = {'apple': 2.50, 'banana': 2.10, 'orange': 1.50}\n","\n","# The example sentence includes 'a'/'an' ('an apple' / 'a banana')\n","# which was a bit of an oversight: the point of this exercise\n","# was to loop through a dictionary and access values.\n","# You could make a solution like this to avoid it.\n","\n","for fruit in fruit_colors:\n"," color = fruit_colors[fruit]\n"," price = fruit_prices[fruit]\n","\n"," print(fruit + 's', 'are', color, 'and cost €', price, sep=' ')\n","\n","# Bonus points if you DID implement a solution on when to use\n","# 'a' or 'an'! Here is an example of your you can do that.\n","\n","print()\n","\n","def starts_with_vowel(word):\n"," '''\n"," Returns True if the word (a string) starts with a vowel.\n"," '''\n"," vowels = ['a', 'e', 'i', 'o', 'u']\n"," if word[0] in vowels:\n"," return True\n"," return False\n","\n","\n","for fruit in fruit_colors:\n"," color = fruit_colors[fruit]\n"," price = fruit_prices[fruit]\n","\n"," if starts_with_vowel(fruit):\n"," article = 'An'\n"," else:\n"," article = 'A'\n","\n"," print(article, fruit, 'is', color, 'and costs €', price, sep=' ')"],"metadata":{"id":"yn89oAAZu33C","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681894457462,"user_tz":-120,"elapsed":238,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"d6b7d53c-d22c-4499-8b59-de508579836e"},"execution_count":3,"outputs":[{"output_type":"stream","name":"stdout","text":["apples are red and cost € 2.5\n","bananas are yellow and cost € 2.1\n","oranges are orange and cost € 1.5\n","\n","An apple is red and costs € 2.5\n","A banana is yellow and costs € 2.1\n","An orange is orange and costs € 1.5\n"]}]},{"cell_type":"markdown","source":["2 . Here is a longer lists of fruit colours. Write a function `count_fruits` which gets gets a colour as input and returns the number of fruits that have that colour (according to `lots_of_fruit`)."],"metadata":{"id":"Gtp5V9dE0LxK"}},{"cell_type":"code","source":["lots_of_fruit = {'apple': 'red', 'banana': 'yellow', 'orange': 'orange',\n"," 'cucumber': 'green', 'kiwi': 'green', 'strawberry': 'red',\n"," 'pineapple': 'yellow','blackberry': 'black', 'cherry': 'red',\n"," 'gooseberry': 'green', 'raspberry': 'red', 'mandarin': 'orange',\n"," 'lemon': 'yellow', 'lime': 'green'}"],"metadata":{"id":"S7gCNyLCxdrO","executionInfo":{"status":"ok","timestamp":1681894473607,"user_tz":-120,"elapsed":227,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":4,"outputs":[]},{"cell_type":"code","source":["def count_fruits(color):\n"," '''Count the number of fruits in `lots_of_fruit` that match this colour.'''\n"," count = 0\n"," for value in lots_of_fruit.values():\n"," if value == color:\n"," count = count + 1\n"," return count\n","\n","# let's see if it works!\n","assert count_fruits('red') == 4\n","assert count_fruits('lavender') == 0"],"metadata":{"id":"nScDQipK35qN","executionInfo":{"status":"ok","timestamp":1681894484122,"user_tz":-120,"elapsed":259,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":5,"outputs":[]},{"cell_type":"markdown","source":["3 . The list `fruit_basket` contains a bunch of fruits. Can you make a dictionary `fruit_counts` which gives the amount for each fruit in `fruit_basket`? (Do not count the fruits by hand!)"],"metadata":{"id":"-Qp6R3Kp3GId"}},{"cell_type":"code","source":["fruit_basket = ['apple', 'banana', 'banana', 'banana', 'apple', 'orange',\n"," 'orange', 'grape', 'grape', 'grape', 'grape', 'grape', 'grape',\n"," 'grape', 'grape', 'grape', 'pear', 'apple', 'strawberry',\n"," 'strawberry', 'strawberry', 'orange']"],"metadata":{"id":"awf-lLQO3N1U","executionInfo":{"status":"ok","timestamp":1681894489366,"user_tz":-120,"elapsed":217,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":6,"outputs":[]},{"cell_type":"code","source":["def count_items(items):\n"," '''\n"," Count the items in a list.\n","\n"," Input: a list of items, such as strings\n"," Output: a dictionary with the total of occurences for each item.\n"," '''\n","\n"," counts = dict() # we will keep track of our counts in here!\n","\n"," for item in items:\n"," # the current count: either the current value in the dictionary\n"," # or 0 if we haven't seen this fruit yet\n"," current_count = counts.get(item, 0)\n"," new_count = current_count + 1\n"," counts[item] = new_count\n"," \n"," return counts\n","\n","fruit_counts = count_items(fruit_basket)\n","\n","# let's see if it works!\n","assert fruit_counts['apple'] == 3\n"],"metadata":{"id":"MDpIZpbm3-BG","executionInfo":{"status":"ok","timestamp":1681894585893,"user_tz":-120,"elapsed":281,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":7,"outputs":[]},{"cell_type":"markdown","source":["4 . Here is a different list, which contains the words in a sentence. Can you use your code above to make a dictionary `word_counts` telling us how often each word occurs? (Tip: if you need to do very similar tasks, make a function!)\n","\n","Write a function that takes a dictionary like `word_counts` tells us the most commonly occuring item and the count. Note that there can be multiple items that occurred the most."],"metadata":{"id":"h-kJhTO951pc"}},{"cell_type":"code","source":["# the variable sent0 contains the first sentence of The Catcher in the Rye\n","# split into single words\n","sent0 = ['If', 'you', 'really', 'want', 'to', 'hear', 'about', 'it,', 'the', \n"," 'first', 'thing', 'you’ll', 'probably', 'want', 'to', 'know', 'is', \n"," 'where', 'I', 'was', 'born,', 'and', 'what', 'my', 'lousy', 'childhood', \n"," 'was', 'like,', 'and', 'how', 'my', 'parents', 'were', 'occupied', \n"," 'and', 'all', 'before', 'they', 'had', 'me,', 'and', 'all', 'that', \n"," 'David', 'Copperfield', 'kind', 'of', 'crap,', 'but', 'I', 'don’t', \n"," 'feel', 'like', 'going', 'into', 'it,', 'if', 'you', 'want', \n"," 'to', 'know', 'the', 'truth.']"],"metadata":{"id":"mdNug4ct5645","executionInfo":{"status":"ok","timestamp":1681894602379,"user_tz":-120,"elapsed":241,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":8,"outputs":[]},{"cell_type":"code","source":["word_counts = count_items(sent0) # we recycle our function from the last exercise"],"metadata":{"id":"XGY3qSEk6B9j","executionInfo":{"status":"ok","timestamp":1681894603343,"user_tz":-120,"elapsed":3,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}}},"execution_count":9,"outputs":[]},{"cell_type":"code","source":["def most_frequent(counts):\n"," '''\n"," For a dictionary with totals, the most commonly occuring item(s) and the count.\n","\n"," Input should be a dictionary with the total number of occurences for each key in some collection.\n"," Returns a tuple of two items. First is a list of the most frequent item(s). If the input\n"," is an empty dict, the list if empty. Second is the number of occurences for that item.\n"," '''\n","\n"," if not len(counts):\n"," return [], 0\n","\n"," max_count = max(counts.values())\n","\n"," top_items = []\n"," for item, count in counts.items():\n"," if count == max_count:\n"," top_items.append(item)\n","\n"," return top_items, max_count\n","\n","words, total = most_frequent(word_counts)\n","print(words, total)\n","\n","# here are some assert statements you could use to check your own function\n","# feel free to adapt them if your function gives a different output format\n","assert most_frequent(fruit_counts) == (['grape'], 9)\n","assert most_frequent(word_counts) == (['and'], 4)\n","assert most_frequent({}) == ([], 0)"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"iS8rDbONnVDr","executionInfo":{"status":"ok","timestamp":1681894948452,"user_tz":-120,"elapsed":307,"user":{"displayName":"Luka van der Plas","userId":"16305747382115943293"}},"outputId":"c1313777-a4ab-477d-e428-9ae285fc28da"},"execution_count":14,"outputs":[{"output_type":"stream","name":"stdout","text":["['and'] 4\n"]}]}]} \ No newline at end of file diff --git a/solutions/11 working with files solutions.ipynb b/solutions/11 working with files solutions.ipynb new file mode 100644 index 0000000..530a8ec --- /dev/null +++ b/solutions/11 working with files solutions.ipynb @@ -0,0 +1 @@ +{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"provenance":[],"authorship_tag":"ABX9TyNBT3v2osSyHD05LL0HU2aj"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","source":["## Exercise 11.1 - Files\n","In the code block below, try to predict what will be printed, then run the code."],"metadata":{"id":"YC0q3Z4HiM5Z"}},{"cell_type":"code","source":["PATH = 'sample_data/california_housing_test.csv'\n","file = open(PATH)\n","print(file)\n","print(file.read())\n","print(file.readlines())\n","file.close()\n","print(file)"],"metadata":{"id":"vZtR4360i7kh"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["`print(file)` prints the File Object. There is no way to determine by printing if this is still open, or has been closed."],"metadata":{"id":"F9f99yil6tQQ"}},{"cell_type":"markdown","source":["Read the file `sampledata/california_housing_test.csv'`, and print the first row containing data as a list.\n","\n","Are the data in the correct format? Try to fix it if not."],"metadata":{"id":"BXOkW2J7ldYK"}},{"cell_type":"code","source":["PATH = 'sample_data/california_housing_test.csv'\n","file = open(PATH)\n","lines = file.readlines()\n","\n","# Read the first row\n","first_row = lines[0]\n","print(first_row)"],"metadata":{"id":"eP_TfHcmlsce","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1681914737357,"user_tz":-120,"elapsed":202,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}},"outputId":"b58e166d-1764-4e0f-91e2-7ea872519052"},"execution_count":4,"outputs":[{"output_type":"stream","name":"stdout","text":["\"longitude\",\"latitude\",\"housing_median_age\",\"total_rooms\",\"total_bedrooms\",\"population\",\"households\",\"median_income\",\"median_house_value\"\n","\n"]}]},{"cell_type":"markdown","source":["Note that this prints the header row, as one big string. Not really what we are looking for!"],"metadata":{"id":"9Bobwjk07Ssq"}},{"cell_type":"code","source":["# Split the file into header row and data rows\n","header, *data = lines\n","first_row = data[0]\n","print(first_row)\n","print(type(first_row))"],"metadata":{"id":"bwxxok8a7Wyy"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":["This is the first actual row of data, but still as a big string."],"metadata":{"id":"JZeGlr5p7nlV"}},{"cell_type":"code","source":["columns = first_row.split(',')\n","print(columns)\n","print(type(columns[0]))"],"metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"g4XFr9pG7qor","executionInfo":{"status":"ok","timestamp":1681914801091,"user_tz":-120,"elapsed":2,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}},"outputId":"ee3cb701-edf8-44f2-c28b-593f1d33acef"},"execution_count":9,"outputs":[{"output_type":"stream","name":"stdout","text":["['-122.050000', '37.370000', '27.000000', '3885.000000', '661.000000', '1537.000000', '606.000000', '6.608500', '344700.000000\\n']\n","\n"]}]},{"cell_type":"markdown","source":["The row is split into columns. They still contain strings, not numbers. And the last value includes the newline character `\\n`"],"metadata":{"id":"EuCKWl9z7zUf"}},{"cell_type":"code","source":["def clean_value(value):\n"," '''\n"," Clean a single value. Assumes value is a string representation\n"," of a number.\n"," - remove any whitespace characters\n"," - convert the value into a float\n"," - check if it is an integer, if so, convert to an actual int\n"," - return the result\n"," '''\n"," clean_value = value.strip()\n"," float_value = float(clean_value)\n"," if float_value.is_integer():\n"," return int(float_value)\n"," return float_value\n","\n","\n","def clean_values(values):\n"," '''\n"," Cleans an entire row or column using clean_column.\n"," Assumes values is a list of string representations\n"," of numbers.\n"," '''\n"," cleaned_row = []\n"," for value in values:\n"," cleaned_row.append(clean_value(value))\n"," return cleaned_row\n","\n","\n","assert clean_values(columns) == [-122.05, 37.37, 27, 3885, 661, 1537, 606, 6.6085, 344700]"],"metadata":{"id":"BnpSq28I766w","executionInfo":{"status":"ok","timestamp":1681916502255,"user_tz":-120,"elapsed":226,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}}},"execution_count":36,"outputs":[]},{"cell_type":"markdown","source":["## Exercise 11.2: Bonus - working with csv datasets\n","> 💡 If you wish to perform an analysis on your own dataset in the upcoming sessions, make sure you complete this exercise. The code you write here can be reused in your own analysis.\n","\n","1. Upload your own dataset, or use `sample_data/california_housing_test.csv`\n"," 1. Read the data from the CSV file\n"," 2. Write functions that take the data as a parameter, and return the following items:\n"," - The last row\n"," - The last column\n"," - The first row. If this is a header row, try if you can come up with a way to separate it from the data rows.\n"," - Calculate the *harmonic mean* of a column containing numbers. Search the [standard library](https://docs.python.org/3.7/library/index.html) for a a relevant module containing the code to do so.\n"," 3. Add an extra column to the data (think of something that makes sense). Write the whole dataset to a new csv file."],"metadata":{"id":"h-mOS3pwoc1O"}},{"cell_type":"markdown","source":["#### 11.2.1"],"metadata":{"id":"nqZZLHi4-HyR"}},{"cell_type":"code","source":["import csv\n","PATH = 'sample_data/california_housing_test.csv'\n","\n","def read_data():\n"," with open(PATH) as csv_file:\n"," reader = csv.reader(csv_file, delimiter=',')\n"," return list(reader)\n"," \n","assert len(read_data()) == 3001"],"metadata":{"id":"3UI9XbgN-Ffb","executionInfo":{"status":"ok","timestamp":1681915598793,"user_tz":-120,"elapsed":194,"user":{"displayName":"Jelte van Boheemen","userId":"01262930844892157638"}}},"execution_count":23,"outputs":[]},{"cell_type":"markdown","source":["#### 11.2.2\n","This may seem like a whole load of code just to calculate some stuff.\n","\n","But notice that by definding general functions, we create a toolkit that we can apply to any future problems! Think ahead!"],"metadata":{"id":"6PUt-Fni-3g0"}},{"cell_type":"code","source":["def get_row(data, row_index):\n"," '''\n"," Returns the row at row_index\n"," '''\n"," return data[row_index]\n","\n","\n","def get_column(data, column_index):\n"," '''\n"," Returns the column at column_index\n"," '''\n"," column = []\n"," for row in data:\n"," column.append(row[column_index])\n"," return column\n","\n","\n","def separate_headers(data):\n"," '''\n"," Separates tabular data into a header row and data rows\n"," '''\n"," header_row, *data_rows = data\n"," return header_row, data_rows\n","\n","\n","def multiply(num1, num2):\n"," return num1 * num2\n","\n","\n","def combine_columns(column_1, column_2, how):\n"," '''\n"," created a new column based on two existing columns\n"," how should be a function that accepts two numbers and returns a number\n"," column_1 and column_2 should contain numerical data\n"," '''\n"," new_column = []\n"," for index, value_1 in enumerate(column_1):\n"," value_2 = column_2[index]\n"," new_column.append(how(value_1, value_2))\n"," return new_column\n","\n","\n","\n","def add_column(data, column_name, column_data):\n"," '''\n"," Adds an extra column to the end of the data\n"," Assumes data containts tabular data WITH headers\n"," colum_data size should match existing table\n"," '''\n"," headers, data_rows = separate_headers(data)\n"," headers = [headers + [column_name]]\n","\n"," new_rows = []\n"," for index, row in enumerate(data_rows):\n"," new_row = row + [column_data[index]]\n"," new_rows.append(new_row)\n"," return headers + new_rows\n","\n","def write_table_to_csv(data, filepath):\n"," with open(filepath, mode='w') as f:\n"," writer = csv.writer(f)\n","\n"," for row in data:\n"," writer.writerow(row)\n","\n","\n","# read the data and get the last row\n","data = read_data()\n","last_row = get_row(data, -1)\n","print(last_row)\n","\n","# determine the number of columns, and use this to get the last column\n","number_of_columns = len(last_row) - 1 # remember that list indices start at 0!\n","last_column = get_column(data, number_of_columns)\n","print(last_column)\n","\n","# get the first data row\n","headers, data_rows = separate_headers(data)\n","first_row = data_rows[0]\n","print(first_row)\n","\n","# get the index of the 'median_income' column\n","income_index = header.index('median_income')\n","# get the column data\n","income = get_column(data_rows, income_index)\n","# convert the data to numbers\n","income_numerical = clean_values(income)\n","# finally, calculate the harmonic mean\n","import statistics\n","harmonic_mean = statistics.harmonic_mean(income_numerical)\n","print(harmonic_mean)\n","\n","# add a new column\n","# get households the same way we did income, this time on one line\n","households_numerical = clean_values(get_column(data_rows, header.index('households')))\n","# combine households and income by multiplying them\n","total_income = combine_columns(income_numerical, households_numerical, multiply)\n","new_data = add_column(data, 'total_income', total_income)\n","# finally, write to a new file\n","write_table_to_csv(new_data, 'sample_data/california_housing_test_expanded.csv')\n"],"metadata":{"id":"wOEhjWRq-6QL"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":[],"metadata":{"id":"UuvUPP01_uUL"}}]} \ No newline at end of file diff --git a/solutions/Extra exercises day 1 solutions.ipynb b/solutions/Extra exercises day 1 solutions.ipynb new file mode 100644 index 0000000..c27aa92 --- /dev/null +++ b/solutions/Extra exercises day 1 solutions.ipynb @@ -0,0 +1,587 @@ +{ + "cells": [ + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Hierbij wat extra opdrachtjes voor de modules van dag 1!" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Types\n", + "## Exercise A\n", + "useful for after 1.4\n", + "\n", + "1. Create one variable each for every following type (replace None with an example):\n", + " - Integer (`int`)\n", + " - Floating point (`float`)\n", + " - Boolean (`bool`)\n", + " - String (`str`)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "example_int = 1\n", + "example_float = 2.0\n", + "example_bool = True\n", + "example_string = 'four'" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Did you know that you can check the type of a variable in Python? If you are ever unsure of the type of a variable, use the `type()` function to check, e.g.:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "print(type(1))\n", + "print(type(1.0))\n", + "print(type(False))\n", + "print(type('one'))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Now try and check the types of the examples you just declared using the method above:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "## Space for exercise\n", + "print(type(example_int))\n", + "print(type(example_float))\n", + "print(type(example_bool))\n", + "print(type(example_string))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Python is a 'dynamically typed' language, which means that the type of a variable can vary based on its context or user coercion. For example, you can coerce an integer to a float by declaring:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2 \n", + "2.0 \n" + ] + } + ], + "source": [ + "example_integer = 2 # declare example integer\n", + "print(example_integer, type(example_integer)) #print the integer and its type\n", + "\n", + "coerced_float = float(example_integer)\n", + "print(coerced_float, type(coerced_float))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can coerce these types manually or Python sometimes does it automatically, for example when you try and execute operations on a variable that requires a certain type. For instance, if you try to add the integer and float above, the result of that operation will be a float. Python automatically coerces the integer to a float to complete the addition.\n", + "\n", + "3. For this exercise, try to perform some operations on these variables below. Which types can be automatically added together? And what type is the result of their operation? What happens when you try a different operation, such as subtraction?" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3.0 \n", + "4.0 \n", + "3.0 \n", + "threethree \n", + "2 \n" + ] + } + ], + "source": [ + "ex_int = 1\n", + "ex_float = 2.0\n", + "ex_string = 'three'\n", + "ex_bool = True\n", + "\n", + "ex_result = ex_int + ex_float # example operation\n", + "print(ex_result, type(ex_result))\n", + "\n", + "result2 = ex_float + ex_float\n", + "print(result2, type(result2))\n", + "\n", + "result3 = ex_float + ex_bool\n", + "print(result3, type(result3))\n", + "\n", + "result4 = ex_string + ex_string\n", + "print(result4, type(result4))\n", + "\n", + "result5 = ex_bool + ex_int\n", + "print(result5, type(result5))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Lists\n", + "## Exercise B\n", + "Let's make some lists! \n", + "1. Start by declaring an empty list (`empty_list = []`)." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "my_list = []" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You can check the length of the list with the `len()` function:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0\n" + ] + } + ], + "source": [ + "print(len(my_list))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Now, add some elements to your list. Then check the length of the list again!" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "3" + ] + }, + "execution_count": 16, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "## Space for exercise\n", + "my_list.append([1, 2.0, True, 'Four'])\n", + "my_list.append(example_float)\n", + "my_list.append(example_int)\n", + "len(my_list)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Loops\n", + "## Exercise C" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "1. Now that you have your list, let's walk through it and print every element in it. Hint: use the `for` loop." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[1, 2.0, True, 'Four']\n", + "2.0\n", + "1\n" + ] + } + ], + "source": [ + "## Space for exercise\n", + "for item in my_list:\n", + " print(item)" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "2. Instead of simply printing the elements, see if you can print the result of an operation with each element (for example, print the element + 1 if all your list elements are numbers or booleans). Alternatively, see if you can print the type of each element in the list." + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "\n", + "\n" + ] + } + ], + "source": [ + "## Space for exercise\n", + "for item in my_list:\n", + " print(type(item))" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Logical Operators\n", + "## Exercise D\n", + "Python allows the use of several logical operators, so to get you in the mindset of a computer, see if you can determine whether an expression is going to return `True` or `False`. After you have given your answer, run the code in the cell to see if you were correct!" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": {}, + "outputs": [], + "source": [ + "# Declaration of the variables used in the exercise\n", + "n1 = 1\n", + "n2 = 2\n", + "n3 = 3.4\n", + "n4 = 4.5\n", + "s1 = 'Hello'\n", + "s2 = 'World'\n", + "s3 = 'Hallo'\n", + "s4 = 'Wereld'\n", + "l1 = [n1, n2, n3, n4]\n", + "l2 = [s1, s2, s3, s4]" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 1\n", + "n1 == n2" + ] + }, + { + "attachments": {}, + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 2\n", + "n1 + n2 == 3" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 3\n", + "n1 + n3 != 3.4" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 30, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 4\n", + "s1 + s2 == \"Hello World\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "False" + ] + }, + "execution_count": 31, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 5\n", + "s3 == \"hallo\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 6\n", + "len(l1) == len(l2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "True or False?" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "#Example 7\n", + "len(s3) == len(s1)" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "True\n", + "False\n" + ] + } + ], + "source": [ + "##Example 8\n", + "for item in l2:\n", + " print(len(item) == 5)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.2" + }, + "orig_nbformat": 4, + "vscode": { + "interpreter": { + "hash": "2cc67e3a9982c67c9491f847535e93961a1a3bd6725cdcb43113c9880de5dac3" + } + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/teaching materials/0_Introduction.ipynb b/teaching materials/0_Introduction.ipynb deleted file mode 100755 index 1d1c268..0000000 --- a/teaching materials/0_Introduction.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Introduction.ipynb","provenance":[],"collapsed_sections":[],"authorship_tag":"ABX9TyO6FzkfpZhr99ftIowKgUps"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"_Hnez8dT2xWz"},"source":["# CDH course \"Programming in Python\"\n","## Who are we?\n","\n","- Julian Gonggrijp & Jelte van Boheemen\n","- Developers at the Digital Humanities Lab\n","\n","\n","## Who are you?\n","- Entry level course, no previous experience required\n","- If you have some experience, parts of the course may be familiar. Challenge yourself with some difficult exercises!\n","\n","## Goals\n","- Introduce the basics of the Python programming language\n","- Write simple computer programs\n","- Simple data analysis on your own data\n","- Teach good practises that you can apply to all your future programming, and make you a self-reliant programmer\n","\n","\n","## Colab Notebooks\n","- Runs Python code in your web browser not installing required\n","- If you do not have a Google account, please make one\n","- Presenting straight from Colab, so you can follow our example\n","\n","## Course materials\n","https://tinyurl.com/cdh-python\n","\n","## Please interupt if you have any questions!\n","Let's get started! [To part 1](https://colab.research.google.com/drive/1Ip0vwlf22MNVWLJceCgrIMadtOLSlxdO?usp=sharing)"]}]} \ No newline at end of file diff --git a/teaching materials/1_1_python_basics.ipynb b/teaching materials/1_1_python_basics.ipynb deleted file mode 100755 index 0aab5c6..0000000 --- a/teaching materials/1_1_python_basics.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Day 1, part 1 - Python Basics.ipynb","provenance":[],"collapsed_sections":[],"toc_visible":true,"authorship_tag":"ABX9TyOYJ9fb6wAUFQzhBVQ8WcHi"},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"8eZi1PYt1p-i"},"source":["# 1 - Python basics\n","\n"]},{"cell_type":"markdown","metadata":{"id":"mM1V09O2aBHD"},"source":["## 1.1 - Hello, world\n","- Run a simple program\n","- Output to the screen\n","- Lines starting with `#` are comments, they are ignored by the program"]},{"cell_type":"code","metadata":{"id":"gVfjgWZOY_fs","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636967556322,"user_tz":-60,"elapsed":230,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"e7d8a2d4-436f-4fc6-cbf9-001d7d8d09a5"},"source":["# Let's make the program say hello this is ignored\n","print(\"Hello, world!\")\n","print(\"Whatever you want\")"],"execution_count":4,"outputs":[{"output_type":"stream","name":"stdout","text":["Whatever you want\n"]}]},{"cell_type":"markdown","metadata":{"id":"B-9asW2lw5Fk"},"source":["## Exercise 1\n","- Write your own hello world program and execute it"]},{"cell_type":"markdown","metadata":{"id":"AWR0hSuzbEmR"},"source":["## 1.2 - Types\n","\n","* Number\n"," * Integer: `0`, `1`, `2`, `-1`, `122803`\n"," * Floating point (decimal): `0.0`, `1.1`, `2.122803`\n","\n","\n","\n","\n","\n","\n"]},{"cell_type":"markdown","metadata":{"id":"mTn3zLre4U9S"},"source":[""]},{"cell_type":"code","metadata":{"id":"rJLSAQCr4KYw"},"source":["0\n","1\n","2\n","-1\n","\n","0.12\n","1.2\n","-0.1"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"zSPHuo44QPWM"},"source":["* String (text)\n"," * Double quote: `\"b\"`, `\"Who says I can't use an apostrophe?\"`, `\"\"` (empty string)\n"," * Single quote: `'a'`, `'here is some text'`, `'1'`, `'2.3'`"]},{"cell_type":"code","metadata":{"id":"ScPTgkiG4bWc"},"source":["\"this is a string\"\n","'this is a string'\n","\n","'1'\n","1\n"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"L04bFM7iQQOb"},"source":["* Boolean\n"," * `True` or `False`"]},{"cell_type":"code","metadata":{"id":"fjpthJ_e41j8"},"source":["True\n","False\n","\n","\"True\"\n","print(True)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"lsTxBVVedyqS"},"source":["## 1.3 - Operators\n","\n","- Arithmetic\n"," - `1 + 1`\n"," - `2 - 1`\n"," - `3 * 4`\n"," - `10 / 2`"]},{"cell_type":"code","metadata":{"id":"WaBTyfRZPLUX"},"source":["10 / 2"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"VfhH8_1cPLlp"},"source":["- String operators\n"," - Concatenation: `\"Hello \" + \"world!\"`\n"," - Repetition: `\"Hello\" * 3`\n"]},{"cell_type":"code","metadata":{"id":"fF924rHaPP8P","colab":{"base_uri":"https://localhost:8080/","height":35},"executionInfo":{"status":"ok","timestamp":1636968024556,"user_tz":-60,"elapsed":224,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"30e5a678-e06b-46be-b569-ee4a41ddf2bd"},"source":["\"hello \" + \"world\"\n","\"hello \" * 3"],"execution_count":14,"outputs":[{"output_type":"execute_result","data":{"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"},"text/plain":["'hello hello hello '"]},"metadata":{},"execution_count":14}]},{"cell_type":"markdown","metadata":{"id":"6E5l_WAXPTcQ"},"source":["- Comparison\n"," - Evaluates to `True` or `False`\n"," - Equals `1 == 1`, `\"hello\" == \"hello\"`\n"," - Not equals `1 != 2`, `\"hello\" != \"goodbye\"`\n"," - Greater/smaller than `1 < 2`, `\"b\" > \"a\"`"]},{"cell_type":"code","metadata":{"id":"eCsTzljPPXc9"},"source":[""],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"XKeTtLOGQpks"},"source":["## 1.4 - Variables\n","* \"Container\" for values\n"," * `a = 1`\n","* Can be reassigned to a new value\n"," * `a = 2`\n","* In Python, no strict types\n"," * `a = 1`\n"," * `a = \"hello\"`\n"," \n"," \n","\n","\n"]},{"cell_type":"code","metadata":{"id":"qaCMxJMpRvAP","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636968322355,"user_tz":-60,"elapsed":308,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"663281a9-51a3-436e-a73c-daa68d508a6e"},"source":[""],"execution_count":28,"outputs":[{"output_type":"stream","name":"stdout","text":["hello\n"]}]},{"cell_type":"markdown","metadata":{"id":"J5L_PjLYlhgR"},"source":["* Can also assign another variable, or an expression"]},{"cell_type":"code","metadata":{"id":"MI_JjAeDlh-w","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636968450575,"user_tz":-60,"elapsed":302,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"753f519e-b00a-4bfe-b32a-4663741f4365"},"source":["a = 1\n","b = a\n","print(b)\n","\n","a = 2\n","\n","print(b)\n","print(a)"],"execution_count":35,"outputs":[{"output_type":"stream","name":"stdout","text":["1\n","1\n","2\n"]}]},{"cell_type":"code","metadata":{"id":"ko6EZrIi9lVQ","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636968394959,"user_tz":-60,"elapsed":313,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"797fde4e-7197-4f85-9c66-0487cb2fe5a2"},"source":["b = 1\n","c = b + 1\n","print(c)"],"execution_count":32,"outputs":[{"output_type":"stream","name":"stdout","text":["2\n"]}]},{"cell_type":"code","metadata":{"id":"zfqHHZ129ld3","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636968419639,"user_tz":-60,"elapsed":311,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"309c73ae-e9f4-4383-fe92-81ce31dc0e71"},"source":["d = 5\n","e = 4\n","g = 8\n","f = d + e + 5 - g\n","print(f)"],"execution_count":33,"outputs":[{"output_type":"stream","name":"stdout","text":["6\n"]}]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"QgVk2G187AFx","executionInfo":{"status":"ok","timestamp":1636968436948,"user_tz":-60,"elapsed":303,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"a841ec31-3376-4347-bf89-621917b9d0e4"},"source":["print(a)"],"execution_count":34,"outputs":[{"output_type":"stream","name":"stdout","text":["2\n"]}]},{"cell_type":"markdown","metadata":{"id":"QrJK8upSR9aR"},"source":["* Naming\n"," * Rules\n"," * contains only `a-z`, `A-Z`, `0-9`, `_`\n"," * does not start with a number\n"," * Conventions\n"," * meaningful name: `age = 33`, not `a = 30`\n"," * for multiple words, \"snake case\" : `age_in_years`, not `ageInYears`\n"," * either all lowercase `age` or all uppercase `AGE` (for constants). \n"," * Case sensitive\n"," * `age_in_years != ageInYears`\n"]},{"cell_type":"code","metadata":{"id":"Tp64GSb1T4xX","executionInfo":{"status":"ok","timestamp":1636968676150,"user_tz":-60,"elapsed":312,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}}},"source":[""],"execution_count":36,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"wv1N7FP-T5QQ"},"source":["## 1.5 - Lists\n","- Collection of values\n"," - `[1, 2, 3]`, `[\"hello\", \"world\"]`, `[]` (empty list)\n"," - Mixed types possible: `[\"hello\", 1, False]`"]},{"cell_type":"code","metadata":{"id":"0GWOcQgyUraG"},"source":["age = 33\n","age_list = [12, 20, age]\n","print(age_list)"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"dpkcrvAe8Fqn","executionInfo":{"status":"ok","timestamp":1636968804868,"user_tz":-60,"elapsed":309,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"fbf409d8-ba04-4197-e4d9-46b7e660b7f4"},"source":["age = 33\n","age_someone_else = 34\n","list_of_ages = [age, age_someone_else, True, \"hello\", 2.0]\n","print(list_of_ages)"],"execution_count":40,"outputs":[{"output_type":"stream","name":"stdout","text":["[33, 34, True, 'hello', 2.0]\n"]}]},{"cell_type":"markdown","metadata":{"id":"YLKw03brU4It"},"source":["- Accessing list elements\n"," - *index*: from `0` to `length of list - 1`\n"," - Acces by index: `list[0]`, `list[1]`, `list[-1]` (last element)"]},{"cell_type":"code","metadata":{"id":"RZVOomcAVHej","colab":{"base_uri":"https://localhost:8080/","height":69},"executionInfo":{"status":"ok","timestamp":1636968936044,"user_tz":-60,"elapsed":301,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"e13c1d57-297d-4c8c-98f1-97ddef09a0cd"},"source":["word_list = [\"hello\", \"world\"]\n","print(word_list[0])\n","world = word_list[1]\n","print(world)\n","\n","word_list[-1]"],"execution_count":46,"outputs":[{"output_type":"stream","name":"stdout","text":["hello\n","world\n"]},{"output_type":"execute_result","data":{"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"},"text/plain":["'world'"]},"metadata":{},"execution_count":46}]},{"cell_type":"markdown","metadata":{"id":"Vd3kfXOeVfYV"},"source":[" - Assign like any variable"]},{"cell_type":"code","metadata":{"id":"SEkFg6knVivk"},"source":["word_list = [\"hello\", \"world\"]\n","word_list[1] = \"class\"\n","print(word_list)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"XSTx1cnGV9zM"},"source":[" - Add elements: `list + list` or `list.append(element)`\n"]},{"cell_type":"code","metadata":{"id":"ZOIwkafiWAbZ","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636901624757,"user_tz":-60,"elapsed":220,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"c578a3db-13e9-4d3a-ac44-a04c752c5cfa"},"source":["list1 = [\"hello\", \"world\"]\n","list1 = list1 + [\"!\"]\n","print(list1)"],"execution_count":null,"outputs":[{"output_type":"stream","name":"stdout","text":["['hello', 'world', '!']\n"]}]},{"cell_type":"code","metadata":{"id":"cHgMRhnl9F46"},"source":["list1 = ['hello', 'world']\n","list2 = [1, 2]\n","\n","big_list = list1 + list2\n","print(big_list)\n","\n","big_list + [\"another word\"]"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"3N5kz5yO8Gy0"},"source":["list2 = [1, 2]\n","list2.append(3)\n","print(list2)"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/"},"id":"VC8TZusM9cxJ","executionInfo":{"status":"ok","timestamp":1636969126104,"user_tz":-60,"elapsed":245,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"aad4c92d-0f2d-40d8-d481-19aaf40e9c1e"},"source":["list2.append([\"hello\", \"world\"])\n","print(list2)\n","print(list2[-1])"],"execution_count":53,"outputs":[{"output_type":"stream","name":"stdout","text":["[1, 2, 'hello', ['hello', 'world'], ['hello', 'world']]\n","['hello', 'world']\n"]}]},{"cell_type":"code","metadata":{"id":"C6LVb5nL8G8q"},"source":["list3 = [True, False]\n","list3 = list3 + False\n","print(list3)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"uIdQ4lOfWnW4"},"source":[" - Accessing multiple values (\"slicing\")\n"," - `list[begin:end]`\n"," - *end* is **not** included\n"," - `list[begin:]` everything from begin to the end of the list (end is included)"]},{"cell_type":"code","metadata":{"id":"OpKtOpn7WtUn"},"source":["list1 = [\"hello\", \"world\", \"!\"]\n","hello_world = list1[0:2]\n","print(hello_world)\n","\n","list1[0:2] = [\"hello\", \"class\"]\n","print(list1)"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"colab":{"base_uri":"https://localhost:8080/","height":35},"id":"0ZhWcG_l92jE","executionInfo":{"status":"ok","timestamp":1636969327342,"user_tz":-60,"elapsed":230,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"3c050851-ec5d-4d08-f3c2-dc0dff2a8602"},"source":["list1 = [\"hello\", \"world\", \"!\", \"hello\", \"world\", \"!\", \"hello\", \"world\", \"!\", \"hello\", \"world\", \"!\"]\n"],"execution_count":63,"outputs":[{"output_type":"execute_result","data":{"application/vnd.google.colaboratory.intrinsic+json":{"type":"string"},"text/plain":["'!'"]},"metadata":{},"execution_count":63}]},{"cell_type":"markdown","metadata":{"id":"cre-ptY-YTQO"},"source":["## 1.6 - Loops\n","- Go through a list, run some code for each element"]},{"cell_type":"code","metadata":{"id":"HmLA3LAMYnIK","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636969479273,"user_tz":-60,"elapsed":298,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"6e9f8331-9722-435e-c193-a8f44f322fdb"},"source":["list1 = [\"hello\", \"world\", \"!\"]\n","\n","\n","for value in list1:\n"," print(value)"],"execution_count":66,"outputs":[{"output_type":"stream","name":"stdout","text":["hello\n","world\n","!\n"]}]},{"cell_type":"code","metadata":{"id":"7EcmE2hr8vqw","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636969476108,"user_tz":-60,"elapsed":282,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"011d217e-85b1-437f-e137-293ac74ca5e9"},"source":["for word in list1:\n"," print(word)"],"execution_count":65,"outputs":[{"output_type":"stream","name":"stdout","text":["hello\n","world\n","!\n","hello\n","world\n","!\n","hello\n","world\n","!\n","hello\n","world\n","!\n"]}]},{"cell_type":"markdown","metadata":{"id":"KMq5PWx1Y-pM"},"source":["- Multiple lines of code go in an indented block"]},{"cell_type":"code","metadata":{"id":"9BVjK7BgZBrK"},"source":["list1 = [\"hello\", \"world\", \"!\"]\n","\n","for word in list1:\n"," new_word = word + \"_new\"\n"," print(\"printing the new word...\")\n"," print(new_word)\n"," print(new_word)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"Y7ZQZ4koiU2a"},"source":["- Loop over string\n"]},{"cell_type":"code","metadata":{"id":"IBbyqfM5iYhB","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636969590895,"user_tz":-60,"elapsed":268,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"83cd316d-0f8f-43c9-83f0-d29b2c4434e2"},"source":["for letter in \"Hello, world!\":\n"," print(letter)"],"execution_count":69,"outputs":[{"output_type":"stream","name":"stdout","text":["H\n","e\n","l\n","l\n","o\n",",\n"," \n","w\n","o\n","r\n","l\n","d\n","!\n"]}]},{"cell_type":"markdown","metadata":{"id":"cuT-iJjXi_Oh"},"source":["- List of lists\n"]},{"cell_type":"code","metadata":{"id":"6eMzZgoKjBA5"},"source":["list_of_lists = [[\"hello\", \"world\"], [\"this\", \"is\", \"jelte\"]]\n","\n","for sublist in list_of_lists:\n"," print(sublist)\n"," for word in sublist:\n"," print(word)"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"JcBr9iTs_mGc"},"source":["list_of_lists = [[\"hello\", \"world\"], [\"this\", \"is\", \"jelte\"]]\n","\n","\n","for sublist in list_of_lists:\n"," print(sublist)\n"," for word in sublist:\n"," print(word)"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"K3HyYxuQZ4Dt"},"source":["## 1.7 - Conditionals\n","- Check if some statement is the case\n","- Run code if `True`"]},{"cell_type":"code","metadata":{"id":"tacCSBrDaFL2","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1636969842284,"user_tz":-60,"elapsed":245,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"4692f7a9-af1a-458b-d101-70425595d59a"},"source":["a = 4\n","\n","if a == 2:\n"," print(\"its 2\")\n","\n","if a == 4:\n"," print(\"a is four\")\n","\n","if a != 2:\n"," print(\"this will not get printed\")\n","\n","if a > 2:\n"," print(\"a is greater than 2\")"],"execution_count":77,"outputs":[{"output_type":"stream","name":"stdout","text":["a is four\n"]}]},{"cell_type":"markdown","metadata":{"id":"-E_oCGVcauCO"},"source":["- Add an `else` clause"]},{"cell_type":"code","metadata":{"id":"I3_CLdl_ay_0"},"source":["a = 4\n","\n","if a == 2:\n"," print(\"a is two\")\n","else:\n"," print(\"a is not two\")"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"9G4hNJ7faeCR"},"source":["- Combining with lists"]},{"cell_type":"code","metadata":{"id":"8x-OiDOzakty"},"source":["list1 = [1, 2, 3, 4, 5]\n","\n","for element in list1:\n"," if element == 3:\n"," print(\"we have found 3!\")\n"," else:\n"," print(\"sadly, not 3\")"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"WqLkE5_RwG4R"},"source":["- `elif` (else-if) for multiple `if` statements with shared `else`\n","\n"]},{"cell_type":"code","metadata":{"id":"cov_FjfzwPES"},"source":["x = 6\n","\n","if x == 3:\n"," print(\"x is 3\")\n","elif x == 2:\n"," print(\"x is 2\")\n","elif x == 5:\n"," print('nope')\n","else:\n"," print(\"x is neither 2 nor 3\")"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"oTE5rxAGmr_6"},"source":["## 1.8 - Logical operators\n","- condition1 `and` condition2\n","- condition1 `or` condition2\n","- `not`"]},{"cell_type":"code","metadata":{"id":"b5XWif5oBZjD"},"source":["not True"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"Zu5vgDPkmx8N"},"source":["a = 4\n","if a > 2 and a < 5:\n"," print(\"a between 2 and 5\")\n","\n","word = \"foobar\"\n","if word == \"foo\" and word == \"bar\":\n"," print(\"foo or bar\")\n","\n","age = 25\n","if age > 20 and not age == 21:\n"," print(\"older than 20, but not 21\")"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"3BmPB2ubwDME"},"source":["## Exercise 2\n","- [To the exercise notebook](https://colab.research.google.com/drive/1P68w4Ewzptp5KLo5EMMowKOSywFMzoc8?usp=sharing)"]}]} \ No newline at end of file diff --git a/teaching materials/1_2_functions.ipynb b/teaching materials/1_2_functions.ipynb deleted file mode 100644 index 4f98bca..0000000 --- a/teaching materials/1_2_functions.ipynb +++ /dev/null @@ -1,296 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Functions.ipynb", - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "code", - "metadata": { - "id": "aK5-pZuG6KGP", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "137f10ac-c515-4cb2-cec8-197d1705f3a8" - }, - "source": [ - "print(' ' * 3 + '*' * 1)\n", - "print(' ' * 2 + '*' * 3)\n", - "print(' ' * 1 + '*' * 5)\n", - "print(' ' * 0 + '*' * 7)" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - " *\n", - " ***\n", - "*****\n", - "*******\n" - ] - } - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "8VJ7_bvx_B3P", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 35 - }, - "outputId": "90649abf-d87c-48b7-bc4a-4f81fe819e99" - }, - "source": [ - "def centered_stars(center, width):\n", - " half_width = width // 2\n", - " padding = center - half_width\n", - " return ' ' * padding + '*' * width\n", - "\n", - "centered_stars(3, 5)" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "application/vnd.google.colaboratory.intrinsic+json": { - "type": "string" - }, - "text/plain": [ - "' *****'" - ] - }, - "metadata": {}, - "execution_count": 8 - } - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "GjGFmJU3AX9U", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "2d7ce865-f64c-400d-fb99-80d5967820dc" - }, - "source": [ - "print(centered_stars(2, 1))\n", - "print(centered_stars(2, 3))\n", - "print(centered_stars(2, 5))" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - " *\n", - " ***\n", - "*****\n" - ] - } - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "Jwfbo50wBLfF", - "colab": { - "base_uri": "https://localhost:8080/" - }, - "outputId": "059e8dbc-39e4-4dea-cbc4-c94c2d41b5d0" - }, - "source": [ - "widths = list(range(1, 6, 2))\n", - "for width in widths:\n", - " print(centered_stars(2, width))" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - " *\n", - " ***\n", - "*****\n" - ] - } - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "NOo4cSHXDsUM", - "colab": { - "base_uri": "https://localhost:8080/", - "height": 789 - }, - "outputId": "2e65679e-db57-4b4a-d33a-a7a1cfdc1073" - }, - "source": [ - "def triangle(height, center=None):\n", - " import pdb; pdb.set_trace()\n", - " widths = list(range(1, height * 2, 2))\n", - " if center == None:\n", - " center = height - 1\n", - " lines = []\n", - " for width in widths:\n", - " lines.append(centered_stars(center, width))\n", - " return '\\n'.join(lines)\n", - "\n", - "triangle(3)" - ], - "execution_count": null, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "> (3)triangle()\n", - "-> widths = list(range(1, height * 2, 2))\n", - "(Pdb) n\n", - "> (4)triangle()\n", - "-> if center == None:\n", - "(Pdb) \n", - "> (5)triangle()\n", - "-> center = height - 1\n", - "(Pdb) \n", - "> (6)triangle()\n", - "-> lines = []\n", - "(Pdb) \n", - "> (7)triangle()\n", - "-> for width in widths:\n", - "(Pdb) \n", - "> (8)triangle()\n", - "-> lines.append(centered_stars(center, width))\n", - "(Pdb) s\n", - "--Call--\n", - "> (1)centered_stars()\n", - "-> def centered_stars(center, width):\n", - "(Pdb) \n", - "> (2)centered_stars()\n", - "-> half_width = width // 2\n", - "(Pdb) p width\n", - "1\n", - "(Pdb) p center\n", - "2\n", - "(Pdb) n\n", - "> (3)centered_stars()\n", - "-> padding = center - half_width\n", - "(Pdb) p half_width\n", - "0\n", - "(Pdb) n\n", - "> (4)centered_stars()\n", - "-> return ' ' * padding + '*' * width\n", - "(Pdb) p padding\n", - "2\n", - "(Pdb) p ' ' * padding + '*' * width\n", - "' *'\n", - "(Pdb) u\n", - "> (8)triangle()\n", - "-> lines.append(centered_stars(center, width))\n", - "(Pdb) c\n" - ] - }, - { - "output_type": "execute_result", - "data": { - "application/vnd.google.colaboratory.intrinsic+json": { - "type": "string" - }, - "text/plain": [ - "' *\\n ***\\n*****'" - ] - }, - "metadata": {}, - "execution_count": 27 - } - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "rpqUgX6-foDt", - "outputId": "5c7da72b-38e4-4897-ffac-a15163d4aa50" - }, - "source": [ - "TRIANGLE_ALIGN_COLUMN = 0\n", - "\n", - "print(triangle(height=15, center=TRIANGLE_ALIGN_COLUMN))\n", - "\n", - "print(triangle(6, TRIANGLE_ALIGN_COLUMN))\n", - "\n", - "print(triangle(20, TRIANGLE_ALIGN_COLUMN))" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "*\n", - "***\n", - "*****\n", - "*******\n", - "*********\n", - "***********\n", - "*************\n", - "***************\n", - "*****************\n", - "*******************\n", - "*********************\n", - "***********************\n", - "*************************\n", - "***************************\n", - "*****************************\n", - "*\n", - "***\n", - "*****\n", - "*******\n", - "*********\n", - "***********\n", - "*\n", - "***\n", - "*****\n", - "*******\n", - "*********\n", - "***********\n", - "*************\n", - "***************\n", - "*****************\n", - "*******************\n", - "*********************\n", - "***********************\n", - "*************************\n", - "***************************\n", - "*****************************\n", - "*******************************\n", - "*********************************\n", - "***********************************\n", - "*************************************\n", - "***************************************\n" - ] - } - ] - } - ] -} \ No newline at end of file diff --git a/teaching materials/2_1_documentation_reading_data.ipynb b/teaching materials/2_1_documentation_reading_data.ipynb deleted file mode 100755 index 2af95be..0000000 --- a/teaching materials/2_1_documentation_reading_data.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Day 2 - Part 1: Documentation and reading data","provenance":[],"collapsed_sections":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"gQG7nLEn_SET"},"source":["# Readable code and documentation\n","> “Code is more often read than written.”\n","> — Guido van Rossum (Python creator) \n","\n","Readable code is very important. For yourself, and for others.\n","\n","Good practises:\n","- Use descriptive names for variables, arguments and functions.\n","- Keep functions small.\n","- Make sure functions have only one task.\n","- Add comments if the code is difficult to follow.\n","- Add *docstrings* to functions to describe what they do.\n","\n","\n","\n","\n"]},{"cell_type":"code","metadata":{"id":"Pu7jeXynAdRi"},"source":["def do_something(a, y):\n"," z = [a,y]\n"," for e in z:\n"," e[-1] = e[-1] + 1\n"," print(e)\n","\n","do_something([1,2,3], [4,5,6])"],"execution_count":null,"outputs":[]},{"cell_type":"code","metadata":{"id":"DHYIMRFqAM8f"},"source":["BY = 2\n","\n","def create_nested_list(list1, list2):\n"," return [list1, list2]\n","\n","def increment_last_el(list):\n"," list[-1] = list[-1] + BY\n"," return list\n","\n","def increment_last_element(list1, list2):\n"," \"\"\"\n"," Take two lists of numbers.\n"," Return them with incremented last value\n"," \"\"\"\n"," nested_list = create_nested_list(list1, list2)\n"," for sublist in nested_list:\n"," increment_last_el(sublist)\n"," return nested_list\n","\n","import math\n","answer = increment_last_element([1.0, \"a\"], [3, 5])\n","answer"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"J-BlN7p1F-cG"},"source":["# Reading data\n","\n","- Write a program that works with an existing data source\n","- In this course, we will use *comma separated value (CSV)* files"]},{"cell_type":"markdown","metadata":{"id":"z3QpNJC3LwCg"},"source":["## Upload and read a file"]},{"cell_type":"code","metadata":{"id":"oYF19uB-H2qW"},"source":["FILENAME = 'capitals.csv'\n","\n","def read_data():\n"," with open(FILENAME) as csv_file:\n"," return csv_file.read()\n","\n","print(read_data())"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"DTINkPwrIXHb"},"source":["## Use a library\n","- People before you have read CSV files\n","- No need to reinvent the wheel\n","- The `csv` module is part of the *standard library*, it comes with every Python installation\n","\n","\n"]},{"cell_type":"code","metadata":{"id":"591dGJTtJCz6"},"source":["import csv\n","\n","FILENAME = 'nogc_vietnamese.csv'\n","\n","def read_data():\n"," with open(FILENAME) as csv_file:\n"," reader = csv.reader(csv_file, delimiter=',')\n"," return list(reader)\n","\n","data = read_data()\n","data[10][0]"],"execution_count":null,"outputs":[]},{"cell_type":"markdown","metadata":{"id":"fmaAa4v6mVaU"},"source":["- You can unpack a row into multiple variables, this is useful if you know what the columns are"]},{"cell_type":"code","metadata":{"id":"-jPkiLGdmbxA","colab":{"base_uri":"https://localhost:8080/"},"executionInfo":{"status":"ok","timestamp":1637055787965,"user_tz":-60,"elapsed":216,"user":{"displayName":"Jelte van Boheemen","photoUrl":"https://lh3.googleusercontent.com/a-/AOh14GheLnTZKvy8P4D-Jl7hmsBhPGYHfOa1IeSLeP-Ynw=s64","userId":"10826796817228738014"}},"outputId":"917a53fd-f871-4b40-ab29-bda3f3512b91"},"source":["data = read_data()\n","\n","for row in data:\n"," first_column, *rest = row\n"],"execution_count":34,"outputs":[{"output_type":"stream","name":"stdout","text":["vietnamese\n","english natural_unnatural south middle north\n","Nam nhìn nó\n","Nam sees himself N 0.16 0.10 0.26\n","Nam nhìn nó\n","Nam sees himself UN 0.57 0.53 0.46\n","Nam nhìn mình\n","Nam sees himself’ N 0.37 0.17 0.33\n","Nam nhìn mình\n","Nam sees himself’ UN 0.30 0.48 0.44\n","Nam tự nhìn nó \n","Nam looks at himself N 0.50 0.50 0.56\n","Nam tự nhìn nó \n","Nam looks at himself UN 0.16 0.26 0.26\n","Tôi nhìn mình\n","I see myself N 0.49 0.36 0.40\n","Tôi nhìn mình\n","I see myself UN 0.49 0.37 0.38\n","Mày nhìn mình đấy à?\n","Are you looking at yourself? N 0.18 0.32 0.55\n","Mày nhìn mình đấy à?\n","Are you looking at yourself? UN 0.54 0.42 0.30\n","Chúng tôi khen mình\n","We praise ourselves N 0.41 0.25 0.37\n","Chúng tôi khen mình\n","We praise ourselves UN 0.41 0.49 0.28\n","Chúng nó khen mình\n","They praise themselves N 0.10 0.20 0.30\n","Chúng nó khen mình\n","They praise themselves UN 0.70 0.45 0.39\n","Chúng mày khen mình đó hả?\n","Are you (all) praising yourselves? N 0.20 0.19 0.31\n","Chúng mày khen mình đó hả?\n","Are you (all) praising yourselves? UN 0.70 0.49 0.39\n","Ho khen mình\n","They praise themselves N 0.16 0.17 0.22\n","Ho khen mình\n","They praise themselves UN 0.82 0.59 0.59\n","Chúng tôi khen chúng tôi \n","We praise ourselves N 0.33 0.16 0.08\n","Chúng tôi khen chúng tôi \n","We praise ourselves UN 0.49 0.63 0.60\n","Chúng nó khen chúng nó \n","They praise themselves N 0.41 0.39 0.43\n","Chúng nó khen chúng nó \n","They praise themselves UN 0.16 0.34 0.34\n","Họ khen họ \n","They praise themselves N 0.34 0.19 0.19\n","Họ khen họ \n","They praise themselves UN 0.27 0.51 0.52\n","Chúng mày khen chúng mày đó hả? \n","Are you all praising myself ? N 0.19 0.39 0.56\n","Chúng mày khen chúng mày đó hả? \n","Are you all praising myself ? UN 0.30 0.28 0.24\n","Chúng tôi tự khen chúng tôi \n","We praise ourselves N 0.41 0.31 0.31\n","Chúng tôi tự khen chúng tôi \n","We praise ourselves UN 0.50 0.48 0.54\n","Chúng nó tự khen chúng nó \n","They praise themselves N 0.75 0.60 0.57\n","Chúng nó tự khen chúng nó \n","They praise themselves UN 0.16 0.21 0.17\n","Chúng mày tự khen chúng mày đó hả ? \n","Are you all praising yourselves ? N 0.70 0.61 0.67\n","Chúng mày tự khen chúng mày đó hả ? \n","Are you all praising yourselves ? UN 0.20 0.15 0.12\n","Họ tự hen họ \n","They praise themselves N 0.90 0.64 0.64\n","Họ tự hen họ \n","They praise themselves UN 0.09 0.17 0.24\n"]}]}]} \ No newline at end of file diff --git a/teaching materials/cheatsheet_basics.ipynb b/teaching materials/cheatsheet_basics.ipynb deleted file mode 100755 index 6424376..0000000 --- a/teaching materials/cheatsheet_basics.ipynb +++ /dev/null @@ -1 +0,0 @@ -{"nbformat":4,"nbformat_minor":0,"metadata":{"colab":{"name":"Basics - Cheatsheet.ipynb","provenance":[],"collapsed_sections":[]},"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"}},"cells":[{"cell_type":"markdown","metadata":{"id":"fliaJAWJqSo8"},"source":["# Python basics cheatsheet\n","## Types\n","#### numbers\n","```python\n","0\n","2.0\n","-8\n","```\n","####strings (text)\n","```python\n","# string (text)\n","\"this is a string\"\n","'this is also a string'\n","```\n","#### booleans\n","```python\n","True\n","False\n","```\n","\n","\n","\n","\n","\n","\n","\n","\n"]},{"cell_type":"markdown","metadata":{"id":"0EXsKLzkuIjl"},"source":["## Operators\n","#### arithmetic\n","```python\n","1 + 1\n","8 - 2\n","10 * 4\n","12 / 3\n","```\n","#### string operators\n","```python\n","# concatenation\n","\"hello\" + \"world\"\n","# repetition\n","\"hello\"*3\n","```\n","#### comparison\n","```python\n","1 == 1 # equals\n","\"hello\" != \"goodbye\" # not equals\n","2 > 1 # greater than\n","1 < 2 # smaller than\n","```"]},{"cell_type":"markdown","metadata":{"id":"yDVm1CyMuEfO"},"source":["## Variables\n","#### assigning and reassigning\n","```python\n","a = 20\n","a = \"hello\"\n","b = 2 + 1\n","c = 3 + b\n","```"]},{"cell_type":"markdown","metadata":{"id":"OO8XCq8_uCP_"},"source":["## Lists\n","```python\n","[]\n","[1, 2, 3]\n","[\"word\", True, 8.2]\n","```\n","#### accessing and setting elements\n","```python\n","list[index]\n","list[index] = \"new value\"\n","```\n","\n","#### adding elements\n","```python\n","list = list + [element]\n","list.append(element)\n","list = list + [element1, element2]\n","```\n","\n","#### slicing (x to y)\n","```python\n","list[x:y]\n","```\n","\n","#### slicing (x to end)\n","```python\n","list[x:]\n","```"]},{"cell_type":"markdown","metadata":{"id":"bsbP2Rgkt8_A"},"source":["\n","## Loops\n","#### loop over a list\n","```python\n","for element in list:\n"," # execute some code\n"," # and some more code\n","```\n","#### loop over a string\n","```python\n","for letter in \"string\":\n"," # execute some code\n","```\n","#### list of lists\n","```python\n","nested_list = [[element1, element2], [element3, element4]]\n","sublist1 = nested_list[0]\n","sublist2 = nested_list[1]\n","\n","for sublist in nested_list: \n"," for element in sublist:\n"," # execute some code\n","```\n","\n","\n","\n","\n"]},{"cell_type":"markdown","metadata":{"id":"rTjNruPOu5BI"},"source":["## Conditionals\n","#### if-elif-else\n","```python\n","if condition1:\n"," # execute some code\n","elif condition2:\n"," # execute some other code\n","else:\n"," # execute code if no conditions are true\n","```\n","#### logical operators\n","```python\n","condition1 and condition2\n","condition1 or condition2\n","not condition\n","```"]}]} \ No newline at end of file diff --git a/teaching materials/cheatsheet_functions.ipynb b/teaching materials/cheatsheet_functions.ipynb deleted file mode 100644 index b71f55e..0000000 --- a/teaching materials/cheatsheet_functions.ipynb +++ /dev/null @@ -1,108 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Functions-cheatsheet.ipynb", - "provenance": [] - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "K10hhF1isHEh" - }, - "source": [ - "# Functions cheatsheet\n", - "\n", - "## Defining a function\n", - "\n", - "```python\n", - "def function_name(parameter1, parameter2):\n", - " # Statements that involve the parameters here.\n", - " # Variables defined here are only visible inside\n", - " # the function.\n", - " return # Expression with the end result here.\n", - "```\n", - "\n", - "## Calling a function\n", - "\n", - "```python\n", - "a_variable = function_name(argument1, argument2)\n", - "```\n", - "\n", - "## Optional parameters\n", - "\n", - "```python\n", - "# When defining the function\n", - "def function_name(required, optional=None):\n", - " if optional is None:\n", - " optional = # Insert expression here.\n", - " # Rest of function body.\n", - "\n", - "# When calling the function,\n", - "# ... including only the required parameter:\n", - "function_name(argument1)\n", - "# ... including the required and the optional parameter:\n", - "function_name(argument1, argument2)\n", - "```\n", - "\n", - "## Named arguments\n", - "\n", - "- Let you pass one optional argument while skipping many others.\n", - "- Let you pass arguments in a different order.\n", - "\n", - "```python\n", - "function_name(named_parameter=argument)\n", - "```\n", - "\n", - "## Constants\n", - "\n", - "```python\n", - "# Place this at the top of your program.\n", - "CONSTANT_NAME = 'value of the constant'\n", - "# Everywhere in your program, use CONSTANT_NAME instead\n", - "# of the literal 'value of the constant'.\n", - "# The value of CONSTANT_NAME must never change.\n", - "```\n", - "\n", - "## Setting a breakpoint\n", - "\n", - "```python\n", - "import pdb; pdb.set_trace()\n", - "```\n", - "\n", - "## Debugger commands\n", - "\n", - "```\n", - "p - print the value of the named variable\n", - "n - go to next line\n", - "s - step into next function call\n", - "u - continue until the current function returns\n", - "c - continue until the next breakpoint, or until the program ends\n", - "q - stop now without finishing the program\n", - "h - help, overview of commands\n", - "```" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "syk7ykOQiAZ7" - }, - "source": [ - "" - ], - "execution_count": null, - "outputs": [] - } - ] -} \ No newline at end of file diff --git a/teaching materials/tips.ipynb b/teaching materials/tips.ipynb deleted file mode 100644 index 3267450..0000000 --- a/teaching materials/tips.ipynb +++ /dev/null @@ -1,2250 +0,0 @@ -{ - "nbformat": 4, - "nbformat_minor": 0, - "metadata": { - "colab": { - "name": "Tips.ipynb", - "provenance": [], - "toc_visible": true - }, - "kernelspec": { - "name": "python3", - "display_name": "Python 3" - }, - "language_info": { - "name": "python" - } - }, - "cells": [ - { - "cell_type": "markdown", - "metadata": { - "id": "eL_rkx7cIm77" - }, - "source": [ - "# Tips\n", - "\n", - "This notebook contains tips for the final exercise of the 2021 CDH entry level Python course at Utrecht University. Participants were asked to think of an analysis that they might want to perform and to submit a description of this analysis in advance of the course. The tips in this notebook were chosen based on those submissions.\n", - "\n", - "The tips in this notebook build on top of the [basics cheatsheet](https://colab.research.google.com/drive/1um6_5Pd6biIK0TPAP6bIGnx3qiM3iTRj?usp=sharing) and the [functions cheatsheet](https://colab.research.google.com/drive/1O0ARbDaX7_A7tNF1QWjQAVlu8jY4F24o?usp=sharing).\n", - "\n", - "While the notebook is written such that you can read it top to bottom, you are welcome to cherry-pick the topics that interest you. There is a table of contents in the left margin. Some sections contain internal links to other sections.\n", - "\n", - "As a general tip, you can get a complete overview of the Python standard library [over here][python-libs].\n", - "\n", - "[python-libs]: https://docs.python.org/3/library/index.html" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "wBOMsp2twgbB" - }, - "source": [ - "## Converting between types\n", - "\n", - "String to int:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "1aU45qPvwntM" - }, - "source": [ - "int('123')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "cfrMiRd3wy9d" - }, - "source": [ - "Integer to string:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "LNJEIXCtw6rq" - }, - "source": [ - "str(123)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "RtGlRbICxf__" - }, - "source": [ - "Float to string:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "ejGhZs8SxjUN" - }, - "source": [ - "str(0.5)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "TdaVUNpBxmQ8" - }, - "source": [ - "String to float:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "Nwk3D9VExoU_" - }, - "source": [ - "float('0.5')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "6CYPccQYxwCm" - }, - "source": [ - "Boolean to string:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "JJf6fjNGxzvC" - }, - "source": [ - "str(True)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "LV7o-rkDx3MY" - }, - "source": [ - "String to boolean:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "UUPNXO4mx5eb" - }, - "source": [ - "print('Direct boolean from string does not work:', bool('False'))\n", - "\n", - "# So we have to write a function.\n", - "def boolean_from_string(string):\n", - " if string == 'False':\n", - " return False\n", - " else:\n", - " return True\n", - "\n", - "print(boolean_from_string('True'))\n", - "print(boolean_from_string('False'))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "CfnNAUKmyhOj" - }, - "source": [ - "Integer to float:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "st9vZgf0yixm" - }, - "source": [ - "float(123)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Gmw_vdGoyl3c" - }, - "source": [ - "Float to integer:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "JZ_l3IdhynF-" - }, - "source": [ - "int(0.5)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "97z6FUGz8uAS" - }, - "source": [ - "## Strings\n", - "\n", - "Strings have a couple of tricks that may be useful for the final exercise. We illustrate them quickly below. A complete overview of all string methods can be found [here](https://docs.python.org/3/library/stdtypes.html#text-sequence-type-str).\n", - "\n", - "[`str.startswith`](https://docs.python.org/3/library/stdtypes.html#str.startswith) and [`str.endswith`](https://docs.python.org/3/library/stdtypes.html#str.endswith) will tell you whether a string begins or ends with a particular other string, respectively." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "07ik0vd2-6tQ" - }, - "source": [ - "for word in ['magazine', 'kangaroo', 'rooster', 'broom']:\n", - " if word.startswith('roo'):\n", - " print('\"' + word + '\" starts with \"roo\"')\n", - " if word.endswith('roo'):\n", - " print('\"' + word + '\" ends with \"roo\"')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "FVyAad6OAtNX" - }, - "source": [ - "[`str.lower`](https://docs.python.org/3/library/stdtypes.html#str.lower) and [`str.upper`](https://docs.python.org/3/library/stdtypes.html#str.upper) return a copy of a string that is converted to all lowercase or all uppercase, respectively. These functions are useful when you don't want case to influence comparisons." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "9sjgompVA_Qi" - }, - "source": [ - "word1 = 'banana'\n", - "word2 = 'Banana'\n", - "\n", - "print('case-sensitive:', word1 == word2)\n", - "print('case-insensitive:', word1.lower() == word2.lower())" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "TyjWFAWR_0Dp" - }, - "source": [ - "[`str.join`](https://docs.python.org/3/library/stdtypes.html#str.join) can glue a sequence of strings together, as we have seen in [the Monday afternoon session](https://colab.research.google.com/drive/10H5QM0jBiDZJdjqPlvBia4oZMnIbxvuy?usp=sharing)." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "JlqAc5N8AQPu" - }, - "source": [ - "print(' + '.join(['1', '2', '3', '4']))\n", - "print(', '.join(['do', 're', 'mi', 'fa', 'sol', 'la', 'ti', 'do']))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "g0x1VvE5B71w" - }, - "source": [ - "[`str.split`](https://docs.python.org/3/library/stdtypes.html#str.split) is the opposite of `str.join`: it will split a string by a given separator and return a list with the fragments. If you don't specify a separator, it will split by whitespace." - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "R11wYmWFCVdb", - "outputId": "ca8804e9-80a5-4771-e3f0-1adee880f66b" - }, - "source": [ - "print('1 + 2 + 3 + 4'.split(' + '))\n", - "print('1 + 2 + 3 + 4'.split('+'))\n", - "print('1 + 2 + 3 + 4'.split())\n", - "print('1 2 3 4'.split())" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "['1', '2', '3', '4']\n", - "['1 ', ' 2 ', ' 3 ', ' 4']\n", - "['1', '+', '2', '+', '3', '+', '4']\n", - "['1', '2', '3', '4']\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "0csn-TVPC8qG" - }, - "source": [ - "[`str.splitlines`](https://docs.python.org/3/library/stdtypes.html#str.splitlines) is basically `str.split('\\n')`, but it cleverly recognizes many types of line endings (which might differ between platforms) and it has an option to keep the line endings in the resulting fragments." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "k1xy1XmaED7X" - }, - "source": [ - "[`str.strip`](https://docs.python.org/3/library/stdtypes.html#str.strip) will return a new string with the whitespace removed from the beginning and end. You can also specify a different set of characters that should be removed. The default mode of removing whitespace is useful for cleaning up text that was downloaded from the internet or that was copypasted from some kind of document." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "djsFEC5DE6md" - }, - "source": [ - "\" This string isn't very tidy. \".strip()" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "G4tC_OiFFth3" - }, - "source": [ - "### Escapes\n", - "\n", - "There are some characters that normally aren't allowed to appear in a literal string. We can shoehorn them in anyway by placing a backslash `\\` in front of the character, or another letter that acts as a placeholder. This is called *escaping* the character. The combination of the backslash and the following character is called an *escape sequence*. Python also uses these escape sequences when echoing raw strings back at us. The following escape sequences occur often:\n", - "\n", - "`\\n` - linefeed (\"newline\") character.\n", - "\n", - "`\\r\\n` - carriage return plus linefeed. For archeological reasons I will not go into, these two characters together count as a single line separator in Microsoft Windows. So you are likely to find it in files that were created in Windows.\n", - "\n", - "`\\t` - tab character.\n", - "\n", - "`\\'` - straight single quote (escape not needed in strings delimited by double quotes).\n", - "\n", - "`\\\"` - straight double quote (escape not needed in strings delimited by single quotes).\n", - "\n", - "`\\\\` - the backslash itself.\n", - "\n", - "You can get a complete overview of escape sequences if you scroll down from [here](https://docs.python.org/3/reference/lexical_analysis.html#string-and-bytes-literals)." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "mUmNSdNzMq_M" - }, - "source": [ - "### Format strings\n", - "\n", - "A format string is a perfectly normal string that contains some special notation, i.e., pairs of braces `{}`. While the presence of those braces does not oblige us to anything, we *can* use their presence (and insert them on purpose) in order to benefit from the [`str.format`](https://docs.python.org/3/library/stdtypes.html#str.format) method. For example, if I have the following string,\n", - "\n", - "```python\n", - "'Ta-da!'\n", - "```\n", - "\n", - "I can turn it into a format string simply by inserting a pair of braces, anywhere I like:\n", - "\n", - "```python\n", - "'Ta-da: {}'\n", - "```\n", - "\n", - "If I call `str.format` on a format string, it will interpret pairs of braces as placeholders and replace them by any arguments that I pass." - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 37 - }, - "id": "NQmg3z2cPPFW", - "outputId": "c6647728-a0ac-4f50-e5ed-36e9b0c94cbf" - }, - "source": [ - "'Ta-da: {}'.format('this is Python!')" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "application/vnd.google.colaboratory.intrinsic+json": { - "type": "string" - }, - "text/plain": [ - "'Ta-da: this is Python!'" - ] - }, - "metadata": {}, - "execution_count": 29 - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ZtwiQhMJPcAd" - }, - "source": [ - "You can insert as many placeholders and pass as many arguments as you like, as long as there are at least as many arguments as placeholders. Of course, you usually want the number of arguments to exactly match the number of placeholders in the format string, but `str.format` will simply skip any arguments that remain." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "x_f2iRsQQNqr" - }, - "source": [ - "print('Ta-da: {}'.format(1, 2, 3))\n", - "print('Ta{}da{} {}'.format('-', ':', 'success!'))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "7GOzHkgLRGYi" - }, - "source": [ - "Format strings are a great way to compose strings out of some fixed parts and some variable parts, especially if the fixed parts aren't entirely regular. Consider the following code, which you might have written in [exercise 3]():" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "mTVp_EOmR_nm" - }, - "source": [ - "YELL_START = 'Go go '\n", - "YELL_END = '!!!'\n", - "\n", - "def yell(name):\n", - " return YELL_START + name + YELL_END\n", - "\n", - "yell('Jelte')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "fwTdCa4QSOuv" - }, - "source": [ - "Using a format string, this code would be a bit more explicit and a bit easier to read and write as well:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "KvbXfNykSmiB" - }, - "source": [ - "YELL_FORMAT = 'Go go {}!!!'\n", - "\n", - "def yell(name):\n", - " return YELL_FORMAT.format(name)\n", - "\n", - "yell('Jelte')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "TbnEKRdlTGTj" - }, - "source": [ - "The above discussion addresses about 90% of all string formatting needs, but for the remaining 10%, `str.format` is chock-full of bells and whistles. You can use named arguments, reuse the same argument in multiple places, align placeholders to a particular width with filler characters of choice, specify how to format numbers, and so forth and so on. You can read all about it [here](https://docs.python.org/3/library/string.html#formatstrings)." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "0FJ_vXwlwT_5" - }, - "source": [ - "### Cross-platform file paths\n", - "\n", - "Consider the location of the current notebook (`Tips.ipynb`). It is located inside a folder called `Colab Notebooks`, which is inside a folder called `My Drive`, which is inside my Google Drive account. In Windows, we write such paths as follows:\n", - "\n", - " My Drive\\Colab Notebooks\\Tips.ipynb\n", - "\n", - "In macOS and Linux, on the other hand, we separate the path components with forward slashes:\n", - "\n", - " My Drive/Colab Notebooks/Tips.ipynb\n", - "\n", - "In Python, we often need to create a string with a file path, which would be different depending on whether the code is running on Windows or elsewhere (backslashes appear twice because they need to be [escaped](#scrollTo=Escapes)):\n", - "\n", - "```py\n", - "windows_path = 'My Drive\\\\Colab Notebooks\\\\Tips.ipynb'\n", - "maclinux_path = 'My Drive/Colab Notebooks/Tips.ipynb'\n", - "```\n", - "\n", - "We generally want our code to work on all platforms, without having to change the path notation or having to introduce `if`/`else` statements everywhere to choose between alternative file paths. This is where the standard module [`os.path`][os.path] comes to our rescue. It provides a function called `join`, which glues the path components together with the separator that is appropriate for whatever platform the code is running on:\n", - "\n", - "```py\n", - "import os.path as op\n", - "\n", - "crossplatform_path = op.join('My Drive', 'Colab Notebooks', 'Tips.ipynb')\n", - "```\n", - "\n", - "The above snippet is repeated in the code cell below. If you run it, you will see that Google Colab runs on a system that uses the same path convention as macOS and Linux.\n", - "\n", - "Besides glueing path components together, [`os.path`][os.path] also provides tools for taking paths apart again and for converting back and forth between absolute and relative paths.\n", - "\n", - "[os.path]: https://docs.python.org/3/library/os.path.html" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "AfuPbq5iwRsR", - "outputId": "48cb5576-1a6d-4b82-fcb2-46c76c0bbb3d" - }, - "source": [ - "import os.path as op\n", - "\n", - "crossplatform_path = op.join('My Drive', 'Colab Notebooks', 'Tips.ipynb')\n", - "\n", - "print(crossplatform_path)" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "My Drive/Colab Notebooks/Tips.ipynb\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "zHyB8HjpU9hv" - }, - "source": [ - "## Tuples\n", - "\n", - "When you have two things, you can call them a pair. When you have three things, you can call them a triple. Four things, a quadruple. We continue with quintuple, sextuple, septuple, octuple. See where this is going? ;-)\n", - "\n", - "The general mathematical term for small groups like those is *N*-tuple, commonly abbreviated as \"tuple\". Python has a data type for tuples, which you almost never need to be aware of. It's a feature that [silently](https://docs.python.org/3/library/functions.html#func-tuple) makes things work, just like cleaners silently and inconspicuously prevent our society from collapsing.\n", - "\n", - "You don't need to create your own tuples for the final exercise (at least not consciously), but since the terminology is bound to come up, I will give a short explanation of what they are. A tuple is similar to a list, with two main differences:\n", - "\n", - "1. Tuples are intended for small(ish) groups of values, while lists will happily store millions of values for you.\n", - "2. Tuples are *immutable*: you cannot change their contents after creation.\n", - "\n", - "When you see values separated by commas, and they are not in a list, a parameter list or an argument list, you are probably looking at a tuple. I will mention it when they appear in other tips. Here, I will just mention two situations where tuples may appear all by themselves.\n", - "\n", - "Tuples are sometimes used to return two or more values from a function at the same time. For example, the built-in function [`divmod`](https://docs.python.org/3/library/functions.html#divmod) can tell you the quotient and remainder of two numbers in one call:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "LrwtKmfpayq0" - }, - "source": [ - "quotient, remainder = divmod(29, 11)\n", - "\n", - "print('quotient:', quotient, 'check:', quotient == 29 // 11)\n", - "print('remainder:', remainder, 'check:', remainder == 29 % 11)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Qm-KzHTdbtCq" - }, - "source": [ - "`divmod(29, 11)` was returning a tuple and we *unpacked* that tuple into the variables `quotient` and `remainder`. That's because their names where to the left of the assignment operator. Tuple unpacking was already briefly mentioned in [the Tuesday morning session](https://colab.research.google.com/drive/11mQhWcu5zLe05UhokHkD4s38SjTSqJjH#scrollTo=fmaAa4v6mVaU). On the other hand, when we put comma-separated values to the *right* of an assignment operator, it means that we *pack* those values into a new tuple. We can do a nice trick with this and swap two variables by packing them into a tuple and then immediately unpacking them again in reverse order:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "ttECYgPLc6ra" - }, - "source": [ - "winner = 'Bert'\n", - "loser = 'Ernie'\n", - "\n", - "winner, loser = loser, winner\n", - "\n", - "print('winner:', winner)\n", - "print('loser:', loser)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "hpnieEnwpmhK" - }, - "source": [ - "## Dictionaries\n", - "\n", - "On the first day of the course, we have seen lists, which can hold an arbitrary number of values. The values are numbered sequentially, with the first having index `0`. You can create an empty list by calling `list()` or by writing an empty pair of square brackets, `[]`.\n", - "\n", - "A [dictionary][dict] is also a data structure that can hold an arbitrary number of values. The difference from a list is that the values are not numbered sequentially. Instead, every value has an arbitrary unique **key** which you need to set explicitly. An empty dictionary is created by calling `dict()` or by writing an empty pair of braces, `{}`.\n", - "\n", - "Dictionaries are useful when you want to associate values with each other. For example, your dataset might have a nominal column called `fruit`, with the possible levels being `apple`, `banana` and `cherry`, and you might want to count for each level in how many rows it occurs. In this case your will be associating fruits with frequencies, and a dictionary is the appropriate data structure for storing those associations. In the code below, we illustrate how dictionaries work and how you might use one to tally frequencies.\n", - "\n", - "[dict]: https://docs.python.org/3/library/stdtypes.html#mapping-types-dict" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "7JVH7h_Bu6mS" - }, - "source": [ - "# In the general case, we can create a dictionary and\n", - "# immediately set key-value pairs with the brace notation:\n", - "example_dict = {\n", - " 'apple': 'juicy',\n", - " 'banana': 'fragrant',\n", - " 'cherry': 'sweet',\n", - "}\n", - "\n", - "# Retrieving a value associated with a key can be done by\n", - "# placing the key between square brackets, similar to\n", - "# indexing a list:\n", - "example_dict['cherry']" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "zhIMlt2TxoGC" - }, - "source": [ - "# If you try to read a key that isn't present in the \n", - "# dictionary, you will get a KeyError:\n", - "example_dict['date']" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "vOk3VAnIyWgz" - }, - "source": [ - "# If we want to know whether a key is present in a dict,\n", - "# we can use the `in` operator:\n", - "print('cherry' in example_dict)\n", - "print('date' in example_dict)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "yE8urPkiy-Iw" - }, - "source": [ - "# If we want to retrieve the value for a key if it exists,\n", - "# and fall back to a default value otherwise, we can use `get`:\n", - "print(example_dict.get('cherry', 'oops'))\n", - "print(example_dict.get('date', 'oops'))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "BSXQQZfs0OfU" - }, - "source": [ - "# You can update and add key-value pairs by assignment.\n", - "example_dict['banana'] = 'yellow'\n", - "example_dict['date'] = 'wrinkly'\n", - "\n", - "# You can remove keys with the `del` operator.\n", - "del example_dict['apple']\n", - "\n", - "# Let's see what we have now.\n", - "example_dict" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "VisTnjOjxodE" - }, - "source": [ - "In the next two examples, we use [tuple unpacking](#scrollTo=Tuples)." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "XnZcOLDM1zM-" - }, - "source": [ - "# We can iterate over the keys and values of dictionary.\n", - "for key, value in example_dict.items():\n", - " print('A', key, 'is', value)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "code", - "metadata": { - "id": "PdcV9FVm2X48" - }, - "source": [ - "# Now let's see how we can use a dictionary to tally.\n", - "# Suppose we have the following table of fruit orders:\n", - "orders = [\n", - " ['2021-11-15', 'banana', 100],\n", - " ['2021-11-16', 'apple', 33],\n", - " ['2021-11-17', 'banana', 150],\n", - "]\n", - "\n", - "# We will pretend we haven't already seen those data and\n", - "# start with an empty dict.\n", - "fruit_tally = {}\n", - "\n", - "# Now we iterate over the orders and fill our dict.\n", - "for date, fruit, quantity in orders:\n", - " # First we retrieve how many times we have seen `fruit`\n", - " # before. If we haven't seen it before, the key isn't in the\n", - " # dict, so we provide 0 as a fallback value.\n", - " tally = fruit_tally.get(fruit, 0)\n", - " # Now we can add or update the tally for this `fruit`.\n", - " fruit_tally[fruit] = tally + 1\n", - "\n", - "# Did we count correctly?\n", - "fruit_tally" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "g_90Pk6j4Plm" - }, - "source": [ - "For exercise, you can try adapting the above code example to compute total ordered quantities per fruit, or a list of order dates per fruit." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "hhu9T00mFSHd" - }, - "source": [ - "## Iterables\n", - "\n", - "In the [FizzBuzz exercise](https://colab.research.google.com/drive/1P68w4Ewzptp5KLo5EMMowKOSywFMzoc8#scrollTo=FMySjPAXx4v1), we saw the following notation for creating a list with the integers from `0` (inclusive) to `101` (exclusive):\n", - "\n", - "```python\n", - "list(range(0, 101))\n", - "```\n", - "\n", - "We later also saw this notation in [the Monday afternoon session](https://colab.research.google.com/drive/10H5QM0jBiDZJdjqPlvBia4oZMnIbxvuy#scrollTo=Jwfbo50wBLfF&line=1&uniqifier=1). In that case, we passed a third argument to `range` to set the step size to `2`, so that only every second integer was included in the range. For completeness, I'll mention that if you pass only one argument, `range` will interpret that as the end value and assume that you want to start at `0`.\n", - "\n", - "It's clear what such a `list(range(begin, end))` expression does, but the curious might wonder what you get if you leave off the outer `list()`. What is a `range` just by itself? In any case, you can still loop over it:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "XTmiVuEAGJlL" - }, - "source": [ - "for number in range(0, 3):\n", - " print(number)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "axzQrGdBLWDF" - }, - "source": [ - "However, unlike with a list, we cannot add our own elements to it:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 164 - }, - "id": "oHDOpj2GLevE", - "outputId": "2d0ae6bd-61b2-497a-e8da-b1a45d1c3b97" - }, - "source": [ - "range(0, 3).append(3)" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "error", - "ename": "AttributeError", - "evalue": "ignored", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m Traceback (most recent call last)", - "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mappend\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m3\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[0;31mAttributeError\u001b[0m: 'range' object has no attribute 'append'" - ] - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "6q2Tt_4eKc_K" - }, - "source": [ - "If we try to print it, it remains mysterious:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "-MtW-ANdKn_d", - "outputId": "39abd51e-e1bf-4ef9-997a-52d88f452448" - }, - "source": [ - "print(range(0, 3))" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "range(0, 3)\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "X6KSp6FbMPRP" - }, - "source": [ - "I will no longer keep you in suspense. The value returned by [`range`][range] is a *generator*. You can think of a generator as a function that returns multiple times, each time producing the next value in some kind of sequence. This means that a generator, unlike a list, does not store all elements of its sequence at the same time; rather, it produces the next one when you ask for it.\n", - "\n", - "> For the final exercise, you don't need to write generators yourself, so we will not spend any text on how to do that. It is however useful to know how to use them, so we discuss that below.\n", - "\n", - "Python's `for` loop knows how to take one value at a time out of a generator, just like it knows how to take one value at a time out of a list. We call the more general class of things that `for` can loop over *iterables*. There are many more types of iterables besides lists and generators (including [tuples](#scrollTo=Tuples) and [dictionaries](#scrollTo=Dictionaries)) and `for` is able to deal with all of them, because all iterables follow the same **iterator convention**.\n", - "\n", - "In fact, this convention is not restricted to `for`. Most functions in the Python standard library that work with sequences, accept not just lists but any iterable. We have already seen this in action when we did `list(range(0, 101))`: `list` accepted an iterable, `range(0, 101)`, took out its values one by one, stored all of them in a list, and finally returned that list to you.\n", - "\n", - "Since generators don't store all of their values at the same time and we might not always need all values in a sequence, they are potentially more efficient than lists. For this reason, many standard library functions also *return* generators rather than lists.\n", - "\n", - "By combining functions that consume and return iterables, we can often replace loops by shorter expressions. In the next few subsections, we illustrate the most important functions on iterables.\n", - "\n", - "[range]: https://docs.python.org/3/library/functions.html#func-range" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "RelVVKVzX9T7" - }, - "source": [ - "### `enumerate`\n", - "\n", - "The built-in [`enumerate`][enumerate] accepts any iterable and returns a generator. As the name suggests, it numbers the values in the input sequence, while also echoing back the values themselves (in [pairs](#scrollTo=Tuples)):\n", - "\n", - "[enumerate]: https://docs.python.org/3/library/functions.html#enumerate" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "Zq8dHhH-Y-Cx" - }, - "source": [ - "example_list = ['Colorless', 'green', 'ideas', 'sleep', 'furiously']\n", - "\n", - "list(enumerate(example_list))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "LMPR_En8Zhn7" - }, - "source": [ - "This can be useful when you are looping over a sequence, and you need not only the values but also their index in the sequence:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "ADqR2KG2Zdkc" - }, - "source": [ - "for index, value in enumerate(example_list):\n", - " print('Word number', index, 'is', value)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "cSdPo0RGbvre" - }, - "source": [ - "For comparison, this is what the above loop would look like without `enumerate`:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "tEOM7Iwwbz9r" - }, - "source": [ - "index = 0\n", - "for value in example_list:\n", - " print('Word number', index, 'is', value)\n", - " index = index + 1" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "vX59S1uDaBLI" - }, - "source": [ - "### `filter`\n", - "\n", - "The built-in [`filter`][filter] accepts a function and an iterable. It passes each value in the iterable to the function in a separate call. It returns a generator with only the values in the input sequence for which the function returned `True`.\n", - "\n", - "[filter]: https://docs.python.org/3/library/functions.html#filter" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "YgQ2RCRbbJDY" - }, - "source": [ - "def odd(number):\n", - " return number % 2 == 1\n", - "\n", - "fibonacci_10 = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]\n", - "\n", - "list(filter(odd, fibonacci_10))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "30NBqwSZbqee" - }, - "source": [ - "For comparison, this is what the last line would look like without `filter`:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "UuzJGcjOcOL8" - }, - "source": [ - "result_list = []\n", - "for number in fibonacci_10:\n", - " if odd(number):\n", - " result_list.append(number)\n", - "result_list" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "81vNGdqgc1PI" - }, - "source": [ - "### `map`\n", - "\n", - "The built-in [`map`][map] accepts a function and an iterable. It passes each value in the iterable as the first argument to the function in a separate call. It returns a generator with the return values of each of those calls.\n", - "\n", - "[map]: https://docs.python.org/3/library/functions.html#map" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "Gdw4kFoCeQ4x" - }, - "source": [ - "def square(number):\n", - " return number ** 2\n", - "\n", - "list(map(square, range(10)))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "CMWKdfZued1f" - }, - "source": [ - "For comparison, code without `map` that produces the same output as the last line:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "I13FNH_ZeptA" - }, - "source": [ - "result_list = []\n", - "for number in range(10):\n", - " result_list.append(square(number))\n", - "result_list" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "S5NtKmJ21L_u" - }, - "source": [ - "You can also pass multiple iterables to `map`. In that case, `map` will take one value from each iterable per iteration and pass the value from the first iterable as the first argument to the function, the corresponding value from the second iterable as the second argument, and so on. In the following example, we use a [format string](#scrollTo=Format_strings)." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "5W6NwA8D2Kz3" - }, - "source": [ - "sentence = '{} {} {} {}.'.format\n", - "\n", - "# The following lists have been shuffled.\n", - "# For fun, you can try reordering them so the correct words\n", - "# from each list match up again. :-)\n", - "# (But run the code first so you know what it does.)\n", - "properties = ['Gentle', 'Playful', 'Stubborn', 'Thirsty']\n", - "people = ['camels', 'plumbers', 'giants', 'children']\n", - "verbs = ['tighten', 'devour', 'ruin', 'capture']\n", - "objects = ['nightmares', 'massage chairs', 'cactuses', 'rusty fittings']\n", - "\n", - "phrases = map(sentence, properties, people, verbs, objects)\n", - "for phrase in phrases:\n", - " print(phrase)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "G7fup_SyBode" - }, - "source": [ - "Without `map` (and without `enumerate` or `range`), the last loop would have looked like this instead:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "9a1XKPuFBtpF" - }, - "source": [ - "index = 0\n", - "for prop in properties:\n", - " group = people[index]\n", - " verb = verbs[index]\n", - " obj = objects[index]\n", - " print(sentence(prop, group, verb, obj))\n", - " index = index + 1" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "9DCBUR61DNRr" - }, - "source": [ - "If you pass iterables of unequal lengths, `map` will stop at the end of the shortest iterable. In the next subsection, we will take a quick look at how this can sometimes be useful." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "pR-4fFPZDMOi" - }, - "source": [ - "# operator.mul is a function that multiplies two numbers. It\n", - "# does exactly the same thing as the `*` operator, but as a\n", - "# function so you can pass it as an argument to other functions.\n", - "# More about the operator module in the next subsection.\n", - "from operator import mul\n", - "\n", - "small = [1, 2, 3]\n", - "large = [5, 7, 11, 13, 17, 19, 23, 29]\n", - "\n", - "list(map(mul, small, large))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "yBYdJR9VHLQU" - }, - "source": [ - "### More built-in functions\n", - "\n", - "`range`, `enumerate`, `filter` and especially `map` are the functions on iterables that you'll be using the most. There are however more built-in functions on iterables worth knowing about. Below, we briefly mention a few.\n", - "\n", - "- [`all`](https://docs.python.org/3/library/functions.html#all) consumes an iterable. If the sequence contains at least one `False` value, it returns `False`. Otherwise it returns `True` (including when it is empty). It's like the `and` operator, but operating on an arbitrary number of operands instead of exactly two.\n", - "- [`any`](https://docs.python.org/3/library/functions.html#any) is the exact opposite of `all`: it returns `True` if the sequence contains at least one `True` value, otherwise `False`. Can be thought of as the \"long form\" of the `or` operator.\n", - "- [`len`](https://docs.python.org/3/library/functions.html#len) can tell you the length of lists, strings, and some other iterables that can \"know\" their size in advance, including `range`.\n", - "- [`list`](https://docs.python.org/3/library/functions.html#func-list), as we have seen in previous examples, can store the values from any iterable into a list.\n", - "- [`max`](https://docs.python.org/3/library/functions.html#max) can be passed a single iterable argument, in which case it will return the maximum value of the sequence. You can however also pass multiple arguments, in which case it will simply compare them directly (e.g. `max(range(10))` will return `9` and `max(3, 4)` will return `4`). Likewise for [`min`](https://docs.python.org/3/library/functions.html#min).\n", - "- [`str.join`](https://docs.python.org/3/library/stdtypes.html#str.join), which I covered in more detail in [Strings](#scrollTo=Strings), can take the strings that it will glue together from any iterable sequence.\n", - "- [`sum`](https://docs.python.org/3/library/functions.html#sum), as the name suggests, will return the sum of all values in an iterable sequence." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "LugfHklV0b4C" - }, - "source": [ - "### Operators\n", - "\n", - "Given two lists of numbers, we might want to create a third list where each element is the sum of the correponding elements of the first two lists. We cannot pass the `+` operator to `map`, because the `+` operator is not a function:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "ddcs1QaK1APC" - }, - "source": [ - "first_list = [1, 2, 3]\n", - "second_list = [7, 7, 5]\n", - "\n", - "list(map(+, first_list, second_list))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "Ix-TPRvY1Pc-" - }, - "source": [ - "Fortunately, the [`operator`](https://docs.python.org/3/library/operator.html) standard module exports function versions of most operators, so we can do this instead:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "UG_UUx8S1jQw" - }, - "source": [ - "from operator import add\n", - "\n", - "first_list = [1, 2, 3]\n", - "second_list = [7, 7, 5]\n", - "\n", - "list(map(add, first_list, second_list))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ezmNWLLM2G4w" - }, - "source": [ - "The operators that you would most likely use this way, and their corresponding functions exported from `operator`, are the following (full list [here](https://docs.python.org/3/library/operator.html#mapping-operators-to-functions)):\n", - "\n", - "`+` - `add` (for adding numbers)\n", - "\n", - "`+` - `concat` (for concatenating strings or lists)\n", - "\n", - "`-` - `neg` (unary minus to flip the sign of a number)\n", - "\n", - "`-` - `sub` (binary minus to subtract two numbers)\n", - "\n", - "`in` - `contains` (for checking whether a value appears in an iterable)\n", - "\n", - "`*` - `mul`\n", - "\n", - "`/` - `truediv` (`//` is `floordiv`)\n", - "\n", - "`%` - `mod`\n", - "\n", - "`**` - `pow`\n", - "\n", - "`<` - `lt`\n", - "\n", - "`>` - `gt`\n", - "\n", - "`==` - `eq`\n", - "\n", - "`!=` - `ne`" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "0SMYES0-gyBX" - }, - "source": [ - "### Bound methods\n", - "\n", - "In the `map` subsection, I used an [example](#scrollTo=5W6NwA8D2Kz3&line=1&uniqifier=1) with the notation `'{} {} {} {}.'.format`. I stored that in a variable and then passed that as a function to `map`. It turns out this is a general thing we can do in more situations, so let's briefly touch on how this works.\n", - "\n", - "The essence is that" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "51cj58Pdogj_" - }, - "source": [ - "'{} {} {} {}.'.format(1, 2, 3, 4)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "O-0kegzaonFi" - }, - "source": [ - "is equivalent to" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "GqxgL5Rgorx3" - }, - "source": [ - "str.format('{} {} {} {}.', 1, 2, 3, 4)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "3DWOZQHKpClX" - }, - "source": [ - "We generally use the first form because it is more convenient, but Python is actually translating it to the second form behind our backs. The [format string](#scrollTo=Format_strings) `'{} {} {} {}.'` is being passed as the first argument to the function `str.format` in both cases.\n", - "\n", - "If we do `'{} {} {} {}.'.format` without actually calling the function and passing an argument list, Python understands that we want to use `'{} {} {} {}.'` as the first argument when we later make the call. It returns a special, *bound* version of `str.format` that already has our format string filled in, so we only need to supply the remaining arguments. This is a special form of *partial application* (we will see the more general form of partial application in the [next subsection](#scrollTo=partial)). Python's support for this special form has something to do with classes and objects, which you can optionally read more about in [a later section](#scrollTo=Classes_and_objects).\n", - "\n", - "With this theory out of the way, let's look at a couple more examples of how we can use both bound and unbound functions in `map` and similar functions. We use [string](#scrollTo=Strings) and [dictionary](#scrollTo=Dictionaries) function in this example." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "xSptat6auBDW" - }, - "source": [ - "# We can map the unbound str.lower to lowercase a sequence of strings.\n", - "strings = ['Hawaii', 'Iceland', 'Hokkaido', 'Vanuatu']\n", - "print(list(map(str.lower, strings)))\n", - "\n", - "# We can filter by the bound dict.get to check for associated values.\n", - "topography = {\n", - " 'Iceland': 'volcanic',\n", - " 'Vanuatu': 'Melanesia',\n", - "}\n", - "# Give me only the islands I know something about.\n", - "print(list(filter(topography.get, strings)))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "EqorhEmy6pxq" - }, - "source": [ - "With bound methods, we can achieve ultimate minimalism in our [example](#scrollTo=fwTdCa4QSOuv&line=1&uniqifier=1) from the format strings section, repeated here:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "Q49H5CvR7DbK" - }, - "source": [ - "YELL_FORMAT = 'Go go {}!!!'\n", - "\n", - "def yell(name):\n", - " return YELL_FORMAT.format(name)\n", - "\n", - "yell('Jelte')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "kJnvBskM7GvW" - }, - "source": [ - "because we can suffice with this:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "BHiKKKM77JKL" - }, - "source": [ - "yell = 'Go go {}!!!'.format\n", - "\n", - "yell('Jelte')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "XO0Q3vhf74Nd" - }, - "source": [ - "### `itertools` and `functools`\n", - "\n", - "The [`itertools`](https://docs.python.org/3/library/itertools.html) and [`functools`](https://docs.python.org/3/library/functools.html) standard modules let you turn your iterable-fu up to 11. Most of the contents of these modules are a bit advanced, but there are a couple of tricks in there that might be useful during the final exercise. We quickly illustrate them below." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "ucNV6xs0Tr8x" - }, - "source": [ - "#### `repeat`\n", - "\n", - "[`itertools.repeat`](https://docs.python.org/3/library/itertools.html#itertools.repeat), as the name suggests, will keep repeating a value that you specify. *Forever*. That means you should definitely not try to loop over it! However, you can use it when you need to `map` a function that takes multiple arguments, where some arguments come from a (finite) iterable sequence while at least one argument is the same every time. Consider the following excerpt of the example code from [the Monday afternoon session](https://colab.research.google.com/drive/10H5QM0jBiDZJdjqPlvBia4oZMnIbxvuy?usp=sharing) (edited for brevity):" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "HbbMbbNvckz7" - }, - "source": [ - "def centered_stars(center, width):\n", - " padding = center - width // 2\n", - " return ' ' * padding + '*' * width\n", - "\n", - "lines = []\n", - "for width in range(1, 6, 2):\n", - " lines.append(centered_stars(2, width))\n", - "\n", - "print('\\n'.join(lines))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "YHOPuLOwh3Qx" - }, - "source": [ - "We can replace the loop by an expression using `map` and `repeat`:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "I8NMn7KUh-3S" - }, - "source": [ - "from itertools import repeat\n", - "\n", - "lines = map(centered_stars, repeat(2), range(1, 6, 2))\n", - "\n", - "print('\\n'.join(lines))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "PW2498IlmijJ" - }, - "source": [ - "#### `partial`\n", - "\n", - "[`functools.partial`](https://docs.python.org/3/library/functools.html#functools.partial) takes a function plus any number of other arguments, and then returns a new version of the function to which those arguments have already been applied." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "i_Pjs-rGnfH2" - }, - "source": [ - "from functools import partial\n", - "\n", - "# center_2_stars is a version of centered_stars when the first\n", - "# parameter (`center`) is fixed to the value 2. This version\n", - "# accepts only one argument, `width`.\n", - "center_2_stars = partial(centered_stars, 2)\n", - "\n", - "center_2_stars(3)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "yCkaJitHnrXk" - }, - "source": [ - "While `functools.partial` does not operate on iterables by itself, it can be really useful when you want to adjust functions before you pass them to `filter`, `map` and the like. We could have used it instead of `itertools.repeat` to eliminate the loop from our triangle example:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "jjr_D7jpoYul" - }, - "source": [ - "lines = map(center_2_stars, range(1, 6, 2))\n", - "\n", - "print('\\n'.join(lines))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "IRRPl6piyQn8" - }, - "source": [ - "`partial` also works with keyword arguments. In some cases, this makes it possible to partially apply arguments out of order. This doesn't work for the operators, but there are some workarounds possible. Consider writing a function that subtracts `3` from whatever number you pass to it:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "WT3OJFSr18MW" - }, - "source": [ - "def minus_3(number):\n", - " return number - 3\n", - "\n", - "minus_3(4)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "MVmN8nSt2Ow1" - }, - "source": [ - "It would be nice if we could skip writing a function ourselves and instead just combine `operator.sub` with `functools.partial`." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "DK8Y4dWHzY_J" - }, - "source": [ - "from operator import sub\n", - "from functools import partial\n", - "\n", - "minus_3 = partial(sub, b=3)\n", - "\n", - "minus_3(4)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "pQpjPTbb2oNd" - }, - "source": [ - "The above code doesn't work, but we can avoid the problem by adding `-3` instead of subtracting `+3`:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "H3MwPyuF27vg" - }, - "source": [ - "from operator import add\n", - "from functools import partial\n", - "\n", - "minus_3 = partial(add, -3)\n", - "\n", - "minus_3(4)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "-LH3TiwCpNbp" - }, - "source": [ - "#### `reduce`\n", - "\n", - "[`functools.reduce`](https://docs.python.org/3/library/functools.html#functools.reduce) is for when you want to combine (or *reduce*) all values from a sequence to a single value. It accepts a function, an iterable and an optional starting value. If you don't supply a starting value, it will use the first value in the sequence instead.\n", - "\n", - "`reduce` keeps a work-in-progress value of sorts, which is often called the *accumulator*. The accumulator is initially set to the starting value. For every remaining value in the iterable sequence, `reduce` calls the function with two arguments: the accumulator and the value itself. The return value from the function becomes the new accumulator. After the last value in the sequence, the latest accumulator is returned as the final result.\n", - "\n", - "For illustration, here is how you might use `reduce` to reverse a string:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "kN5Uw_iB6QE6" - }, - "source": [ - "from functools import reduce\n", - "\n", - "def prepend_letter(accumulator, next_letter):\n", - " return next_letter + accumulator\n", - "\n", - "def reverse_string(string):\n", - " # In this case, we reduce a sequence of characters to a new string.\n", - " return reduce(prepend_letter, string)\n", - "\n", - "reverse_string('abcdef')" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "AxfCOlrU7H75" - }, - "source": [ - "And here is how we could write our own implementations of the built-in functions `max` and `sum` using `reduce`:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "P1CltqPc7UvG" - }, - "source": [ - "from functools import reduce\n", - "from operator import add\n", - "\n", - "def greater(a, b):\n", - " if a < b:\n", - " return b\n", - " else:\n", - " return a\n", - "\n", - "def max(iterable):\n", - " return reduce(greater, iterable)\n", - "\n", - "def sum(iterable):\n", - " return reduce(add, iterable)\n", - "\n", - "numbers = [3, 5, 4]\n", - "\n", - "print('max:', max(numbers))\n", - "print('sum:', sum(numbers))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "_zR8E_94YHCv" - }, - "source": [ - "## Calculations\n", - "\n", - "As we have written in the course manual, Python is \"batteries included\"—it comes with a lot of functionality out of the box. This is certainly also the case for numerical computations and even some basic statistics. We highlight some common tools below.\n", - "\n", - "- The built-in functions [`abs`][abs], [`max`][max], [`min`][min], [`pow`][pow], [`round`][round] and [`sum`][sum] do exactly what the names suggest. You can also use the `**` operator for powers.\n", - "- The built-in [`range`][range] function, which we have seen before, lets you generate linear series of numbers.\n", - "- The [`math`][math] standard module contains a wealth of general mathematical functions and constants, such as [`log`][math.log], [`sqrt`][math.sqrt], [`cos`][math.cos], [`pi`][math.pi] and [`tau`][math.tau].\n", - "- The [`random`][random] standard module covers most random number generating needs, as well as random shuffling and sampling.\n", - "- The [`statistics`][statistics] standard module includes the common staples of statistical analysis, such as [`mean`][statistics.mean], [`median`][statistics.median], [`mode`][statistics.mode], [`stdev`][statistics.stdev], [`variance`][statistics.variance], [`covariance`][statistics.covariance], [`correlation`][statistics.correlation] and even a simple [`linear_regression`][statistics.linear_regression]. Unfortunately, however, the latter three are not available in Google Colab, because they were only recently added to the Python standard library and Colab is not running the latest (\"bleeding edge\") version of Python. The next two subsections offer some alternatives.\n", - "\n", - "A complete overview of numerical functionality in the Python standard library can be found [here][python-numeric].\n", - "\n", - "[abs]: https://docs.python.org/3/library/functions.html#abs\n", - "[max]: https://docs.python.org/3/library/functions.html#max\n", - "[min]: https://docs.python.org/3/library/functions.html#min\n", - "[pow]: https://docs.python.org/3/library/functions.html#pow\n", - "[range]: https://docs.python.org/3/library/functions.html#func-range\n", - "[round]: https://docs.python.org/3/library/functions.html#round\n", - "[sum]: https://docs.python.org/3/library/functions.html#sum\n", - "[math]: https://docs.python.org/3/library/math.html\n", - "[math.log]: https://docs.python.org/3/library/math.html#math.log\n", - "[math.sqrt]: https://docs.python.org/3/library/math.html#math.sqrt\n", - "[math.cos]: https://docs.python.org/3/library/math.html#math.cos\n", - "[math.pi]: https://docs.python.org/3/library/math.html#math.pi\n", - "[math.tau]: https://docs.python.org/3/library/math.html#math.tau\n", - "[random]: https://docs.python.org/3/library/random.html\n", - "[statistics]: https://docs.python.org/3/library/statistics.html\n", - "[statistics.mean]: https://docs.python.org/3/library/statistics.html#statistics.mean\n", - "[statistics.median]: https://docs.python.org/3/library/statistics.html#statistics.median\n", - "[statistics.mode]: https://docs.python.org/3/library/statistics.html#statistics.mode\n", - "[statistics.stdev]: https://docs.python.org/3/library/statistics.html#statistics.stdev\n", - "[statistics.variance]: https://docs.python.org/3/library/statistics.html#statistics.variance\n", - "[statistics.covariance]: https://docs.python.org/3/library/statistics.html#statistics.covariance\n", - "[statistics.correlation]: https://docs.python.org/3/library/statistics.html#statistics.correlation\n", - "[statistics.linear_regression]: https://docs.python.org/3/library/statistics.html#statistics.linear_regression\n", - "[python-numeric]: https://docs.python.org/3/library/numeric.html" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "xoBLhOpvmu2P", - "outputId": "f5fedaf1-74d0-4382-e343-e717cf567fd9" - }, - "source": [ - "!python --version" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "Python 3.7.12\n" - ] - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "rKxMNbMMuMCw" - }, - "source": [ - "### Computing covariance and correlation yourself\n", - "\n", - "Given two equally long sequences of numbers and their averages (which you might have already computed because you needed them elsewhere), you can compute the sample covariance and correlation as follows using [iterables](#scrollTo=Iterables):" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "moprSI-g90tZ" - }, - "source": [ - "from itertools import repeat\n", - "from operator import sub, mul\n", - "from statistics import mean, stdev\n", - "\n", - "def differences(series, average):\n", - " return map(sub, series, repeat(average))\n", - "\n", - "def covariance(series1, series2, average1=None, average2=None):\n", - " differences1 = differences(series1, average1 or mean(series1))\n", - " differences2 = differences(series2, average2 or mean(series2))\n", - " products = map(mul, differences1, differences2)\n", - " return sum(products) / (len(series1) - 1)\n", - "\n", - "def correlation(series1, series2, average1=None, average2=None):\n", - " '''Pearson's correlation coefficient.'''\n", - " cov = covariance(series1, series2, average1, average2)\n", - " stdev1 = stdev(series1, average1)\n", - " stdev2 = stdev(series2, average2)\n", - " return cov / (stdev1 * stdev2)\n", - "\n", - "column1 = [1, 2, 3, 4, 5, 6, 7]\n", - "column2 = [4, 5, 6, 5, 5, 8, 9]\n", - "column3 = [8, 7, 6, 5, 4, 3, 2]\n", - "\n", - "print('covariance 1-2:', covariance(column1, column2))\n", - "print('correlation 1-2:', correlation(column1, column2))\n", - "print('correlation 2-1:', correlation(column2, column1))\n", - "print('correlation 1-3:', correlation(column1, column3))\n", - "print('correlation 2-3:', correlation(column2, column3))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "JYTbShRDBoS1" - }, - "source": [ - "### Using covariance and correlation from an external package\n", - "\n", - "[pandas](https://pandas.pydata.org/pandas-docs/stable/index.html) provides implementations of [covariance](https://pandas.pydata.org/pandas-docs/stable/user_guide/computation.html#covariance), [correlation](https://pandas.pydata.org/pandas-docs/stable/user_guide/computation.html#correlation) and many other statistical functions. If you want to do serious statistics, you should probably use pandas or some other third-party package that can do the heavy lifting for you. If you choose this path, head over to [dataframes](#scrollTo=pandas_dataframes_and_read_csv) first." - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "F6mIIM3zLw1p" - }, - "source": [ - "## Classes and objects\n", - "\n", - "For the final exercise, you do not need to create your own classes. However, since you may encounter the terminology and the notation when using third-party packages, here is a *very* quick explanation.\n", - "\n", - "An **object** is a value with internal structure. For example, I might have a variable with the name `jack` that holds a description of my friend Jack. The parts of that description are called its **attributes**. In this example, `jack.name` might hold the string `'Jack'` and `jack.phone` might hold the string `'+31612345678'` (not his real phone number ;-). `jack` is the object and `name` and `phone` are its attributes.\n", - "\n", - "Attributes can hold all types of values, including functions. In the latter case, the attribute is also called a **method**. For example, `jack.call()` might dial Jack's number. Attributes might also themselves be objects with their own nested attributes, so you can have chains of names connected with dots, for example `house.kitchen.sink`. In the latter dotted name, `kitchen` and `sink` are both attributes, and `house` and `kitchen` must both be objects, though `sink` might be an object as well.\n", - "\n", - "Whenever you see two names connected with a dot, the left one must be an object. You have already encountered a few types of objects. Every list has an `.append()` method, so lists are objects. When you call `csv.reader()`, the `csv` module is an object (though we usually don't use the words \"attribute\" and \"method\" to refer to the parts of a module; we rather say that `csv.reader` is a *qualified name*). In fact, *nearly everything* in Python is an object; this is why it is called an *object-oriented* programming language.\n", - "\n", - "Objects are generally created using a **class**. You can think of a class as a template for creating objects of a particular shape. For example, our `jack` object might have been created using the `Person` class. We say that `jack` is an **instance** of `Person` and also that we **instantiated** `Person` when we created `jack`. Typically, you can expect all instances of a class to have the same attributes and methods. Packages often organize their documentation by class, listing the methods of its instances and their usage.\n", - "\n", - "Instantiating a class looks exactly like calling a function and storing the return value in a variable. The only visible clue that you're instantiating a class rather than calling a function, is that classes usually have a name starting with an uppercase letter:\n", - "\n", - "```py\n", - "jack = Person(name='Jack')\n", - "```\n", - "\n", - "There is no danger in thinking of a class instantiation as a function call, or in instantiating a class without knowing it because its name starts with a lowercase letter. In reality, however, a class is not a function but an object!" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "MoyqHwBhvBTH" - }, - "source": [ - "## Working with times and calendar dates\n", - "\n", - "The [`datetime`][datetime] standard module provides tools for working with dates and times. It exports the `date`, `time` and `datetime` [classes](#scrollTo=Classes_and_objects), which let you represent a date, a time or both, exactly as the names suggest.\n", - "\n", - "[datetime]: https://docs.python.org/3/library/datetime.html" - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "W5ZlB-uXkC6S" - }, - "source": [ - "### Parsing dates from text\n", - "\n", - "If you are working with dates for the final course exercise, it is most likely that you are extracting date strings from a CSV. Such a string might, for example, look like `'2021/11/15'`. In some cases, you may need to extract specific information from those dates, such as the year, month, hour or even weekday. For such use cases, it is advisable to convert the date string to a `date`, `time` or `datetime` object first by *parsing* it.\n", - "\n", - "The [`datetime.strptime`][datetime.strptime] function can do this job for you. It takes two parameters: the date string that needs to be parsed, and a second string that describes the *format* of the date. Our example above consisted of four digits that identify the year, a slash, two digits that identify the month, another slash, and finally two digits that identify the day of the month. We write that as `'%Y/%m/%d'`. In such a format string, a `%` with a letter after it is a placeholder for a particular piece of the date or time, while all other characters simply represent themselves. You can find a list of all available placeholders [here][datetime-formats].\n", - "\n", - "[datetime.strptime]: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-behavior\n", - "[datetime-formats]: https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "cOo_KnhWsR2m" - }, - "source": [ - "from datetime import datetime as dt\n", - "\n", - "yesterday_str = '2021/11/15'\n", - "date_format = '%Y/%m/%d'\n", - "\n", - "yesterday_obj = dt.strptime(yesterday_str, date_format)\n", - "print('datetime:', yesterday_obj)\n", - "\n", - "# dt.strptime always returns a full datetime, even if the input\n", - "# string and the format string contain only a date or only a time.\n", - "# You can reduce the datetime object to just a date or just a time\n", - "# by calling a method of the same name:\n", - "print('date: ', yesterday_obj.date())\n", - "print('time: ', yesterday_obj.time())" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "iDp5QxvpxZIo" - }, - "source": [ - "### Extracting information from date and time objects\n", - "\n", - "Once you have a `date`, `time`, or `datetime` object, extracting information from it is very easy, as we demonstrate below. [`datetime`][datetime.datetime] objects have all date-related attributes and methods of `date` as well as all time-related attributes and methods of `time`. You can find the most important attributes [here][datetime-attributes] and the most important methods [here][datetime-methods] (you can also scroll up from the latter link for some additional methods related to time zones).\n", - "\n", - "[datetime.datetime]: https://docs.python.org/3/library/datetime.html#datetime-objects\n", - "[datetime-attributes]: https://docs.python.org/3/library/datetime.html#datetime.datetime.year\n", - "[datetime-methods]: https://docs.python.org/3/library/datetime.html#datetime.datetime.utcoffset" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "M9pQ2otg0EQU" - }, - "source": [ - "# Year, month etcetera attributes are all represented as numbers.\n", - "print('year: ', yesterday_obj.year)\n", - "print('month: ', yesterday_obj.month)\n", - "print('hour: ', yesterday_obj.hour)\n", - "\n", - "# Python starts the week on Monday and starts numbering at zero.\n", - "print('weekday: ', yesterday_obj.weekday())\n", - "# The ISO 8601 standard also starts on Monday, but starts numbering at one.\n", - "print('isoweekday:', yesterday_obj.isoweekday())" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "GLBue3palj8M" - }, - "source": [ - "## Sorting\n", - "\n", - "Python has a built-in function [`sorted`][sorted], which can sort anything that you can loop over (including the key-value pairs of a [dictionary](#scrollTo=Dictionaries)). It always returns a list with the result.\n", - "\n", - "By default, it will sort ascending, i.e., by increasing order of magnitude. Numbers are compared by value, strings are compared lexicographically (with all uppercase letters sorting before all lowercase letters), and lists are compared by the first item, with subsequent items being used as tie breakers if previous items compared equal.\n", - "\n", - "[sorted]: https://docs.python.org/3/library/functions.html#sorted\n", - "[sorting-howto]: https://docs.python.org/3/howto/sorting.html#sortinghowto" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "FIw_4XyNn9UK" - }, - "source": [ - "list_of_numbers = [5, 3, 4]\n", - "list_of_strings = ['Good', 'day', 'to', 'you']\n", - "list_of_lists = [\n", - " [6, 'zucchini'],\n", - " [5, 'eggs'],\n", - " [6, 'broccoli'],\n", - "]\n", - "\n", - "print(sorted(list_of_numbers))\n", - "print(sorted(list_of_strings))\n", - "print(sorted(list_of_lists))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "_uzxS1S1setr" - }, - "source": [ - "### Sorting in descending order\n", - "\n", - "If you want to sort descending instead, pass the named argument `reverse=True`." - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "e2RSQaXFszpT" - }, - "source": [ - "sorted(list_of_numbers, reverse=True)" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "YKx3ObxltgXz" - }, - "source": [ - "### Custom comparison\n", - "\n", - "If you want `sorted` to perform a different kind of comparison in order to decide on the order of the items, you can pass a function as the named `key` argument. This function should take one item as its parameter and return a new value that `sorted` will use for the comparison instead.\n", - "\n", - "Below, we use the function `str.lower` to do a case-insensitive sort:" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "5_w-T2ryuknR", - "outputId": "d9f68252-3e93-48c0-fdf9-f001a107fdf2" - }, - "source": [ - "sorted(list_of_strings, key=str.lower)" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/plain": [ - "['day', 'Good', 'to', 'you']" - ] - }, - "metadata": {}, - "execution_count": 5 - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "92yLh2OWvO-q" - }, - "source": [ - "The [`operator`][operator] standard module exports several useful functions that let you create instant simple functions for the purpose of sorting. Most importantly, [`itemgetter`][operator.itemgetter] lets you sort sequences by a different item than the first and [`attrgetter`][operator.attrgetter] lets you sort [objects](#scrollTo=Classes_and_objects) by a particular attribute. There is also [`methodcaller`][operator.methodcaller] which lets you sort by the result of a method call.\n", - "\n", - "Below, we use `itemgetter` to sort the key-value pairs of a [dictionary](#scrollTo=Dictionaries) by value instead of by key:\n", - "\n", - "[operator]: https://docs.python.org/3/library/operator.html#module-operator\n", - "[operator.itemgetter]: https://docs.python.org/3/library/operator.html#operator.itemgetter\n", - "[operator.attrgetter]: https://docs.python.org/3/library/operator.html#operator.attrgetter\n", - "[operator.methodcaller]: https://docs.python.org/3/library/operator.html#operator.methodcaller" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "HigJMisJydem" - }, - "source": [ - "from operator import itemgetter\n", - "\n", - "example_dict = {'banana': 'yellow', 'cherry': 'sweet', 'date': 'wrinkly'}\n", - "\n", - "sorted(example_dict.items(), key=itemgetter(1))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "P16V-uttzQXw" - }, - "source": [ - "And below, we use `attrgetter` to sort [dates](#scrollTo=Working_with_times_and_calendar_dates) by month:" - ] - }, - { - "cell_type": "code", - "metadata": { - "id": "jG1RMiBzzpky" - }, - "source": [ - "from operator import attrgetter\n", - "from datetime import date\n", - "\n", - "list_of_dates = [\n", - " date(year=2021, month=11, day=16),\n", - " date(year=2022, month=3, day=17),\n", - " date(year=2020, month=5, day=18),\n", - "]\n", - "\n", - "sorted(list_of_dates, key=attrgetter('month'))" - ], - "execution_count": null, - "outputs": [] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "7rsvpuMn1kSl" - }, - "source": [ - "## `pandas` dataframes and `read_csv`\n", - "\n", - "[pandas][pandas] is a package that provides general data structures and data analysis tools for Python. If you venture into statistics or datamining with Python, it is likely that you will sooner or later encounter [`pandas.DataFrame`][pandas.DataFrame] (which is a [class](#scrollTo=Classes_and_objects)). It holds tabular data in which each column might have a different type. Other packages often use this data structure, too.\n", - "\n", - "If you encounter `pandas` during the final course exercise, it is probably because you are using a function from a third-party package that expects you to pass in the data as a `DataFrame`. In this case, it is useful to know that `pandas` provides the [`read_csv`][pandas.read_csv] function. It accepts a file or file name as its first parameter and returns the contents of the CSV file as a `DataFrame`. You can then pass this object to the function that expects a `DataFrame`. The `read_csv` function also accepts a couple of optional parameters that let you specify details about the way the CSV file is formatted, its columns, etcetera.\n", - "\n", - "In the example code below, we illustrate how you can create a `DataFrame` using `read_csv`. Note that we define a [cross-platform path using `os.path`](#scrollTo=Cross_platform_file_paths). In the [next section](#scrollTo=Clustering_with_scikit_learn), we illustrate how the `data` object may be passed to a third-party analysis function.\n", - "\n", - "[pandas]: https://pandas.pydata.org/pandas-docs/stable/index.html\n", - "[pandas.DataFrame]: https://pandas.pydata.org/pandas-docs/stable/user_guide/dsintro.html#dataframe\n", - "[pandas.read_csv]: https://pandas.pydata.org/pandas-docs/stable/user_guide/io.html#io-read-csv-table" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/", - "height": 142 - }, - "id": "1m-b-UVLF_rM", - "outputId": "0b542154-2e25-4f71-c445-856836f0a749" - }, - "source": [ - "#requires pandas\n", - "\n", - "import os.path as op\n", - "import pandas\n", - "\n", - "file_path = op.join('sample_data', 'california_housing_test.csv')\n", - "\n", - "data = pandas.read_csv(file_path)\n", - "# `data` is an instance of pandas.DataFrame with several columns\n", - "# containing geographic center points of neighborhoods in\n", - "# California as well as demographics about the inhabitants and\n", - "# their houses.\n", - "\n", - "# You may sometimes want to pass only a subset of the dataset\n", - "# to a function. For this purpose, dataframes can be sliced in\n", - "# a way that is similar to lists. The following example will\n", - "# contain only the 'total_rooms' column:\n", - "data.loc[:, 'total_rooms']\n", - "\n", - "# The following example will include two columns, in a different\n", - "# order than they appeared in the CSV:\n", - "data.loc[:, ['households', 'population']]\n", - "# You can also use this notation if you want to use a subset of\n", - "# multiple columns.\n", - "\n", - "# For slicing rows by position, you use the `iloc` attribute\n", - "# instead of `loc`:\n", - "data.iloc[0:3]\n", - "\n", - "# Both ways of slicing can be combined:\n", - "data.loc[:, ['households', 'population']].iloc[0:3]" - ], - "execution_count": null, - "outputs": [ - { - "output_type": "execute_result", - "data": { - "text/html": [ - "
\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "
householdspopulation
0606.01537.0
1277.0809.0
2495.01484.0
\n", - "
" - ], - "text/plain": [ - " households population\n", - "0 606.0 1537.0\n", - "1 277.0 809.0\n", - "2 495.0 1484.0" - ] - }, - "metadata": {}, - "execution_count": 20 - } - ] - }, - { - "cell_type": "markdown", - "metadata": { - "id": "EYVhwfCP2oEK" - }, - "source": [ - "## Clustering with scikit-learn\n", - "\n", - "[scikit-learn][sklearn] is a package that provides many data mining and machine learning tools, including cluster analysis. You can find the documentation [here][sklearn.cluster]. We give a very minimal example of hierarchical clustering with Ward linkage below. You can find a more extensive example [here][sklearn-example]. Note that we are using the `data` object, which is a `pandas.DataFrame`, from the [previous section](#scrollTo=pandas_dataframes_and_read_csv).\n", - "\n", - "[sklearn]: https://scikit-learn.org/stable/index.html\n", - "[sklearn.cluster]: https://scikit-learn.org/stable/modules/clustering.html\n", - "[sklearn-example]: https://scikit-learn.org/stable/auto_examples/cluster/plot_digits_linkage.html#sphx-glr-auto-examples-cluster-plot-digits-linkage-py" - ] - }, - { - "cell_type": "code", - "metadata": { - "colab": { - "base_uri": "https://localhost:8080/" - }, - "id": "upo6gPd46sVt", - "outputId": "6938e3d2-8104-4f8c-fca6-f10b70d36dbb" - }, - "source": [ - "#requires sklearn\n", - "\n", - "from sklearn.cluster import AgglomerativeClustering\n", - "\n", - "# We start by creating the object that will *eventually* contain\n", - "# the clustering.\n", - "clustering = AgglomerativeClustering()\n", - "# Next, we feed in the data through the `fit` method. We will\n", - "# cluster the neighborhoods by geographical location.\n", - "clustering.fit(data.loc[:, ['latitude', 'longitude']])\n", - "# The clustering is now established. We illustrate below by\n", - "# printing the cluster assignment of the first 20 rows in the\n", - "# dataset.\n", - "print(clustering.labels_[:20])\n", - "# In a more serious application, we would probably inspect the\n", - "# cluster dendrogram or plot the data with a coloring to indicate\n", - "# the cluster assignment of each data point. The scikit-learn\n", - "# documentation explains how to do such things." - ], - "execution_count": null, - "outputs": [ - { - "output_type": "stream", - "name": "stdout", - "text": [ - "[1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 0 1 1 0 1]\n" - ] - } - ] - } - ] -} \ No newline at end of file