{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Introduction To Python" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python is a powerful, flexible programming language widely used for scientific computing, in web/Internet development, to write desktop graphical user interfaces (GUIs), create games, and much more. It became the *de facto* standard for machine learning, with a huge variety of specialized libraries such as:\n", "\n", "* `scikit-learn` , a toolbox with a multitude of ML algorithms already implemented.\n", "* `tensorflow` , an automatic differentiation library by Google for deep learning.\n", "* `pytorch` , another popular automatic differentiation library by Facebook.\n", "\n", "Python is an high-level, interpreted, object-oriented language written in C, which means it is compiled on-the-fly, at run-time execution. Its syntax is close to C, but without prototyping (whether a variable is an integer or a string will be automatically determined by the context). It can be executed either directly in an interpreter (à la Matlab), in a script or in a notebook (as here).\n", "\n", "The documentation on Python can be found at [http://docs.python.org](http://docs.python.org).\n", "\n", "Many resources to learn Python exist on the Web:\n", "\n", "- Free book [Dive into Python](http://www.diveintopython.net/).\n", "- [Learn Python](https://www.learnpython.org/).\n", "- [Learn Python the hard way](http://learnpythonthehardway.org).\n", "- Learn Python on [Code academy](http://www.codecademy.com/tracks/python).\n", "- Scipy lectures note [http://www.scipy-lectures.org](http://www.scipy-lectures.org/)\n", "- An Introduction to Interactive Programming in Python on [Coursera](https://www.coursera.org/course/interactivepython).\n", "\n", "This notebook only introduces you to the basics, so feel free to study additional resources if you want to master Python programming." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Working With Python\n", "\n", "There are basically three ways to program in Python: the interpreter for small commands, scripts for longer programs and notebooks (as here) for interactive programming.\n", "\n", "### Python Interpreter\n", "\n", "To start the Python interpreter, simply type its name in a terminal under Linux:\n", "\n", "```bash\n", "user@machine ~ $ python\n", "```\n", "\n", "```python\n", "Python 3.7.4 (default, Jul 16 2019, 07:12:58) \n", "[GCC 9.1.0] on linux\n", "Type \"help\", \"copyright\", \"credits\" or \"license\" for more information.\n", ">>> \n", "```\n", "\n", "You can then type anything at the prompt, for example a print statement:\n", "\n", "```python\n", ">>> print(\"Hello World!\")\n", "Hello World!\n", "```\n", "\n", "To exit Python call the `exit()` function (or `Ctrl+d`):\n", "\n", "```python\n", ">>> exit()\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Scripts\n", "\n", "Instead of using the interpreter, you can run scripts which can be executed sequentially. Simply edit a text file called `MyScript.py` containing for example:\n", "\n", "```python\n", "# MyScript.py\n", "# Implements the Hello World example.\n", "\n", "text = 'Hello World!' # define a string variable\n", "\n", "print(text)\n", "```\n", "\n", "The `#` character is used for comments. Execute this script by typing in a Terminal:\n", "\n", "```bash\n", "python MyScript.py\n", "```\n", "\n", "As it is a scripted language, each instruction in the script is executed from the beginning to the end, except for the declared functions or classes which can be used later." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Jupyter Notebooks\n", "\n", "A third recent (but very useful) option is to use Jupyter notebooks (formerly IPython notebooks). \n", "\n", "Jupyter notebooks allow you to edit Python code in your browser (but also Julia, R, Scala...) and run it locally. \n", "\n", "To launch a Jupyter notebook, type in a terminal:\n", "\n", "```bash\n", "jupyter notebook\n", "```\n", "\n", "and create a new notebook (Python 3)\n", "\n", "When a Jupyter notebook already exists (here `1-Python.ipynb`), you can also start it directly:\n", "\n", "```bash\n", "jupyter notebook 1-Python.ipynb\n", "```\n", "\n", "Alternatively, Jupyter lab has a more modern UI, but is still in beta.\n", "\n", "The main particularity of notebooks is that code is not executed sequentially from the beginning to the end, but only when a **cell** is explicitly run with **Ctrl + Enter** (the active cell stays the same) or **Shift + Enter** (the next cell becomes active).\n", "\n", "To edit a cell, select it and press **Enter** (or double-click).\n", "\n", "**Q:** In the next cell, run the Hello World! example:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello World!\n" ] } ], "source": [ "text = 'Hello World!'\n", "print(text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "There are three types of cells:\n", "\n", "* Python cells allow to execute Python code (the default)\n", "* Markdown cells which allow to document the code nicely (code, equations), like the current one.\n", "* Raw cell are passed to nbconvert directly, it allows you to generate html or pdf versions of your notebook (not used here).\n", "\n", "**Beware that the order of execution of the cells matters!**\n", "\n", "**Q:** In the next three cells, put the following commands:\n", "\n", "1. `text = \"Text A\"`\n", "2. `text = \"Text B\"`\n", "3. `print(text)`\n", "\n", "and run them in different orders (e.g. 1, 2, 3, 1, 3)" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [], "source": [ "text = \"Text A\"" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [], "source": [ "text = \"Text B\"" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Text A\n" ] } ], "source": [ "print(text)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Executing a cell can therefore influence cells before and after it. If you want to run the notebook sequentially, select **Kernel/Restart & Run all**.\n", "\n", "Take a moment to explore the options in the menu (Insert cells, Run cells, Download as Python, etc)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basics In Python\n", "\n", "### Print Statement\n", "\n", "In Python 3, the `print()` function is a regular function:\n", "\n", "```python\n", "print(value1, value2, ...)\n", "```\n", "\n", "You can give it as many arguments as you want (of whatever type), they will be printed one after another separated by spaces.\n", "\n", "**Q:** Try to print \"Hello World!\" using two different strings \"Hello\" and \"World!\":" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello World!\n" ] } ], "source": [ "text1 = 'Hello'\n", "text2 = \"World!\"\n", "\n", "print(text1, text2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Data Types\n", "\n", "As Python is an interpreted language, variables can be assigned without specifying their type: it will be inferred at execution time.\n", "\n", "The only thing that counts is how you initialize them and which operations you perform on them.\n", "\n", "```python\n", "a = 42 # Integer\n", "b = 3.14159 # Double precision float\n", "c = 'My string' # String\n", "d = False # Boolean\n", "e = a > b # Boolean\n", "```\n", "\n", "**Q:** Print these variables as well as their type:\n", "\n", "```python\n", "print(type(a))\n", "```" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Value of a is 42 , Type of a is: \n", "Value of b is 3.14159 , Type of b is: \n", "Value of c is My string , Type of c is: \n", "Value of d is False , Type of d is: \n", "Value of e is True , Type of e is: \n" ] } ], "source": [ "a = 42 # Integer\n", "b = 3.14159 # Double precision float\n", "c = 'My string' # String\n", "d = False # Boolean\n", "e = a > b # Boolean\n", "\n", "print('Value of a is', a,', Type of a is:', type(a))\n", "print('Value of b is', b,', Type of b is:', type(b))\n", "print('Value of c is', c,', Type of c is:', type(c))\n", "print('Value of d is', d,', Type of d is:', type(d))\n", "print('Value of e is', e,', Type of e is:', type(e))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Assignment Statement And Operators\n", "\n", "#### Assignment Statement\n", "\n", "The assignment can be done for a single variable, or for a tuple of variables separated by commas:\n", "\n", "\n", "```python\n", "m = 5 + 7\n", "\n", "x, y = 10, 20\n", "\n", "a, b, c, d = 5, 'Text', None, x==y\n", "```\n", "\n", "**Q:** Try these assignments and print the values of the variables." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "12 10 20 5 Text None False\n" ] } ], "source": [ "m = 5 + 7\n", "x, y = 10, 20\n", "a, b, c, d = 5, 'Text', None, x==y\n", "\n", "print(m, x, y, a, b, c, d,)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Operators\n", "\n", "Most usual operators are available:\n", "\n", "```python\n", "+ , - , * , ** , / , // , %\n", "== , != , <> , > , >= , < , <=\n", "and , or , not\n", "```\n", "\n", "**Q:** Try them and comment on their behaviour. Observe in particular what happens when you add an integer and a float." ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "8.0 \n" ] } ], "source": [ "x = 3 + 5.\n", "print(x, type(x))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q:** Notice how integer division is handled by python 3 by dividing an integer by either an integer or a float:" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2.5\n", "2.5\n" ] } ], "source": [ "print(5/2)\n", "print(5/2.)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Strings\n", "\n", "A string in Python can be surrounded by either single or double quotes (no difference as long as they match). Three double quotes allow to print new lines directly (equivalent of `\\n` in C).\n", "\n", "**Q:** Use the function `print()` to see the results of the following statements:\n", "\n", "```python\n", "a = 'abc'\n", "\n", "b = \"def\"\n", "\n", "c = \"\"\"aaa\n", "bbb\n", "ccc\"\"\"\n", "\n", "d = \"xxx'yyy\"\n", "\n", "e = 'mmm\"nnn'\n", "\n", "f = \"aaa\\nbbb\\nccc\"\n", "```" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "abc\n", "def\n", "aaa\n", "bbb\n", "ccc\n", "xxx'yyy\n", "mmm\"nnn\n", "aaa\n", "bbb\n", "ccc\n" ] } ], "source": [ "a = 'abc'\n", "b = \"def\"\n", "c = \"\"\"aaa\n", "bbb\n", "ccc\"\"\"\n", "d = \"xxx'yyy\"\n", "e = 'mmm\"nnn'\n", "f = \"aaa\\nbbb\\nccc\"\n", "\n", "print(a)\n", "print(b)\n", "print(c)\n", "print(d)\n", "print(e)\n", "print(f)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Lists\n", "\n", "Python knows a number of compound data types, used to group together other values. The most versatile is the list, which can be written as a list of comma-separated values (items) between square brackets `[]`. List items need not all to have the same type. \n", "\n", "```python\n", "a = ['spam', 'eggs', 100, 1234]\n", "```\n", "\n", "**Q:** Define a list of various variables and print it:" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['spam', 'eggs', 100, 1234]\n" ] } ], "source": [ "a = ['spam', 'eggs', 100, 1234]\n", "\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The number of items in a list is available through the `len()` function applied to the list:\n", "\n", "```python\n", "len(a)\n", "```\n", "\n", "**Q:** Apply `len()` on the list, as well as on a string:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Length of the list: 4\n", "Length of the word spam: 4\n" ] } ], "source": [ "print(\"Length of the list:\", len(a))\n", "print(\"Length of the word spam:\", len('spam'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To access the elements of the list, indexing and slicing can be used. \n", "\n", "* As in C, indices start at 0, so `a[0]` is the first element of the list, `a[3]` is its fourth element. \n", "\n", "* Negative indices start from the end of the list, so `a[-1]` is the last element, `a[-2]` the last but one, etc.\n", "\n", "* Slices return a list containing a subset of elements, with the form `a[start:stop]`, `stop` being excluded. `a[1:3]` returns the second and third elements. WHen omitted, `start` is 0 (`a[:2]` returns the two first elements) and `stop` is the length of the list (`a[1:]` has all elements of `a` except the first one). \n", "\n", "**Q:** Experiment with indexing and slicing on your list." ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['spam', 'eggs', 100, 1234]\n", "a[0] spam\n", "a[3] 1234\n", "a[-1] 1234\n", "a[1:3] ['eggs', 100]\n" ] } ], "source": [ "print(a)\n", "print(\"a[0]\", a[0])\n", "print(\"a[3]\", a[3])\n", "print(\"a[-1]\", a[-1])\n", "print(\"a[1:3]\", a[1:3])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Copying lists can cause some problems: \n", "\n", "```python\n", "a = [1,2,3] # Initial list\n", "\n", "b = a # \"Copy\" the list by reference \n", "\n", "a[0] = 9 # Change one item of the initial list\n", "```\n", "\n", "**Q:** Now print `a` and `b`. What happens?" ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "a : [9, 2, 3]\n", "b : [9, 2, 3]\n" ] } ], "source": [ "a = [1,2,3] # Initial list\n", "\n", "b = a # \"Copy\" the list by reference \n", "\n", "a[0] = 9 # Change one item of the initial list\n", "\n", "print('a :', a)\n", "print('b :', b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**A:** `B = A` does not make a copy of the **content** of `A`, but of its **reference** (pointer). So `a` and `b` both points at the same object." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The solution is to use the built-in `copy()` method of lists:\n", "\n", "```python\n", "b = a.copy()\n", "```\n", "\n", "**Q:** Try it and observe the difference." ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[9, 2, 3]\n", "[1, 2, 3]\n" ] } ], "source": [ "a = [1, 2, 3]\n", "b = a.copy()\n", "a[0] = 9\n", "\n", "print(a)\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Lists are objects, with a lot of different built-in methods (type `help(list)` in the interpreter or in a cell):\n", "\n", "- `a.append(x)`: Add an item to the end of the list.\n", "- `a.extend(L)`: Extend the list by appending all the items in the given list.\n", "- `a.insert(i, x)`: Insert an item at a given position.\n", "- `a.remove(x)`: Remove the first item from the list whose value is x.\n", "- `a.pop(i)`: Remove the item at the given position in the list, and return it.\n", "- `a.index(x)`: Return the index in the list of the first item whose value is x.\n", "- `a.count(x)`: Return the number of times x appears in the list.\n", "- `a.sort()`: Sort the items of the list, in place.\n", "- `a.reverse()`: Reverse the elements of the list, in place.\n", "\n", "**Q:** Try out quickly these methods, in particular `append()` which we will use quite often." ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 2, 3, 4]\n" ] } ], "source": [ "a = [1, 2, 3]\n", "\n", "a.append(4)\n", "\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Dictionaries\n", "\n", "Another useful data type built into Python is the dictionary. Unlike lists, which are indexed by a range of numbers from 0 to length -1, dictionaries are indexed by keys, which can be any *immutable* type; strings and numbers can always be keys.\n", "\n", "Dictionaries can be defined by curly braces `{}` instead of square brackets. The content is defined by `key:item` pairs, the item can be of any type:\n", "\n", "```python\n", "tel = {\n", " 'jack': 4098, \n", " 'sape': 4139\n", "}\n", "```\n", "\n", "To retrieve an item, simply use the key:\n", "\n", "```python\n", "tel_jack = tel['jack']\n", "```\n", "\n", "To add an entry to the dictionary, just use the key and assign a value to the item. It automatically extends the dictionary (warning, it can be dangerous!).\n", "\n", "```python\n", "tel['guido'] = 4127\n", "```\n", "\n", "**Q:** Create a dictionary and elements to it." ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'jack': 4098, 'sape': 4139, 'guido': 4127}\n", "4098\n" ] } ], "source": [ "tel = {'jack': 4098, 'sape': 4139}\n", "tel_jack = tel['jack']\n", "tel['guido'] = 4127\n", "\n", "print(tel)\n", "print(tel_jack)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `keys()` method of a dictionary object returns a **list** of all the keys used in the dictionary, in the order in which you added the keys (if you want it sorted, just apply the `sorted()` function on it). \n", "\n", "```python\n", "a = tel.keys()\n", "b = sorted(tel.keys())\n", "```\n", "\n", "`values()` does the same for the value of the items:\n", "\n", "```python\n", "c = tel.values()\n", "```\n", "\n", "**Q:** Do it on your dictionary." ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "dict_keys(['jack', 'sape', 'guido'])\n", "['guido', 'jack', 'sape']\n", "dict_values([4098, 4139, 4127])\n" ] } ], "source": [ "a = tel.keys()\n", "b = sorted(a)\n", "c = tel.values()\n", "\n", "print(a)\n", "print(b)\n", "print(c)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### If Statement \n", "\n", "Perhaps the most well-known conditional statement type is the `if` statement. For example:\n", "\n", "```python\n", "if x < 0:\n", " print('x =', x, 'is negative')\n", "elif x == 0:\n", " print('x =', x, 'is zero')\n", "else:\n", " print('x =', x, 'is positive')\n", "```\n", "\n", "**Q:** Give a value to the variable `x` and see what this statement does." ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x = 5 is positive\n" ] } ], "source": [ "x = 5\n", "\n", "if x < 0 :\n", " print('x =', x, 'is negative')\n", "elif x == 0:\n", " print('x =', x, 'is zero')\n", "else:\n", " print('x =', x, 'is positive')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Important!** The main particularity of the Python syntax is that the scope of the different structures (functions, for, if, while, etc...) is defined by the indentation, not by curly braces `{}`. As long as the code stays at the same level, it is in the same scope:\n", "\n", "```python\n", "if x < 0 :\n", " print('x =', x, 'is negative')\n", " x = -x\n", " print('x =', x, 'is now positive')\n", "elif x == 0:\n", " print('x =', x, 'is zero')\n", "else:\n", " print('x =', x, 'is positive')\n", "```\n", "\n", "A reasonable choice is to use four spaces for the indentation instead of tabs (configure your text editor if you are not using Jupyter).\n", "\n", "When the scope is terminated, you need to come back at **exactly** the same level of indentation. Try this misaligned structure and observe what happens:\n", "\n", "```python\n", "if x < 0 :\n", " print('x =', x, 'is negative')\n", " elif x == 0:\n", " print('x =', x, 'is zero')\n", " else:\n", " print('x =', x, 'is positive')\n", "```\n", "\n", "Jupyter is nice enough to highlight it for you, but not all text editors do that..." ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "ename": "IndentationError", "evalue": "unindent does not match any outer indentation level (, line 3)", "output_type": "error", "traceback": [ "\u001b[0;36m File \u001b[0;32m:3\u001b[0;36m\u001b[0m\n\u001b[0;31m elif x == 0:\u001b[0m\n\u001b[0m ^\u001b[0m\n\u001b[0;31mIndentationError\u001b[0m\u001b[0;31m:\u001b[0m unindent does not match any outer indentation level\n" ] } ], "source": [ "if x < 0 :\n", " print('x =', x, 'is negative')\n", " elif x == 0:\n", " print('x =', x, 'is zero')\n", " else:\n", " print('x =', x, 'is positive')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "In a if statement, there can be zero or more elif parts. What to do when the condition is true should be indented. The keyword `\"elif\"` is a shortened form of `\"else if\"`, and is useful to avoid excessive indentation. An `if ... elif ... elif ...` sequence is a substitute for the switch or case statements found in other languages.\n", "\n", "The `elif` and `else` statements are optional. You can also only use the if statement alone:\n", "\n", "```python\n", "a = [1, 2, 0]\n", "has_zero = False\n", "if 0 in a:\n", " has_zero = True\n", "```\n", "\n", "Note the use of the `in` keyword to know if an element exists in a list." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### For loops\n", "\n", "The for statement in Python differs a bit from what you may be used to in C, Java or Pascal.\n", "\n", "Rather than always iterating over an arithmetic progression of numbers (like in Pascal), or giving the user the ability to define both the iteration step and halting condition (as C), Python's for statement iterates over the items of any sequence (a list or a string), in the order they appear in the sequence.\n", "\n", "```python\n", "list_words = ['cat', 'window', 'defenestrate']\n", "\n", "for word in list_words:\n", " print(word, len(word))\n", "```\n", "\n", "**Q:** Iterate over the list you created previously and print each element.\n" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "spam\n", "eggs\n", "100\n", "1234\n" ] } ], "source": [ "a = ['spam', 'eggs', 100, 1234]\n", "\n", "for el in a:\n", " print(el)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If you do need to iterate over a sequence of numbers, the built-in function `range()` comes in handy. It generates lists containing arithmetic progressions:\n", "\n", "```python\n", "for i in range(5):\n", " print(i)\n", "```\n", "\n", "**Q:** Try it." ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0\n", "1\n", "2\n", "3\n", "4\n" ] } ], "source": [ "for i in range(5):\n", " print(i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`range(N)` generates a list of N number starting from 0 until N-1.\n", "\n", "It is possible to specify a start value (0 by default), an end value (excluded) and even a step:\n", "\n", "```python\n", "range(5, 10)\n", "range(5, 10, 2)\n", "```\n", "\n", "**Q:** Print the second and fourth elements of your list (`['spam', 'eggs', 100, 1234]`) using `range()`." ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "eggs\n", "1234\n" ] } ], "source": [ "for i in range(1, 4, 2):\n", " print(a[i])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To iterate over all the indices of a list (0, 1, 2, etc), you can combine range() and len() as follows:\n", "\n", "```python\n", "for idx in range(len(a)):\n", "```\n", "\n", "The `enumerate()` function allows to get at the same time the index and the content:\n", "\n", "```python\n", "for i, val in enumerate(a):\n", " print(i, val)\n", "```" ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 spam\n", "1 eggs\n", "2 100\n", "3 1234\n" ] } ], "source": [ "for i, val in enumerate(a):\n", " print(i, val)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "To get iteratively the keys and items of a dictionary, use the `items()` method of dictionary:\n", "\n", "```python\n", "for key, val in tel.items():\n", "```\n", "\n", "**Q:** Print one by one all keys and values of your dictionary." ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "jack 4098\n", "sape 4139\n", "guido 4127\n" ] } ], "source": [ "tel = {'jack': 4098, 'sape': 4139, 'guido': 4127}\n", "\n", "for name, number in tel.items():\n", " print(name, number)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Functions\n", "\n", "As in most procedural languages, you can define functions. Functions are defined by the keyword `def`. Only the parameters of the function are specified (without type), not the return values.\n", "\n", "The content of the function has to be incremented as with for loops.\n", "\n", "Return values can be specified with the `return` keywork. It is possible to return several values at the same time, separated by commas.\n", "\n", "```python\n", "def say_hello_to(first, second):\n", " question = 'Hello, I am '+ first + '!'\n", " answer = 'Hello '+ first + '! I am ' + second + '!'\n", " return question, answer\n", "```\n", "\n", "To call that function, pass the arguments that you need and retrieve the retruned values separated by commas.\n", "\n", "```python\n", "question, answer = say_hello_to('Jack', 'Gill')\n", "```\n", "\n", "**Q:** Test it with different names as arguments." ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, I am Jack!\n", "Hello Jack! I am Gill!\n" ] } ], "source": [ "def say_hello_to(first, second):\n", " question = 'Hello, I am '+ first + '!'\n", " answer = 'Hello '+ first + '! I am ' + second + '!'\n", " return question, answer\n", "\n", "question, answer = say_hello_to('Jack', 'Gill')\n", "\n", "print(question)\n", "print(answer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q:** Redefine the `tel` dictionary `{'jack': 4098, 'sape': 4139, 'guido': 4127}` if needed, and create a function that returns a list of names whose number is higher than 4100." ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['sape', 'guido']\n" ] } ], "source": [ "def filter_dict(tel):\n", " answer = []\n", " for name, number in tel.items():\n", " if number >= 4100:\n", " answer.append(name)\n", " return answer\n", "\n", "tel = {'jack': 4098, 'sape': 4139, 'guido': 4127}\n", "names = filter_dict(tel)\n", "print(names)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Functions can take several arguments (with default values or not). The name of the argument can be specified during the call, so their order won't matter.\n", "\n", "**Q:** Try these different calls to the `say_hello_to()` function:\n", "\n", "```python\n", "question, answer = say_hello_to('Jack', 'Gill')\n", "question, answer = say_hello_to(first='Jack', second='Gill')\n", "question, answer = say_hello_to(second='Jack', first='Gill')\n", "```" ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, I am Jack!\n", "Hello Jack! I am Gill!\n", "Hello, I am Jack!\n", "Hello Jack! I am Gill!\n", "Hello, I am Gill!\n", "Hello Gill! I am Jack!\n" ] } ], "source": [ "question, answer = say_hello_to('Jack', 'Gill')\n", "print(question)\n", "print(answer)\n", "question, answer = say_hello_to(first='Jack', second='Gill')\n", "print(question)\n", "print(answer)\n", "question, answer = say_hello_to(second='Jack', first='Gill')\n", "print(question)\n", "print(answer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Default values can be specified for the last arguments, for example:\n", "\n", "```python\n", "def add (a, b=1):\n", " return a + b\n", "\n", "x = add(2, 3) # returns 5\n", "y = add(2) # returns 3\n", "z = add(a=4) # returns 5\n", "```\n", "\n", "**Q:** Modify `say_hello_to()` so that the second argument is your own name by default." ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Hello, I am Jack!\n", "Hello Jack! I am Gill!\n", "Hello, I am Jack!\n", "Hello Jack! I am Julien!\n" ] } ], "source": [ "def say_hello_to(first, second=\"Julien\"):\n", " question = 'Hello, I am '+ first + '!'\n", " answer = 'Hello '+ first + '! I am ' + second + '!'\n", " return question, answer\n", "\n", "question, answer = say_hello_to('Jack', 'Gill')\n", "print(question)\n", "print(answer)\n", "\n", "question, answer = say_hello_to('Jack')\n", "print(question)\n", "print(answer)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Classes\n", "\n", "Classes are structures allowing to:\n", "\n", "1. Store information in an object.\n", "2. Apply functions on this information.\n", "\n", "In a nutshell:\n", "\n", "```python\n", "class Foo:\n", " \n", " def __init__(self, val):\n", " self.val = val\n", " \n", " def print(self):\n", " print(self.val)\n", " \n", " def set_val(self, val):\n", " self.val = val\n", " self.print()\n", " \n", "a = Foo(42)\n", "a.print()\n", "```\n", "\n", "This defines the **class** `Foo`. The first (obligatory) method of the class is the **constructor** `__init__`. This determines how the **instance** `a` will be instantiated after the call to `a = Foo(42)`. The first argument is `self`, which represents the current instance of the class. We can specify other arguments to the constructor (here `val`), which can be processed or stored.\n", "\n", "Here we store `val` as an **attribute** of the class `Foo` with `self.val`. It is data that will be specific to each created object: if you create `b = Foo(\"reinforcement_learning\")`, the attribute `self.val` will have different values between the two instances. As always in Python, the type does not matter, it can be a float, a string, a numpy array, another object...\n", "\n", "Attributes are accessible from each object as:\n", "\n", "```python\n", "x = a.val\n", "```\n", "\n", "You can set its value by:\n", "\n", "```python\n", "a.val = 12\n", "```\n", "\n", "Classes can define **methods** that can manipulate class attributes as any regular method. The first argument **must** always be `self`. With the `self` object, you can access all attributes (or other methods) of the instance.\n", "\n", "With our toy class, `a.set_val(34)` does exactly the same as `a.val = 34`, or `a.print()` is the same as `print(a.val)`.\n", "\n", "*For C++/Java experts:* attributes and methods are always public in Python. If you want to make an attribute private, preprend its name with an underscore, e.g. `self._val`. It will then not be part of the API of the class (but can be read or written publicly anyway...).\n", "\n", "**Q:** Play around with this basic class, create different objects with different attributes, print them, change them, etc." ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "42\n", "42\n", "32\n", "32\n" ] } ], "source": [ "class Foo:\n", " \n", " def __init__(self, val):\n", " self.val = val\n", " \n", " def print(self):\n", " print(self.val)\n", " \n", " def set_val(self, val):\n", " self.val = val\n", " self.print()\n", "\n", "a = Foo(42)\n", "a.print()\n", "print(a.val)\n", "a.set_val(32)\n", "a.print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A major concept in **object-oriented programming** (OOP) is **class inheritance**. We will not use it much in these exercises, but let's talk shortly about it.\n", "\n", "Inheriting a class is creating a new class that inherits from the attributes and methods of another class (a kind of \"copy\" of the definition of the class). You can then add new attributes or methods, or overload existing ones.\n", "\n", "Example:\n", "\n", "```python\n", "class Bar(Foo):\n", " def add(self, val):\n", " self.val += val\n", " def print(self):\n", " print(\"val =\", self.val)\n", "```\n", "\n", "`Bar` is a child class of `Foo`. It inherits all attributes and methods, including `__init__`, `print` and `set_val`. It creates a new method `add` and **overloads** `print`: the old definition of `print` in `Foo` does not exist anymore for instances of the `Bar` class (but does for instances of the `Foo` class). The constructor can also be overloaded, for example to add new arguments:\n", "\n", "```python\n", "class Bar(Foo):\n", " def __init__(self, val, val2):\n", " self.val2 = val2\n", " super().__init__(val)\n", " def add(self, val):\n", " self.val += val\n", " def print(self):\n", " print(\"val =\", self.val)\n", "```\n", "\n", "`super().__init__(val)` calls the constructor of the `Foo` class (the \"super\" class of `bar`), so it sets the value of `self.val`.\n", "\n", "**Q:** Play around with inheritance to understand the concept." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "val = 42\n" ] } ], "source": [ "class Bar(Foo):\n", " def __init__(self, val, val2):\n", " self.val2 = val2\n", " super().__init__(val)\n", " def add(self, val):\n", " self.val += val\n", " def print(self):\n", " print(\"val =\", self.val)\n", " \n", "b = Bar(12, 23)\n", "b.add(30)\n", "b.print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Exercise\n", "\n", "In cryptography, a Caesar cipher is a very simple encryption technique in which each letter in the plain text is replaced by a letter some fixed number of positions down the alphabet. For example, with a shift of 3, A would be replaced by D, B would become E, and so on. The method is named after Julius Caesar, who used it to communicate with his generals. ROT-13 (\"rotate by 13 places\") is a widely used example of a Caesar cipher where the shift is 13. In Python, the key for ROT-13 may be represented by means of the following dictionary:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [], "source": [ "code = {'a':'n', 'b':'o', 'c':'p', 'd':'q', 'e':'r', 'f':'s',\n", " 'g':'t', 'h':'u', 'i':'v', 'j':'w', 'k':'x', 'l':'y',\n", " 'm':'z', 'n':'a', 'o':'b', 'p':'c', 'q':'d', 'r':'e',\n", " 's':'f', 't':'g', 'u':'h', 'v':'i', 'w':'j', 'x':'k',\n", " 'y':'l', 'z':'m', 'A':'N', 'B':'O', 'C':'P', 'D':'Q',\n", " 'E':'R', 'F':'S', 'G':'T', 'H':'U', 'I':'V', 'J':'W',\n", " 'K':'X', 'L':'Y', 'M':'Z', 'N':'A', 'O':'B', 'P':'C',\n", " 'Q':'D', 'R':'E', 'S':'F', 'T':'G', 'U':'H', 'V':'I', \n", " 'W':'J', 'X':'K', 'Y':'L', 'Z':'M'}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Q:** Your task in this final exercise is to implement an encoder/decoder of ROT-13. Once you're done, you will be able to read the following secret message:\n", "\n", "```\n", "Jnvg, jung qbrf vg unir gb qb jvgu qrrc yrneavat??\n", "```\n", "\n", "The idea is to write a `decode()` function taking the message and the code dictionary as inputs, and returning the decoded message. It should iterate over all letters of the message and replace them with the decoded letter. If the letter is not in the dictionary (e.g. punctuation), keep it as it is. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Method to decode a message\n", "def decode(msg, code):\n", " result = \"\"\n", " for letter in msg:\n", " if letter in code.keys():\n", " result += code[letter]\n", " else:\n", " result += letter\n", " return result\n", "\n", "# Message to decode\n", "msg = \"Jnvg, jung qbrf vg unir gb qb jvgu qrrc yrneavat??\"\n", "\n", "# Decode the message\n", "decoded = decode(msg, code)\n", "print(decoded)" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3.9.12 ('base')", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.12" }, "vscode": { "interpreter": { "hash": "3d24234067c217f49dc985cbc60012ce72928059d528f330ba9cb23ce737906d" } } }, "nbformat": 4, "nbformat_minor": 4 }