{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Image processing I - Programming I\n", "\n", "In this lecture, we will learn the fundamentals of Python and start to look into writing our own functions.\n", "\n", "Much of the material is inspired by [J. VanderPlas: Whirlwind Tour of Python](https://github.com/jakevdp/WhirlwindTourOfPython)\n", "\n", "\n", "## Outline\n", "\n", "* Recap of what we learned about Python so far (basic data types and operations)\n", "* More on lists and other compound types, indexing and slicing\n", "* User-defined functions\n", "* Loops and control structures" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Built-in data types\n", "\n", "Python is a dynamic language and therefore doesn't require variable declarations specifying a variable's type (as, e.g., in C/C++). Simple scalar data types in Python are:\n", "\n", "### Scalar data types\n", "\n", "| Type | Example | Description |\n", "|-------------|----------------|--------------------------------------------------------------|\n", "| ``int`` | ``x = 1`` | integers (i.e., whole numbers) |\n", "| ``float`` | ``x = 1.0`` | floating-point numbers (i.e., real numbers) |\n", "| ``complex`` | ``x = 1 + 2j`` | Complex numbers (i.e., numbers with real and imaginary part) |\n", "| ``bool`` | ``x = True`` | Boolean: True/False values |\n", "| ``str`` | ``x = 'abc'`` | String: characters or text |\n", "| ``NoneType``| ``x = None`` | Special object indicating nulls |\n", "\n", "### Compound data types\n", "\n", "Python also has several built-in compound types that act as containers for other types. These compound types are:\n", "\n", "| Type Name | Example |Description |\n", "|-----------|---------------------------|---------------------------------------|\n", "| ``list`` | ``[1, 2, 3]`` | Ordered collection |\n", "| ``tuple`` | ``(1, 2, 3)`` | Immutable ordered collection |\n", "| ``dict`` | ``{'a':1, 'b':2, 'c':3}`` | Unordered (key,value) mapping |\n", "| ``set`` | ``{1, 2, 3}`` | Unordered collection of unique values |\n", "\n", "The following code produces examples for some of the built-in types provided by Python. Because Python is interpreted you can define these variables right on the spot: " ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "value of variable \"a\": 1\n", "value of variable \"b\": 0.123456789\n", "value of variable \"c\": True\n", "value of variable \"d\": abcdefg\n", "value of variable \"e\": [0, 'a', False, 0, 1.1]\n", "value of variable \"f\": (0, 'a', False, 0, 1.1)\n", "value of variable \"g\": {0, 1.1, 'a'}\n", "value of variable \"h\": {None: [2, 3], (1, 2): 'xyz', 'image': 'processing'}\n", "value of variable \"i\": None\n" ] } ], "source": [ "a = 1\n", "b = 0.123456789\n", "c = True\n", "d = 'abcdefg'\n", "e = [0, 'a', False, 0, 1.1]\n", "f = (0, 'a', False, 0, 1.1)\n", "g = set([0, 'a', False, 0, 1.1])\n", "h = {None: [2,3], (1,2): 'xyz', 'image': 'processing'}\n", "i = None\n", "\n", "print('value of variable \"a\":', a)\n", "print('value of variable \"b\":', b)\n", "print('value of variable \"c\":', c)\n", "print('value of variable \"d\":', d)\n", "print('value of variable \"e\":', e)\n", "print('value of variable \"f\":', f)\n", "print('value of variable \"g\":', g)\n", "print('value of variable \"h\":', h)\n", "print('value of variable \"i\":', i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "What is the `type` of each of these variables? Let's use Python to find out:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "type of variable \"a\": 1\n", "type of variable \"b\": 0.123456789\n", "type of variable \"c\": True\n", "type of variable \"d\": abcdefg\n", "type of variable \"e\": [0, 'a', False, 0, 1.1]\n", "type of variable \"f\": (0, 'a', False, 0, 1.1)\n", "type of variable \"g\": {0, 1.1, 'a'}\n", "type of variable \"h\": {None: [2, 3], (1, 2): 'xyz', 'image': 'processing'}\n", "type of variable \"i\": None\n" ] } ], "source": [ "print('type of variable \"a\":', type(a), a)\n", "print('type of variable \"b\":', type(b), b)\n", "print('type of variable \"c\":', type(c), c)\n", "print('type of variable \"d\":', type(d), d)\n", "print('type of variable \"e\":', type(e), e)\n", "print('type of variable \"f\":', type(f), f)\n", "print('type of variable \"g\":', type(g), g)\n", "print('type of variable \"h\":', type(h), h)\n", "print('type of variable \"i\":', type(i), i)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python integers don't overflow" ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1606938044258990275541962092341162602522202993782792835301376\n" ] } ], "source": [ "a = 2**200\n", "\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Floats are *double precision* floating point numbers. So they have a finite range:" ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0.0\n", "largest float: 1.7976931348623157e+308\n", "smallest float: 2.2250738585072014e-308\n", "overflow: inf\n", "underflow: 2.2250738585072014e-308 5e-324 0.0\n" ] } ], "source": [ "# floats\n", "\n", "import sys\n", "\n", "inf = float('inf')\n", "print(1/inf)\n", "floatmax = sys.float_info.max\n", "floatmin = sys.float_info.min\n", "print('largest float:', floatmax)\n", "print('smallest float:', floatmin)\n", "print('overflow:', floatmax * (1 + 2**(-52)))\n", "# apparently, underflow occurs at numbers that are even smaller\n", "# than floatmin\n", "print('underflow:', 2**-1022, 2**-1074, 2**-1075)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Useful Built-In Functions\n", "\n", "| Type Name | Example |Description |\n", "|-----------|---------------------------|---------------------------------------|\n", "| ``print`` | ``print('Hello, world!')``| Write to standard output |\n", "| ``type`` | ``type(1)`` | Returns the type of an object |\n", "| ``len`` | ``len('abc')`` | Size of object |\n", "| ``dir`` | ``dir(math)`` | Content of module or object |\n", "| ``str`` | ``str(10)`` | Convert object to string |\n", "| ``int`` | ``int('123')`` | Convert string to integer |\n", "| ``range`` | ``range(1, 12)`` | Creates a list |" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'acos', 'acosh', 'asin', 'asinh', 'atan', 'atan2', 'atanh', 'ceil', 'copysign', 'cos', 'cosh', 'degrees', 'e', 'erf', 'erfc', 'exp', 'expm1', 'fabs', 'factorial', 'floor', 'fmod', 'frexp', 'fsum', 'gamma', 'gcd', 'hypot', 'inf', 'isclose', 'isfinite', 'isinf', 'isnan', 'ldexp', 'lgamma', 'log', 'log10', 'log1p', 'log2', 'modf', 'nan', 'pi', 'pow', 'radians', 'remainder', 'sin', 'sinh', 'sqrt', 'tan', 'tanh', 'tau', 'trunc']\n", "3.141592653589793\n", "\n" ] } ], "source": [ "# example code illustrating some built-in functions\n", "import math\n", "print(dir(math))\n", "print(math.pi)\n", "x = int('123')\n", "print(type(x))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Basic operations\n", "\n", "### Arithmetic operations\n", "\n", "Python implements seven basic binary arithmetic operators, two of which can double as unary operators. They are summarized in the following table:\n", "\n", "| Operator | Name | Description |\n", "|--------------|----------------|--------------------------------------------------------|\n", "| ``a + b`` | Addition | Sum of ``a`` and ``b`` |\n", "| ``a - b`` | Subtraction | Difference of ``a`` and ``b`` |\n", "| ``a * b`` | Multiplication | Product of ``a`` and ``b`` |\n", "| ``a / b`` | True division | Quotient of ``a`` and ``b`` |\n", "| ``a // b`` | Floor division | Quotient of ``a`` and ``b``, removing fractional parts |\n", "| ``a % b`` | Modulus | Integer remainder after division of ``a`` by ``b`` |\n", "| ``a ** b`` | Exponentiation | ``a`` raised to the power of ``b`` |\n", "| ``-a`` | Negation | The negative of ``a`` |\n", "| ``+a`` | Unary plus | ``a`` unchanged (rarely used) |\n", "\n", "These operators can be used and combined in intuitive ways, using standard parentheses to group operations. Numbers behave in the expected fashion under addition ``+``, subtraction ``-``, multiplication ``*`` and division:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "45801.0\n", "(45669-1.234j)\n", "(1107+151.782j)\n", "0.0026927623801392356\n" ] } ], "source": [ "# adding, subtracting, multiplying, dividing ints, floats and complex numbers\n", "\n", "a, b, c = 123, 45678., 9+1.234j\n", "\n", "print(a + b)\n", "print(b - c)\n", "print(a * c)\n", "print(a / b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The operator `//` is the floor division:" ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1.4285714285714286\n", "1\n", "3\n", "3\n", "1000\n", "1.4285714285714286\n", "1.0\n" ] } ], "source": [ "# division of two ints can yield a float\n", "# floor division of two ints yields an int\n", "print(10 / 7)\n", "print(10 // 7)\n", "print(10 % 7)\n", "print(10 - 7 * (10//7))\n", "print(10**3)\n", "\n", "# floor division of two floats yields a float\n", "print(10 / 7.)\n", "print(10 // 7.) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Comparison Operations\n", "\n", "Another type of operation which can be very useful is comparison of different values. For this, Python implements standard comparison operators, which return Boolean values ``True`` and ``False``. The comparison operations are listed in the following table:\n", "\n", "| Operation | Description |\n", "|---------------|-----------------------------------|\n", "| ``a == b`` | ``a`` equal to ``b`` |\n", "| ``a != b`` | ``a`` not equal to ``b`` |\n", "| ``a < b`` | ``a`` less than ``b`` |\n", "| ``a > b`` | ``a`` greater than ``b`` |\n", "| ``a <= b`` | ``a`` less than or equal to ``b`` |\n", "| ``a >= b`` | ``a`` greater than or equal to ``b`` |" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "False\n", "False\n", "True\n", "True\n", "False\n" ] } ], "source": [ "print('ab' == 'ab')\n", "print(1 == 1+1)\n", "print(2 != 1+1)\n", "print(6-1 <= 5)\n", "print('a' < 'b')\n", "print('a' > 'b')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Logical operations\n", "\n", "Python provides operators to combine Boolean values using the keywords `and`, `or`, and `not`:\n", "\n", "| Operation | Name | Example |\n", "|---------------|--------|-----------------------------------------------|\n", "|``a and b`` | AND | ``(x < 6) and (x > 2)`` is true for ``x = 4`` |\n", "|``a or b`` | OR | ``(x > 10) or (x % 2 == 0)`` is also true |\n", "|``not a`` | NOT | ``not (x < 6)`` is false |\n", "\n", "There is no special XOR operator, but a simple version of XOR is to use the operator ``=!`` as in\n", "~~~ python\n", "(x > 1) != (x < 10)\n", "~~~" ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "False\n", "True\n", "True\n" ] } ], "source": [ "A = True\n", "B = 10 < 7\n", "print(A and B)\n", "print(A or B)\n", "print(not B)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Identity and Membership Operators\n", "\n", "Like ``and``, ``or``, and ``not``, Python also contains prose-like operators to check for identity and membership.\n", "They are the following:\n", "\n", "| Operator | Description |\n", "|---------------|---------------------------------------------------|\n", "| ``a is b`` | True if ``a`` and ``b`` are identical objects |\n", "| ``a is not b``| True if ``a`` and ``b`` are not identical objects |\n", "| ``a in b`` | True if ``a`` is a member of ``b`` |\n", "| ``a not in b``| True if ``a`` is not a member of ``b`` |" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "True\n", "True\n", "False\n" ] } ], "source": [ "a = 10\n", "b = a\n", "print(a is b)\n", "b = 10\n", "print(a is b)\n", "a = [1, 2]\n", "print(0 in a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Bitwise operations\n", "\n", "In addition to the standard numerical operations, Python includes operators to perform bitwise logical operations on integers. These are much less commonly used than the standard arithmetic operations, but it's useful to know that they exist. The six bitwise operators are summarized in the following table:\n", "\n", "| Operator | Name | Description |\n", "|--------------|-----------------|---------------------------------------------|\n", "| ``a & b`` | Bitwise AND | Bits defined in both ``a`` and ``b`` |\n", "| a | b| Bitwise OR | Bits defined in ``a`` or ``b`` or both |\n", "| ``a ^ b`` | Bitwise XOR | Bits defined in ``a`` or ``b`` but not both |\n", "| ``a << b`` | Bit shift left | Shift bits of ``a`` left by ``b`` units |\n", "| ``a >> b`` | Bit shift right | Shift bits of ``a`` right by ``b`` units |\n", "| ``~a`` | Bitwise NOT | Bitwise negation of ``a`` |" ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "AND: 6\n", " OR: 30\n", "XOR: 24\n", "\n", "Left/right shift\n", "10\n", "1\n", "\n", "Bitwise NOT\n", "-6\n", "5\n", "5\n", "-8\n", "7\n" ] } ], "source": [ "# (14)_10 : 01110\n", "# (22)_10 : 10110\n", "# ===============\n", "# AND : 00110 -> (6)_10\n", "# OR : 11110 -> (30)_10\n", "# XOR : 11000 -> (24)_10\n", "print('AND:', 14 & 22) \n", "print(' OR:', 14 | 22)\n", "print('XOR:', 14 ^ 22)\n", "\n", "print('\\nLeft/right shift')\n", "print(5<<1) # (5)_10 -> (10)_10 since 101 -> 1010\n", "print(5>>2) # (5)_10 -> (2)_10 since 101 -> 10\n", "\n", "print('\\nBitwise NOT')\n", "print(~5) # (5)_10 = 0101 -> 1010 (6)_10\n", "print(~-6) # inversion\n", "print(~~5)\n", "print(~7) # (7)_10 = 0111 -> 1000 (8)_10\n", "print(~-8) # inversion" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Lists, tuples, sets" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[1, 3, 'a', 'bc']\n", "[3]\n", "['a', 'b', 'c', 'd', 'e', 'f']\n", "[0, 1, 4, 9, 16]\n" ] } ], "source": [ "# various ways of creating lists\n", "\n", "a = [1, 3, 'a', 'bc']\n", "b = list(range(3, 5, 2))\n", "c = list('abcdef')\n", "d = [x**2 for x in range(5)]\n", "\n", "print(a)\n", "print(b)\n", "print(c)\n", "print(d)" ] }, { "cell_type": "code", "execution_count": 13, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[[1, 2, 3], [4, 5, 6], [7, 8, 9], 'A']\n", "[4, 5, 6]\n" ] } ], "source": [ "# a list of lists\n", "x = [[1,2,3],[4,5,6],[7,8,9], 'A']\n", "print(x)\n", "print(x[1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Indexing and slicing\n", "\n", "Python provides access to elements in compound types through __indexing__ for single elements, and __slicing__ for multiple elements. Python uses zero-based indexing, so we can access the first and second element in a list `l` using the following syntax `l[0]` and `l[1]`. Elements at the end of the list can be accessed with negative\n", "numbers starting from -1: `l[-1]` and `l[-2]` return the last and the second last element of `l`:" ] }, { "cell_type": "code", "execution_count": 14, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "list: [2, 3, 5, 7, 11]\n", "1st element: 2\n", "2nd element: 3\n", "last element: 11 11\n", "2nd last element: 7\n" ] } ], "source": [ "l = [2, 3, 5, 7, 11]\n", "print('list: ', l)\n", "print('1st element:', l[0])\n", "print('2nd element:', l[1])\n", "print('last element:', l[-1], l[len(l)-1]) # see MATLAB a(end)\n", "print('2nd last element:', l[-2]) " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This figure illustrates indexing for this particular example (source: [J. VanderPlas: Whirlwind Tour of Python](https://github.com/jakevdp/WhirlwindTourOfPython))\n", "\n", "" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "__Slicing__ can be used to access sublists. Slices have the following structure `l[start:stop:step]` where `start`, `stop`, and `step` can be integers or `None`. `start` specifies where the slice starts, `stop` where it ends; `step` is an increment that allows us to skip elements in the slice. " ] }, { "cell_type": "code", "execution_count": 15, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[2, 3, 5, 7, 11]\n", "[2, 5]\n", "[3, 7]\n", "[11, 7, 5, 3, 2]\n" ] } ], "source": [ "# accessing sublists in l\n", "print(l)\n", "\n", "# every second element in list 'l' start with the first one\n", "print(l[:-1:2]) \n", "\n", "# every second element in list 'l' start with the 2nd one\n", "print(l[1::2]) \n", "\n", "# reversed list\n", "print(l[::-1])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Mutable versus immutable containers\n", "\n", "Lists are mutable, i.e. their content can be changed: " ] }, { "cell_type": "code", "execution_count": 16, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "before\n", "[1, 3, 'a', 'b']\n", "[0, 1, 2, 3, 4]\n", "['a', 'b', 'c', 'd', 'e', 'f']\n", "[0, 1, 4, 9, 16]\n", "\n", "after\n", "[10, 3, 'a', 'b']\n", "[0, 1, 2, 3, 4, 10]\n", "['a', 'b', 'c', 'd', 'e', 'f', 0, 1, 4, 9, 16]\n" ] } ], "source": [ "a = [1, 3, 'a', 'b']\n", "b = list(range(5))\n", "c = list('abcdef')\n", "d = [x**2 for x in range(5)]\n", "\n", "print('before')\n", "print(a)\n", "print(b)\n", "print(c)\n", "print(d)\n", "\n", "a[0] = 10\n", "b.append(10)\n", "c.extend(d)\n", "#c = c + d\n", "\n", "print('\\nafter')\n", "print(a)\n", "print(b)\n", "print(c)" ] }, { "cell_type": "code", "execution_count": 17, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['__add__', '__class__', '__contains__', '__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__', '__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__', '__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend', 'index', 'insert', 'pop', 'remove', 'reverse', 'sort']\n", "[0, 1, 23452435, 2, 3, 4, 10]\n" ] } ], "source": [ "# list methods\n", "print(dir(a))\n", "\n", "b.insert(2, 23452435)\n", "print(b)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Tuples are immutable, meaning their content cannot be changed:" ] }, { "cell_type": "code", "execution_count": 18, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(1, 2, 3) \n", "(1, 2, 3) \n", "('a', 'b', 'c') \n", "(1, 2, 3, 1, 2, 3, 'a', 'b', 'c')\n" ] } ], "source": [ "# tuples\n", "\n", "a = (1, 2, 3)\n", "b = 1, 2, 3\n", "c = tuple('abc')\n", "\n", "print(a, type(a))\n", "print(b, type(b))\n", "print(c, type(c))\n", "\n", "print(a + b + c)" ] }, { "cell_type": "code", "execution_count": 19, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "'tuple' object does not support item assignment", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\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[0ma\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m2\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[0;32m----> 2\u001b[0;31m \u001b[0ma\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0;36m0\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;34m'a'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", "\u001b[0;31mTypeError\u001b[0m: 'tuple' object does not support item assignment" ] } ], "source": [ "a = (1, 2, 3)\n", "a[0] = 'a'" ] }, { "cell_type": "code", "execution_count": 20, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "['a', 2, 3]\n" ] } ], "source": [ "a = list(a)\n", "a[0] = 'a'\n", "print(a)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## User-defined functions\n", "\n", "Functions allow you to package reusable pieces of code and use the functionality over and over again without reproducing the code. This helps us to develop compact, bug-free and reusable code. The Python keyword ``def`` marks the definition of a function. This keyword is followed by the function name and input variables that are listed inside round brackets (this list can also be empty); a colon marks the end of the function header:\n", "```python\n", "def function_name(variables1, variable2, ...): \n", " \"\"\"\n", " Optional doc string\n", " \"\"\"\n", " pass\n", "```\n", "The preferred convention for function names is to use [snake_case](https://en.wikipedia.org/wiki/Snake_case), i.e. lower case words separated by an underscore. (See the [PEP8 guidelines](https://www.python.org/dev/peps/pep-0008/) for Python programming for more details on how to write good Python code.) \n", "\n", "Right below the first line, we can place an optional documentation string (*doc string*) followed by the main function code, both indented to the right by a tab. It is not mandatory, but good programming practice to briefly describe what the function does, what input it expects and what the output will be.\n", "```python\n", "def function_name(variables1, variable2, ...): \n", " \"\"\"\n", " Optional doc string\n", " \"\"\"\n", " # main body of the function: set of operations to be performed\n", " # by the function\n", " return result\n", "```\n", "Here the main body of the code is commented out (remember that `#` marks a comment which extends until the end of the line). The keyword `return` is used to return the function's output (if not implemented the function returns `None`). Useful functions can be packaged in a *module* whose filename should end with the .py extension.\n", "\n", "The following function computes the surface area and volume of a cylinder:" ] }, { "cell_type": "code", "execution_count": 21, "metadata": {}, "outputs": [], "source": [ "def cylinder(radius, height):\n", " \"\"\"\n", " Computes the surface and volume of a cylinder\n", " \"\"\"\n", " from math import pi\n", "\n", " surface = 2 * pi * radius * height\n", " volume = pi * radius**2 * height\n", "\n", " return surface, volume" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some comments:\n", "\n", "- we need to fetch the value of $\\pi$ from the built-in module \\texttt{math}\n", "- the exponentiation operator is double asteriks `**` so ``3**4`` is 81 (see section \"Arithmetic operations\")\n", "- the function returns a tuple of two values\n", "\n", "We can call this function with some inputs and store the output as follows:" ] }, { "cell_type": "code", "execution_count": 22, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(12.566370614359172, 6.283185307179586)\n" ] } ], "source": [ "result = cylinder(1, 2)\n", "print(result)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "If we know that the function returns a tuple of two values, we can also directly assign them to specific variables (of course the variable names can be different from the ones used internally in the implementation of ``cylinder``):" ] }, { "cell_type": "code", "execution_count": 23, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "the surface area is 12.566370614359172\n", "the volume is 6.283185307179586\n" ] } ], "source": [ "surf, vol = cylinder(1, 2)\n", "print(f'the surface area is {surf}')\n", "print(f'the volume is {vol}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Python is not typed, therefore the input variables could be any quantity. If the input variables implement the operations that are executed in the function body (such as multiplication and exponentation), the function will also produce a useful output. For example, we could use numpy-arrays as inputs (much more about numpy later):" ] }, { "cell_type": "code", "execution_count": 24, "metadata": {}, "outputs": [ { "ename": "TypeError", "evalue": "can't multiply sequence by non-int of type 'float'", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mTypeError\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[0;31m# this doesn't work since the input doesn't support\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0;31m# the arithmetic operations carried out in 'cylinder'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0mresult\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mcylinder\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m'radius'\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;34m'height'\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;36mcylinder\u001b[0;34m(radius, height)\u001b[0m\n\u001b[1;32m 5\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mmath\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpi\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0msurface\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;36m2\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mpi\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mradius\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mheight\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 8\u001b[0m \u001b[0mvolume\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0mpi\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mradius\u001b[0m\u001b[0;34m**\u001b[0m\u001b[0;36m2\u001b[0m \u001b[0;34m*\u001b[0m \u001b[0mheight\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 9\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", "\u001b[0;31mTypeError\u001b[0m: can't multiply sequence by non-int of type 'float'" ] } ], "source": [ "# this doesn't work since the input doesn't support\n", "# the arithmetic operations carried out in 'cylinder'\n", "result = cylinder('radius', 'height')" ] }, { "cell_type": "code", "execution_count": 25, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "surface: [ 6.28318531 25.13274123 56.54866776 100.53096491 157.07963268]\n", " volume: [ 3.14159265 25.13274123 84.82300165 201.06192983 392.6990817 ]\n" ] } ], "source": [ "import numpy as np\n", "\n", "result = cylinder(np.arange(1,6), np.arange(1,6))\n", "print(f'surface: {result[0]}')\n", "print(f' volume: {result[1]}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "This function call returns a 2-tuple of arrays where each array has five values corresponding to the five values in the input arrays specifying the radii and heights.\n", "\n", "We can also call other user-defined functions within a function: " ] }, { "cell_type": "code", "execution_count": 26, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(12.566370614359172, 6.283185307179586)\n" ] } ], "source": [ "def circle(radius):\n", " \"\"\"\n", " Computes the circumference and area of a circle\n", " \"\"\"\n", " from math import pi\n", "\n", " circ = 2 * pi * radius\n", " area = pi * radius**2\n", " \n", " return circ, area\n", "\n", "\n", "def cylinder(radius, height):\n", " \"\"\"\n", " Computes the surface and volume of a cylinder\n", " \"\"\"\n", " circ, area = circle(radius)\n", "\n", " return circ * height, area * height\n", "\n", "\n", "print(cylinder(1, 2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We can also define functions within a function and call them:" ] }, { "cell_type": "code", "execution_count": 27, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(12.566370614359172, 6.283185307179586)\n" ] } ], "source": [ "def cylinder(radius, height):\n", " \"\"\"\n", " Computes the surface and volume of a cylinder\n", " \"\"\"\n", " def circle2(radius):\n", " \"\"\"\n", " Computes the circumference and area of a circle\n", " \"\"\"\n", " from math import pi\n", "\n", " circ = 2 * pi * radius\n", " area = pi * radius**2\n", " \n", " return circ, area\n", "\n", " circ, area = circle2(radius)\n", "\n", " return circ * height, area * height\n", "\n", "print(cylinder(1, 2))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The function `circle2` is only known locally within the *namespace* of the function `cylinder`. It is unknown outside the function `cylinder`:" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "(6.283185307179586, 3.141592653589793)\n" ] }, { "ename": "NameError", "evalue": "name 'circle2' is not defined", "output_type": "error", "traceback": [ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", "\u001b[0;31mNameError\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 5\u001b[0m \u001b[0;31m# 'circle2' cannot be called because it was defined only\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 6\u001b[0m \u001b[0;31m# within 'cylinder'\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 7\u001b[0;31m \u001b[0mprint\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mcircle2\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1.\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;31mNameError\u001b[0m: name 'circle2' is not defined" ] } ], "source": [ "# 'circle' can be called because it was defined before\n", "# in the global name space\n", "print(circle(1.))\n", "\n", "# 'circle2' cannot be called because it was defined only\n", "# within 'cylinder'\n", "print(circle2(1.))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Namespaces: local versus global variables\n", "\n", "The variables that are created inside a function are local variables, they only exist temporarily and are not accessible from outside: they are not part of the global namespace, but only of the local namespace defined within a function. All local variables are moved to the garbage collector (i.e. they are deleted in the long run) unless they are returned. " ] }, { "cell_type": "code", "execution_count": 29, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "identity of local variable \"z\" : 93873154654080\n", "identity of global variable \"a\": 93873154654080\n", "Is a variable named \"y\" part of the global namespace? - False\n", "Is a variable named \"a\" part of the global namespace? - True\n" ] } ], "source": [ "def f(x):\n", " \"\"\"\n", " Illustrating local and global variables\n", " \"\"\"\n", " # local variable that will not be accessible outside\n", " y = x**2 \n", " \n", " # local variable that will be accessible outside since it is returned\n", " z = y + 1 \n", " \n", " # show object's identity to check if indeed the local variable and\n", " # the one generated by calling the function point to the same memory\n", " # note that 'id(x)' returns the (unique) identity of python object 'x'\n", " print('identity of local variable \"z\" : {}'.format(id(z))) \n", " \n", " return z\n", "\n", "x = 10\n", "a = f(x)\n", "print('identity of global variable \"a\": {}'.format(id(a)))\n", "print('Is a variable named \"y\" part of the global namespace? - {}'.format(\n", " 'y' in globals()))\n", "print('Is a variable named \"a\" part of the global namespace? - {}'.format(\n", " 'a' in globals()))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Since the identity of the objects to which the local variable `z` and the global variable `a` refer is identical, they address the same memory. All variables that are part of the global namespace can be listed by calling the built-in function \n", "```python\n", "globals()\n", "```\n", "\n", "It is also possible to define global variables with the Python keyword `global`, but since the use of global variables is not recommended, we won't discuss global variables any further." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Algorithms and control structures\n", "\n", "An *algorithm* is an ordered sequence of precisely defined instructions that performs some task in a finite amount of time. Ordered means that the instructions can be numbered, but an algorithm must have the ability to alter the order of its instructions using a control structure. There are three categories of algorithmic operations:\n", "\n", "1. __Sequential operations__: Instructions executed in order.\n", "\n", "2. __Conditional operations__: Control structures that first ask a question to be answered with a true/false answer and then select the next instruction based on the answer.\n", "\n", "3. __Iterative operations (loops)__: Control structures that repeat the execution of a block of instructions.\n", "\n", "### Control structures: the `if`, `elif` and `else` keywords\n", "\n", "The `if` statement’s basic form is\n", "```python\n", "if condition:\n", " # do something\n", " pass\n", "```\n", "Every `if` statement terminates with a colon and must be followed by a block of commands that is indented to the right and will be executed, if the condition is met. A condition is a boolean-valued expression such as `i < 10`. " ] }, { "cell_type": "code", "execution_count": 30, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "value of \"a\" inside if block: 10\n", "value of \"a\" outside if block: 20\n" ] } ], "source": [ "a = 10\n", "if a < 20:\n", " print(f'value of \"a\" inside if block: {a}')\n", " a = 20\n", "print(f'value of \"a\" outside if block: {a}')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The basic structure for the use of the `if`-`else` statement is\n", "```python\n", "if condition:\n", " # do something\n", " pass\n", "else:\n", " # do something else\n", " pass\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The general form of the `if` statement is\n", "```python\n", "if condition1:\n", " # statement1\n", " pass\n", "elif condition2:\n", " # statement2\n", " pass\n", "else:\n", " # statement3\n", " pass\n", "```\n", "The `else` and `elif` keywords may be omitted if not required. However, if both are used, the `else` statement must come after the `elif` statement to take care of all conditions that are not met.\n", "\n", "Example:" ] }, { "cell_type": "code", "execution_count": 31, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "value is 0\n", "value is 1\n", "value is -1\n", "value is neither -1, 0, 1\n" ] } ], "source": [ "def f(value):\n", " if value == 0:\n", " print('value is 0')\n", " elif value == 1:\n", " print('value is 1')\n", " elif value == -1:\n", " print('value is -1')\n", " else:\n", " print('value is neither -1, 0, 1')\n", " \n", "f(0)\n", "f(1)\n", "f(-1)\n", "f(100)" ] }, { "cell_type": "code", "execution_count": 32, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "10\n" ] } ], "source": [ "# nested conditions\n", "a = 10\n", "if a < 11:\n", " if a > 9:\n", " print(a)\n", " else:\n", " print(a**2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Loops\n", "\n", "### The `for` loop\n", "\n", "A simple example of a `for` loop is\n", "```python\n", "for k in range(0, 11, 2):\n", " # for loop block\n", " pass\n", "``` \n", "The loop variable `k` is initially assigned the value 0, each successive pass through the loop increments `k` by 2 until the value 10 is reached. The program then continues to execute any statements following the end statement." ] }, { "cell_type": "code", "execution_count": 33, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "0 2 4 6 8 10 " ] } ], "source": [ "for k in range(0, 11, 2):\n", " print(k, end=' ')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The `for` loop can loop over any iterable quantity such as a list or a tuple.\n", "For example:" ] }, { "cell_type": "code", "execution_count": 34, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "x y 0 10 " ] } ], "source": [ "# create a list\n", "a = ['x', 'y', 0, 10] \n", "\n", "# loop over list and print elements\n", "for elem in a:\n", " print(elem, end=' ')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A convenient built-in command is \n", "```python\n", "enumerate\n", "```\n", "which returns an iterator that yields 2-tuples where the first element of the tuple is the list index and the second element is the list element:" ] }, { "cell_type": "code", "execution_count": 35, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "The 1-th element of list \"a\" is x (but the index is 0)\n", "The 2-th element of list \"a\" is y (but the index is 1)\n", "The 3-th element of list \"a\" is 0 (but the index is 2)\n", "The 4-th element of list \"a\" is 10 (but the index is 3)\n" ] } ], "source": [ "for i, elem in enumerate(a):\n", " print(f'The {i+1}-th element of list \"a\" is {elem} (but the index is {i})')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Another useful python command is \n", "```python\n", "zip\n", "```\n", "It allows you to zip up multiple lists in a zipper-like fashion:" ] }, { "cell_type": "code", "execution_count": 36, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "('x', -1, 'a')\n", "('y', -10, 'b')\n", "(0, None, 'c')\n" ] } ], "source": [ "# create three lists to be zipped\n", "a = ['x', 'y', 0, 10] \n", "b = [-1, -10, None, 'q']\n", "c = ['a', 'b', 'c']\n", "\n", "for t in zip(a, b, c):\n", " print(t)\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Note that the shortest list defines the number of tuples that are yielded by `zip`. In the above example, since list `c` has only three elements (whereas lists `a`, `b` have four), the iterator created by the `zip` command yields also only three 3-tuples." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### The `while` loop\n", "\n", "The `while` loop is used when the looping process terminates because a specified condition is satisfied, and thus the number of passes is not known in advance. A simple example of a while loop is\n", "```python\n", "while condition:\n", " # while code block\n", " pass\n", "```\n", "For the correct execution of a while loop the following two conditions must be satisfied:\n", "\n", "- The loop variable must have a value before the `while` statement is executed\n", "- The loop variable must be changed somehow by the statements\n", "\n", "Here is a simple example of a `while` loop:" ] }, { "cell_type": "code", "execution_count": 37, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5 9 17 " ] } ], "source": [ "x = 5\n", "while x < 25:\n", " print(x, end=' ')\n", " x = 2*x - 1" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "The Python keyword `break` allows you to break out of a while loop. " ] }, { "cell_type": "code", "execution_count": 38, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5 9 " ] } ], "source": [ "# without the break statement this loop would run\n", "# forever\n", "x = 5\n", "while True:\n", " print(x, end=' ')\n", " x = 2*x - 1\n", " if x > 12:\n", " break" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "A little quiz: Before executing the code try to guess what will be printed to standard output:" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "scrolled": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 1 2 3 5 8 13 21 34 55 89 " ] } ], "source": [ "a, b = 1, 1\n", "\n", "while a < 100:\n", " print(a, end=' ')\n", " a, b = b, a+b" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## General structure of a Python script\n", "\n", "The general structure of a Python program or script is as follows:\n", "``` python\n", "\"\"\"\n", "Documentation briefly explaining the script's functionality\n", "\"\"\"\n", "# load modules that are needed by the script\n", "import something\n", "\n", "# User-defined functions\n", "def my_function1():\n", " pass\n", "\n", "# Test code or main code\n", "if __name__ == '__main__':\n", " # Put some code running the above function(s) here\n", " # For example\n", " my_function1()\n", "```\n", "By using the condition\n", "``` python\n", "if __name__ == '__main__':\n", "```\n", "you can at the same time \n", "\n", "1. __test__ your code while developing it, \n", "2. __use__ the functions that you defined yourself in some other code __without__ executing the test code.\n", "\n", "A simple example is the following script `circle.py`" ] }, { "cell_type": "code", "execution_count": 40, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "6.283185307179586\n" ] } ], "source": [ "\"\"\"\n", "This module defines a constant 'twopi' and computes the circumference \n", "of a circle\n", "\"\"\"\n", "import math\n", "\n", "# define 2*pi \n", "twopi = 2 * math.pi\n", "\n", "def circumference(radius):\n", " \"\"\"\n", " Computes the circumference of a circle with the given radius\n", " \"\"\"\n", " return twopi * radius\n", "\n", "if __name__ == '__main__':\n", " # some test code\n", " print(circumference(1.))\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "You could save this piece of code in a py-file called, e.g., `circle.py` and use it in some other other \"client\" code:\n", "``` python\n", "# import my own module (without executing the test code)\n", "import circle\n", "l = circle.circumference(2.)\n", "print(circle.twopi)\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Strings\n", "\n", "### String methods" ] }, { "cell_type": "code", "execution_count": 41, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Image Processing I\n", "['Image', 'Processing', 'I']\n", "image processing i\n", "Image+Processing+I\n", "2\n", "3\n" ] } ], "source": [ "s = 'Image Processing I'\n", "print(s)\n", "print(s.split())\n", "print(s.lower())\n", "print(s.replace(' ', '+'))\n", "print(s.count('s'))\n", "print(s.index('g'))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Creating strings with format strings\n" ] }, { "cell_type": "code", "execution_count": 42, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "12\n", "00101101\n" ] } ], "source": [ "s = '{0:d}'\n", "print(s.format(12))\n", "s = '{0:08b}'\n", "print(s.format(45))" ] } ], "metadata": { "hide_input": false, "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.7.6" }, "latex_envs": { "LaTeX_envs_menu_present": true, "autoclose": false, "autocomplete": true, "bibliofile": "biblio.bib", "cite_by": "apalike", "current_citInitial": 1, "eqLabelWithNumbers": true, "eqNumInitial": 1, "hotkeys": { "equation": "Ctrl-E", "itemize": "Ctrl-I" }, "labels_anchors": false, "latex_user_defs": false, "report_style_numbering": false, "user_envs_cfg": false }, "nbTranslate": { "displayLangs": [ "*" ], "hotkey": "alt-t", "langInMainMenu": true, "sourceLang": "en", "targetLang": "fr", "useGoogleTranslate": true } }, "nbformat": 4, "nbformat_minor": 2 }