diff --git a/python_course_2018.ipynb b/python_course_2018.ipynb
new file mode 100644
index 0000000000000000000000000000000000000000..fafc1cf40c7e0e090e2b2be57ae8f6eb0cb89dab
--- /dev/null
+++ b/python_course_2018.ipynb
@@ -0,0 +1,1431 @@
+{
+ "cells": [
+  {
+   "cell_type": "code",
+   "execution_count": 1,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "False"
+      ]
+     },
+     "execution_count": 1,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "1 == 2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 2,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "True"
+      ]
+     },
+     "execution_count": 2,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "1 == 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 3,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "True"
+      ]
+     },
+     "execution_count": 3,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "1 is 1"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 4,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "140184959628256"
+      ]
+     },
+     "execution_count": 4,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "id(1)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 5,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "True"
+      ]
+     },
+     "execution_count": 5,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a = 1\n",
+    "b = 1\n",
+    "a is b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "False"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a = 257\n",
+    "b = 257\n",
+    "a is b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def name():\n",
+    "    print(\"ciao\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 9,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ciao\n"
+     ]
+    }
+   ],
+   "source": [
+    "name()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 20,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def hello(name):\n",
+    "    print(f\"ciao {name:05d}!\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 21,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ciao 00012!\n"
+     ]
+    }
+   ],
+   "source": [
+    "hello(12)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 22,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'12'"
+      ]
+     },
+     "execution_count": 22,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "\"%d\" % 12"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 23,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "TypeError",
+     "evalue": "hello() missing 1 required positional argument: 'name'",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-23-a75d7781aaeb>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mhello\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;31mTypeError\u001b[0m: hello() missing 1 required positional argument: 'name'"
+     ]
+    }
+   ],
+   "source": [
+    "hello()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 30,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def hello(name, phrase=\"ciao {name}!\"):\n",
+    "    print(phrase.format(name=name))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 31,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ciao jenny!\n"
+     ]
+    }
+   ],
+   "source": [
+    "hello(\"jenny\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 33,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def hello(phrase=\"ciao {name}!\", *names):\n",
+    "    for name in names:\n",
+    "        print(phrase.format(name=name))"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 34,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "pietro\n",
+      "pietro\n"
+     ]
+    }
+   ],
+   "source": [
+    "hello(\"pietro\", \"bart\", \"mauro\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 35,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ciao pietro!\n",
+      "ciao bart!\n",
+      "ciao mauro!\n"
+     ]
+    }
+   ],
+   "source": [
+    "def hello(*names):\n",
+    "    for name in names:\n",
+    "        print(\"ciao {name}!\".format(name=name))\n",
+    "        \n",
+    "hello(\"pietro\", \"bart\", \"mauro\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 42,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "ciao pietro! ciao pietro! ciao pietro! \n",
+      "ciao bart! ciao bart! ciao bart! \n",
+      "ciao mauro! ciao mauro! ciao mauro! \n"
+     ]
+    }
+   ],
+   "source": [
+    "def hello(names: list, repeat : int =3):\n",
+    "    for name in names:\n",
+    "        print(\"ciao {name}! \".format(name=name) * repeat)\n",
+    "        \n",
+    "hello([\"pietro\", \"bart\", \"mauro\"])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 43,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "diz = dict(pietro=1982, )"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 44,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "1982"
+      ]
+     },
+     "execution_count": 44,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "diz[\"pietro\"]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 45,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class Rectangle():\n",
+    "    def __init__(self, a: float, b: float):\n",
+    "        self.a = a\n",
+    "        self.b = b"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 46,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "rect0 = Rectangle(2, 3)\n",
+    "rect1 = Rectangle(4, 5)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 47,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{<__main__.Rectangle at 0x7f7f4d750710>: 0,\n",
+       " <__main__.Rectangle at 0x7f7f4d7505f8>: 1}"
+      ]
+     },
+     "execution_count": 47,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "{rect0: 0, rect1: 1}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 48,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{__main__.Rectangle: 1}"
+      ]
+     },
+     "execution_count": 48,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "{Rectangle: 0, Rectangle: 1}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 49,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'asjcvbvjwe'"
+      ]
+     },
+     "execution_count": 49,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "\"asjc\" + \"vbvjwe\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 50,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "TypeError",
+     "evalue": "can only concatenate str (not \"int\") to str",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-50-ccdfa72cd790>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0;34m\"asjc\"\u001b[0m \u001b[0;34m+\u001b[0m \u001b[0;36m2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;31mTypeError\u001b[0m: can only concatenate str (not \"int\") to str"
+     ]
+    }
+   ],
+   "source": [
+    "\"asjc\" + 2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 51,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "'=================================================='"
+      ]
+     },
+     "execution_count": 51,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "\"=\" * 50"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 52,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['a', 'b', 'c', 'd']"
+      ]
+     },
+     "execution_count": 52,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "['a', 'b'] + ['c', 'd'] "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 53,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "['a', 'b', 'a', 'b']"
+      ]
+     },
+     "execution_count": 53,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "['a', 'b'] * 2"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 60,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def hello(**kwargs):\n",
+    "    for k, v in kwargs.items():\n",
+    "        print(f\"key: {k}, value: {v}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 55,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "key: pietro, value: urs\n",
+      "key: bart, value: remote_sensing\n"
+     ]
+    }
+   ],
+   "source": [
+    "hello(pietro=\"urs\", bart=\"remote_sensing\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 56,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def hello(pietro=\"urs\", bart=\"remote_sensing\"):\n",
+    "    print(f\"key: pietro, value: {pietro}\")\n",
+    "    print(f\"key: bart, value: {bart}\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 57,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "key: pietro, value: urs\n",
+      "key: bart, value: remote_sensing\n"
+     ]
+    }
+   ],
+   "source": [
+    "hello()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 58,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "mydict = dict(pietro=\"urs\", bart=\"remote_sensing\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 59,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'pietro': 'urs', 'bart': 'remote_sensing'}"
+      ]
+     },
+     "execution_count": 59,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "mydict"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 62,
+   "metadata": {},
+   "outputs": [
+    {
+     "ename": "TypeError",
+     "evalue": "hello() takes 0 positional arguments but 1 was given",
+     "output_type": "error",
+     "traceback": [
+      "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+      "\u001b[0;31mTypeError\u001b[0m                                 Traceback (most recent call last)",
+      "\u001b[0;32m<ipython-input-62-84ba45c67bcd>\u001b[0m in \u001b[0;36m<module>\u001b[0;34m()\u001b[0m\n\u001b[0;32m----> 1\u001b[0;31m \u001b[0mhello\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mmydict\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+      "\u001b[0;31mTypeError\u001b[0m: hello() takes 0 positional arguments but 1 was given"
+     ]
+    }
+   ],
+   "source": [
+    "hello(mydict)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 63,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a = \"fjd\"\n",
+    "b = \"jrhdfj\""
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 64,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "140184737090560"
+      ]
+     },
+     "execution_count": 64,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "id(a)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 65,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "140184737128888"
+      ]
+     },
+     "execution_count": 65,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "id(b)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 66,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "140184737112560"
+      ]
+     },
+     "execution_count": 66,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "id(a+b)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 67,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a = [1, 2, 3]"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 68,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "140184737120328"
+      ]
+     },
+     "execution_count": 68,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "id(a)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 75,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "a.append(['a', 'b'])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 76,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[1, 2, 3, 'a', 'b', ['a', 'b']]"
+      ]
+     },
+     "execution_count": 76,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "a"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 77,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "140184737120328"
+      ]
+     },
+     "execution_count": 77,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "id(a)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 80,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def append(value, mylist=[]):\n",
+    "    mylist.append(value)\n",
+    "    return mylist"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 83,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[2]"
+      ]
+     },
+     "execution_count": 83,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "append(2, [])"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 85,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def mylongwork(value, _cache={}):\n",
+    "    if value not in _cache:\n",
+    "        _cache[value] = abs(value)\n",
+    "    return _cache[value]\n",
+    "        "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 94,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def func0(a, par=None):\n",
+    "    par = [] if par is None else par\n",
+    "    def func1(b):\n",
+    "        return a * b\n",
+    "    return func1\n",
+    "    "
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 98,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "15"
+      ]
+     },
+     "execution_count": 98,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "f1 = func0(3)\n",
+    "f1(5)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 87,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "{'a': 1, 'b': 1}"
+      ]
+     },
+     "execution_count": 87,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "{k: v for k, v in [('a', 1), ('b', 1)]}"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 93,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[1, 9, 25, 49, 81]"
+      ]
+     },
+     "execution_count": 93,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "mylist = [i*i for i in range(10) if i % 2]\n",
+    "mylist"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 92,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "[1, 9, 25, 49, 81]"
+      ]
+     },
+     "execution_count": 92,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "mylist = []\n",
+    "for i in range(10):\n",
+    "    if i % 2:\n",
+    "        mylist.append(i*i)\n",
+    "mylist"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 103,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from functools import lru_cache\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 104,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "@lru_cache(maxsize=32)\n",
+    "def fib_cached(n):\n",
+    "    if n < 2:\n",
+    "        return n\n",
+    "    return fib_cached(n-1) + fib_cached(n-2)\n",
+    "\n",
+    "def fib_std(n):\n",
+    "    if n < 2:\n",
+    "        return n\n",
+    "    return fib_std(n-1) + fib_std(n-2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 105,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "15.8 ms ± 310 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n"
+     ]
+    }
+   ],
+   "source": [
+    "%timeit fib_std(24)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 106,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "106 ns ± 8.54 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)\n"
+     ]
+    }
+   ],
+   "source": [
+    "%timeit fib_cached(24)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 115,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "from time import time\n",
+    "\n",
+    "def mydec(func, *args, **kwargs):\n",
+    "    start = time()\n",
+    "    value = func(*args, **kwargs)\n",
+    "    stop = time()\n",
+    "    print(f\"It tooks {stop - start}s...\")\n",
+    "    return value"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 116,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "It tooks 9.489059448242188e-05s...\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "144"
+      ]
+     },
+     "execution_count": 116,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "mydec(fib_std, 12)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 118,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "def mydec(func):\n",
+    "    def wrapper(*args, **kwargs):\n",
+    "        start = time()\n",
+    "        value = func(*args, **kwargs)\n",
+    "        stop = time()\n",
+    "        print(f\"It tooks {stop - start}s...\")\n",
+    "        return value\n",
+    "    return wrapper"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 119,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "@mydec\n",
+    "def fib_std(n):\n",
+    "    if n < 2:\n",
+    "        return n\n",
+    "    return fib_std(n-1) + fib_std(n-2)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 120,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "It tooks 9.5367431640625e-07s...\n",
+      "It tooks 1.1920928955078125e-06s...\n",
+      "It tooks 0.00012040138244628906s...\n",
+      "It tooks 7.152557373046875e-07s...\n",
+      "It tooks 0.00048065185546875s...\n",
+      "It tooks 2.384185791015625e-07s...\n",
+      "It tooks 2.384185791015625e-07s...\n",
+      "It tooks 3.743171691894531e-05s...\n",
+      "It tooks 0.0005590915679931641s...\n",
+      "It tooks 2.384185791015625e-07s...\n",
+      "It tooks 2.384185791015625e-07s...\n",
+      "It tooks 3.0994415283203125e-05s...\n",
+      "It tooks 2.384185791015625e-07s...\n",
+      "It tooks 6.270408630371094e-05s...\n",
+      "It tooks 0.0006537437438964844s...\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "5"
+      ]
+     },
+     "execution_count": 120,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "fib_std(5)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 121,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "import numpy as np"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 123,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stdout",
+     "output_type": "stream",
+     "text": [
+      "array(object, dtype=None, copy=True, order='K', subok=False, ndmin=0)\n",
+      "\n",
+      "    Create an array.\n",
+      "\n",
+      "    Parameters\n",
+      "    ----------\n",
+      "    object : array_like\n",
+      "        An array, any object exposing the array interface, an object whose\n",
+      "        __array__ method returns an array, or any (nested) sequence.\n",
+      "    dtype : data-type, optional\n",
+      "        The desired data-type for the array.  If not given, then the type will\n",
+      "        be determined as the minimum type required to hold the objects in the\n",
+      "        sequence.  This argument can only be used to 'upcast' the array.  For\n",
+      "        downcasting, use the .astype(t) method.\n",
+      "    copy : bool, optional\n",
+      "        If true (default), then the object is copied.  Otherwise, a copy will\n",
+      "        only be made if __array__ returns a copy, if obj is a nested sequence,\n",
+      "        or if a copy is needed to satisfy any of the other requirements\n",
+      "        (`dtype`, `order`, etc.).\n",
+      "    order : {'K', 'A', 'C', 'F'}, optional\n",
+      "        Specify the memory layout of the array. If object is not an array, the\n",
+      "        newly created array will be in C order (row major) unless 'F' is\n",
+      "        specified, in which case it will be in Fortran order (column major).\n",
+      "        If object is an array the following holds.\n",
+      "\n",
+      "        ===== ========= ===================================================\n",
+      "        order  no copy                     copy=True\n",
+      "        ===== ========= ===================================================\n",
+      "        'K'   unchanged F & C order preserved, otherwise most similar order\n",
+      "        'A'   unchanged F order if input is F and not C, otherwise C order\n",
+      "        'C'   C order   C order\n",
+      "        'F'   F order   F order\n",
+      "        ===== ========= ===================================================\n",
+      "\n",
+      "        When ``copy=False`` and a copy is made for other reasons, the result is\n",
+      "        the same as if ``copy=True``, with some exceptions for `A`, see the\n",
+      "        Notes section. The default order is 'K'.\n",
+      "    subok : bool, optional\n",
+      "        If True, then sub-classes will be passed-through, otherwise\n",
+      "        the returned array will be forced to be a base-class array (default).\n",
+      "    ndmin : int, optional\n",
+      "        Specifies the minimum number of dimensions that the resulting\n",
+      "        array should have.  Ones will be pre-pended to the shape as\n",
+      "        needed to meet this requirement.\n",
+      "\n",
+      "    Returns\n",
+      "    -------\n",
+      "    out : ndarray\n",
+      "        An array object satisfying the specified requirements.\n",
+      "\n",
+      "    See Also\n",
+      "    --------\n",
+      "    empty_like : Return an empty array with shape and type of input.\n",
+      "    ones_like : Return an array of ones with shape and type of input.\n",
+      "    zeros_like : Return an array of zeros with shape and type of input.\n",
+      "    full_like : Return a new array with shape of input filled with value.\n",
+      "    empty : Return a new uninitialized array.\n",
+      "    ones : Return a new array setting values to one.\n",
+      "    zeros : Return a new array setting values to zero.\n",
+      "    full : Return a new array of given shape filled with value.\n",
+      "\n",
+      "\n",
+      "    Notes\n",
+      "    -----\n",
+      "    When order is 'A' and `object` is an array in neither 'C' nor 'F' order,\n",
+      "    and a copy is forced by a change in dtype, then the order of the result is\n",
+      "    not necessarily 'C' as expected. This is likely a bug.\n",
+      "\n",
+      "    Examples\n",
+      "    --------\n",
+      "    >>> np.array([1, 2, 3])\n",
+      "    array([1, 2, 3])\n",
+      "\n",
+      "    Upcasting:\n",
+      "\n",
+      "    >>> np.array([1, 2, 3.0])\n",
+      "    array([ 1.,  2.,  3.])\n",
+      "\n",
+      "    More than one dimension:\n",
+      "\n",
+      "    >>> np.array([[1, 2], [3, 4]])\n",
+      "    array([[1, 2],\n",
+      "           [3, 4]])\n",
+      "\n",
+      "    Minimum dimensions 2:\n",
+      "\n",
+      "    >>> np.array([1, 2, 3], ndmin=2)\n",
+      "    array([[1, 2, 3]])\n",
+      "\n",
+      "    Type provided:\n",
+      "\n",
+      "    >>> np.array([1, 2, 3], dtype=complex)\n",
+      "    array([ 1.+0.j,  2.+0.j,  3.+0.j])\n",
+      "\n",
+      "    Data-type consisting of more than one element:\n",
+      "\n",
+      "    >>> x = np.array([(1,2),(3,4)],dtype=[('a','<i4'),('b','<i4')])\n",
+      "    >>> x['a']\n",
+      "    array([1, 3])\n",
+      "\n",
+      "    Creating an array from sub-classes:\n",
+      "\n",
+      "    >>> np.array(np.mat('1 2; 3 4'))\n",
+      "    array([[1, 2],\n",
+      "           [3, 4]])\n",
+      "\n",
+      "    >>> np.array(np.mat('1 2; 3 4'), subok=True)\n",
+      "    matrix([[1, 2],\n",
+      "            [3, 4]])\n"
+     ]
+    }
+   ],
+   "source": [
+    "print(np.array.__doc__)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 130,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class Rectangle():\n",
+    "    x : int = 100  # class attribute\n",
+    "\n",
+    "    def __init__(self, a, b):\n",
+    "        self.a = a   # \n",
+    "        self.b = b\n"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 132,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "rect0 = Rectangle(2, 4)\n",
+    "rect1 = Rectangle(5, 6)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 139,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "rect0.y = 4000"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 134,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "100"
+      ]
+     },
+     "execution_count": 134,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rect1.x"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 140,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "rect0.__class__.y = 5000"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 141,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "5000"
+      ]
+     },
+     "execution_count": 141,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rect1.y"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 142,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "4000"
+      ]
+     },
+     "execution_count": 142,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rect0.y"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 151,
+   "metadata": {},
+   "outputs": [],
+   "source": [
+    "class Rectangle():\n",
+    "    def __init__(self, a: float, b: float):\n",
+    "        self.a = a   # \n",
+    "        self.b = b\n",
+    "        \n",
+    "    def area(self):\n",
+    "        return self.a * self.b\n",
+    "    \n",
+    "    def __repr__(self):\n",
+    "        return f\"Rectangle(a={self.a}, b={self.b})\"\n",
+    "    \n",
+    "    def __add__(self, other):\n",
+    "        return Rectangle(a=self.a + other.a, b=self.b + other.b)\n",
+    "        \n",
+    "        \n",
+    "        \n",
+    "rect0 = Rectangle(2, 4)\n",
+    "rect1 = Rectangle(5, 6)"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 149,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "8"
+      ]
+     },
+     "execution_count": 149,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rect0.area()"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 152,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/plain": [
+       "Rectangle(a=7, b=10)"
+      ]
+     },
+     "execution_count": 152,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "rect0 + rect1"
+   ]
+  },
+  {
+   "cell_type": "markdown",
+   "metadata": {},
+   "source": [
+    "A complete list of magic methods is available here:\n",
+    "\n",
+    "https://rszalski.github.io/magicmethods/"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": null,
+   "metadata": {},
+   "outputs": [],
+   "source": []
+  }
+ ],
+ "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.7.0"
+  }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 2
+}