summaryrefslogtreecommitdiff
path: root/notebooks/python/python_intro.ipynb
diff options
context:
space:
mode:
Diffstat (limited to 'notebooks/python/python_intro.ipynb')
-rw-r--r--notebooks/python/python_intro.ipynb453
1 files changed, 393 insertions, 60 deletions
diff --git a/notebooks/python/python_intro.ipynb b/notebooks/python/python_intro.ipynb
index a2acfbc..3c49a14 100644
--- a/notebooks/python/python_intro.ipynb
+++ b/notebooks/python/python_intro.ipynb
@@ -62,7 +62,7 @@
62 }, 62 },
63 { 63 {
64 "cell_type": "code", 64 "cell_type": "code",
65 "execution_count": 96, 65 "execution_count": 50,
66 "id": "54c9e132-30b0-41bf-97e9-0e8b94f3d202", 66 "id": "54c9e132-30b0-41bf-97e9-0e8b94f3d202",
67 "metadata": {}, 67 "metadata": {},
68 "outputs": [], 68 "outputs": [],
@@ -109,7 +109,7 @@
109 }, 109 },
110 { 110 {
111 "cell_type": "code", 111 "cell_type": "code",
112 "execution_count": 97, 112 "execution_count": 51,
113 "id": "bd6134d9-cc0e-4b45-b6b3-50210f6395e2", 113 "id": "bd6134d9-cc0e-4b45-b6b3-50210f6395e2",
114 "metadata": {}, 114 "metadata": {},
115 "outputs": [], 115 "outputs": [],
@@ -122,7 +122,8 @@
122 "\n", 122 "\n",
123 "i = 6 # int, same as int('6'), immutable\n", 123 "i = 6 # int, same as int('6'), immutable\n",
124 "\n", 124 "\n",
125 "f = 0.1 # float, same as float('0.1'), immutable\n", 125 "f = 0.1 # float, same as float('0.1'), immutable, Note!!: Floats have a fixed size,\n",
126 "# hence they don't necessarily behave they way we expect from math class.\n",
126 "\n", 127 "\n",
127 "b = False # bool, same as bool(0), bool(''), bool(None)... immutable / constant\n", 128 "b = False # bool, same as bool(0), bool(''), bool(None)... immutable / constant\n",
128 "\n", 129 "\n",
@@ -138,6 +139,205 @@
138 ] 139 ]
139 }, 140 },
140 { 141 {
142 "cell_type": "code",
143 "execution_count": 52,
144 "id": "cd2b7f98-ea16-49e2-9d19-f37266bd4f3a",
145 "metadata": {},
146 "outputs": [
147 {
148 "name": "stdout",
149 "output_type": "stream",
150 "text": [
151 "'can be written like this'\n"
152 ]
153 },
154 {
155 "data": {
156 "text/plain": [
157 "'foo bar'"
158 ]
159 },
160 "execution_count": 52,
161 "metadata": {},
162 "output_type": "execute_result"
163 },
164 {
165 "name": "stdout",
166 "output_type": "stream",
167 "text": [
168 "works just fine\n",
169 "works\n",
170 "just\n",
171 "fine\n"
172 ]
173 },
174 {
175 "data": {
176 "text/plain": [
177 "'S'"
178 ]
179 },
180 "execution_count": 52,
181 "metadata": {},
182 "output_type": "execute_result"
183 },
184 {
185 "data": {
186 "text/plain": [
187 "'t'"
188 ]
189 },
190 "execution_count": 52,
191 "metadata": {},
192 "output_type": "execute_result"
193 },
194 {
195 "data": {
196 "text/plain": [
197 "'tatnett'"
198 ]
199 },
200 "execution_count": 52,
201 "metadata": {},
202 "output_type": "execute_result"
203 },
204 {
205 "data": {
206 "text/plain": [
207 "'tatnet'"
208 ]
209 },
210 "execution_count": 52,
211 "metadata": {},
212 "output_type": "execute_result"
213 },
214 {
215 "data": {
216 "text/plain": [
217 "'ett'"
218 ]
219 },
220 "execution_count": 52,
221 "metadata": {},
222 "output_type": "execute_result"
223 },
224 {
225 "data": {
226 "text/plain": [
227 "'tte'"
228 ]
229 },
230 "execution_count": 52,
231 "metadata": {},
232 "output_type": "execute_result"
233 },
234 {
235 "data": {
236 "text/plain": [
237 "True"
238 ]
239 },
240 "execution_count": 52,
241 "metadata": {},
242 "output_type": "execute_result"
243 },
244 {
245 "data": {
246 "text/plain": [
247 "False"
248 ]
249 },
250 "execution_count": 52,
251 "metadata": {},
252 "output_type": "execute_result"
253 },
254 {
255 "data": {
256 "text/plain": [
257 "True"
258 ]
259 },
260 "execution_count": 52,
261 "metadata": {},
262 "output_type": "execute_result"
263 },
264 {
265 "data": {
266 "text/plain": [
267 "b'B\\xc3\\x98!'"
268 ]
269 },
270 "execution_count": 52,
271 "metadata": {},
272 "output_type": "execute_result"
273 },
274 {
275 "data": {
276 "text/plain": [
277 "'BØ!'"
278 ]
279 },
280 "execution_count": 52,
281 "metadata": {},
282 "output_type": "execute_result"
283 }
284 ],
285 "source": [
286 "# Strings and bytes\n",
287 "\n",
288 "# apart from other programming languages (PHP, Perl), the next two lines are virtually equal in Python\n",
289 "s = 'can be written like this' # ... and should be written like this\n",
290 "s = \"can be written like this\"\n",
291 "print(repr(s)) # the official Python repr uses single quotes\n",
292 "\n",
293 "# the only important difference:\n",
294 "s = 'can\\'t be written like this'\n",
295 "s = \"can't be written like this\" # better\n",
296 "s = \"can be written \\\"like this\\\"\"\n",
297 "s = 'can be written \"like this\"' # better\n",
298 "\n",
299 "s1 = 'foo'\n",
300 "s2 = 'bar'\n",
301 "s1 + ' ' + s2\n",
302 "\n",
303 "# without new line\n",
304 "print(\n",
305 " 'works '\n",
306 " 'just '\n",
307 " 'fine'\n",
308 ")\n",
309 "\n",
310 "# with new line\n",
311 "print(\n",
312 " 'works\\n'\n",
313 " 'just\\n'\n",
314 " 'fine'\n",
315 ")\n",
316 "\n",
317 "# slicing [from:until(not included):step] - produces a new string (copy)\n",
318 "s3 = 'Statnett'\n",
319 "s3[0] # Out: S\n",
320 "s3[-1] # Out: t\n",
321 "s3[1:] # Out: tatnett\n",
322 "s3[1:-1] # Out: tatnett\n",
323 "s3[-3:] # Out: ett\n",
324 "s3[1:-1:2] # Out: tte\n",
325 "\n",
326 "s3.endswith('nett') # Out: True\n",
327 "s3.startswith('sta') # Out: False (case sensitive)\n",
328 "s3[-4:] == 'nett' # works, but BAD coding style\n",
329 "\n",
330 "# All strings in Python 3 are unicode strings (unicode type) and not byte strings as in Python 2\n",
331 "# One doesn't write strings to: files, sockets, cryptographic functions etc... but rather 'bytes'\n",
332 "\n",
333 "# from unicode string to bytes (UTF-8)\n",
334 "'BØ!'.encode('utf-8') # utf-8 is implicit in Python 3\n",
335 "\n",
336 "# bytes to unicode\n",
337 "b'B\\xc3\\x98!'.decode('utf-8') # utf-8 is implicit in Python 3"
338 ]
339 },
340 {
141 "cell_type": "markdown", 341 "cell_type": "markdown",
142 "id": "6b2bc8fa-a5dc-4a58-92b2-abfb19bfe2ed", 342 "id": "6b2bc8fa-a5dc-4a58-92b2-abfb19bfe2ed",
143 "metadata": {}, 343 "metadata": {},
@@ -320,27 +520,27 @@
320 }, 520 },
321 { 521 {
322 "cell_type": "code", 522 "cell_type": "code",
323 "execution_count": 98, 523 "execution_count": 53,
324 "id": "f4a4ea99-4038-4b61-9b8d-9ce623e6a663", 524 "id": "f4a4ea99-4038-4b61-9b8d-9ce623e6a663",
325 "metadata": {}, 525 "metadata": {},
326 "outputs": [ 526 "outputs": [
327 { 527 {
328 "data": { 528 "data": {
329 "text/plain": [ 529 "text/plain": [
330 "35041378544" 530 "35082617072"
331 ] 531 ]
332 }, 532 },
333 "execution_count": 98, 533 "execution_count": 53,
334 "metadata": {}, 534 "metadata": {},
335 "output_type": "execute_result" 535 "output_type": "execute_result"
336 }, 536 },
337 { 537 {
338 "data": { 538 "data": {
339 "text/plain": [ 539 "text/plain": [
340 "35041378576" 540 "35082617104"
341 ] 541 ]
342 }, 542 },
343 "execution_count": 98, 543 "execution_count": 53,
344 "metadata": {}, 544 "metadata": {},
345 "output_type": "execute_result" 545 "output_type": "execute_result"
346 }, 546 },
@@ -350,7 +550,7 @@
350 "'H'" 550 "'H'"
351 ] 551 ]
352 }, 552 },
353 "execution_count": 98, 553 "execution_count": 53,
354 "metadata": {}, 554 "metadata": {},
355 "output_type": "execute_result" 555 "output_type": "execute_result"
356 }, 556 },
@@ -360,47 +560,47 @@
360 "-6333845781340707986" 560 "-6333845781340707986"
361 ] 561 ]
362 }, 562 },
363 "execution_count": 98, 563 "execution_count": 53,
364 "metadata": {}, 564 "metadata": {},
365 "output_type": "execute_result" 565 "output_type": "execute_result"
366 }, 566 },
367 { 567 {
368 "data": { 568 "data": {
369 "text/plain": [ 569 "text/plain": [
370 "36321214208" 570 "36350585520"
371 ] 571 ]
372 }, 572 },
373 "execution_count": 98, 573 "execution_count": 53,
374 "metadata": {}, 574 "metadata": {},
375 "output_type": "execute_result" 575 "output_type": "execute_result"
376 }, 576 },
377 { 577 {
378 "data": { 578 "data": {
379 "text/plain": [ 579 "text/plain": [
380 "36321613808" 580 "36350587520"
381 ] 581 ]
382 }, 582 },
383 "execution_count": 98, 583 "execution_count": 53,
384 "metadata": {}, 584 "metadata": {},
385 "output_type": "execute_result" 585 "output_type": "execute_result"
386 }, 586 },
387 { 587 {
388 "data": { 588 "data": {
389 "text/plain": [ 589 "text/plain": [
390 "27542959409390741" 590 "8927089887582119463"
391 ] 591 ]
392 }, 592 },
393 "execution_count": 98, 593 "execution_count": 53,
394 "metadata": {}, 594 "metadata": {},
395 "output_type": "execute_result" 595 "output_type": "execute_result"
396 }, 596 },
397 { 597 {
398 "data": { 598 "data": {
399 "text/plain": [ 599 "text/plain": [
400 "27542959409390741" 600 "8927089887582119463"
401 ] 601 ]
402 }, 602 },
403 "execution_count": 98, 603 "execution_count": 53,
404 "metadata": {}, 604 "metadata": {},
405 "output_type": "execute_result" 605 "output_type": "execute_result"
406 } 606 }
@@ -442,6 +642,9 @@
442 "\n", 642 "\n",
443 "A function is a sequence of program instructions that performs a specific task, packaged as a unit.\n", 643 "A function is a sequence of program instructions that performs a specific task, packaged as a unit.\n",
444 "\n", 644 "\n",
645 "\n",
646 "### Why use functions?\n",
647 "\n",
445 "Functions let you:\n", 648 "Functions let you:\n",
446 "\n", 649 "\n",
447 "- reuse code across several programs / projects\n", 650 "- reuse code across several programs / projects\n",
@@ -456,20 +659,51 @@
456 "\n", 659 "\n",
457 "- improve traceability\n", 660 "- improve traceability\n",
458 "\n", 661 "\n",
662 "\n",
663 "### Any downside?\n",
664 "\n",
459 "Function calls bring some overhead pushing / popping function-data into / from stack.\n", 665 "Function calls bring some overhead pushing / popping function-data into / from stack.\n",
460 "\n", 666 "\n",
667 "```python\n",
668 "empty_list = list()\n",
669 "empty_dict = dict()\n",
670 "\n",
671 "# better since it avoids the function call:\n",
672 "empty_list = []\n",
673 "empty_dict = {}\n",
674 "```\n",
675 "\n",
676 "\n",
677 "### Definitions\n",
678 "\n",
461 "Important definitions (may have different meanings in different programming languages):\n", 679 "Important definitions (may have different meanings in different programming languages):\n",
462 "\n", 680 "\n",
463 "- *parameter / formal parameter* - variable / data provided as input to the function\n", 681 "- *parameter / formal parameter* - the names that appear in a function definition. Parameters define what kind of arguments a function can accept.\n",
682 "\n",
683 "- *argument / actual parameter* - the values actually passed to a function when calling it.\n",
464 "\n", 684 "\n",
465 "- *argument / actual parameter* - local variable / data to the given function\n",
466 "\n", 685 "\n",
467 "The keyword `def` introduces a function definition." 686 "The keyword `def` introduces a function definition.\n",
687 "\n",
688 "Given the function definition:\n",
689 "\n",
690 "```python\n",
691 "def func(foo, bar=None, **kwargs):\n",
692 " pass\n",
693 "```\n",
694 "\n",
695 "`foo`, `bar` and `kwargs` are **parameters** of `func`. However, when calling func, for example:\n",
696 "\n",
697 "```python\n",
698 "func(42, bar=314, extra=somevar)\n",
699 "```\n",
700 "\n",
701 "the values `42`, `314`, and `somevar` are arguments."
468 ] 702 ]
469 }, 703 },
470 { 704 {
471 "cell_type": "code", 705 "cell_type": "code",
472 "execution_count": 99, 706 "execution_count": 54,
473 "id": "bf95f44a-1257-440f-b35f-a8536c8c4363", 707 "id": "bf95f44a-1257-440f-b35f-a8536c8c4363",
474 "metadata": {}, 708 "metadata": {},
475 "outputs": [ 709 "outputs": [
@@ -479,7 +713,7 @@
479 "7" 713 "7"
480 ] 714 ]
481 }, 715 },
482 "execution_count": 99, 716 "execution_count": 54,
483 "metadata": {}, 717 "metadata": {},
484 "output_type": "execute_result" 718 "output_type": "execute_result"
485 }, 719 },
@@ -496,7 +730,7 @@
496 "[9, -2]" 730 "[9, -2]"
497 ] 731 ]
498 }, 732 },
499 "execution_count": 99, 733 "execution_count": 54,
500 "metadata": {}, 734 "metadata": {},
501 "output_type": "execute_result" 735 "output_type": "execute_result"
502 }, 736 },
@@ -511,36 +745,47 @@
511 "source": [ 745 "source": [
512 "# Functions (example1)\n", 746 "# Functions (example1)\n",
513 "\n", 747 "\n",
748 "# case1: assuming that the arguments are of ummutable type (f.i. int):\n",
514 "def add(a, b): # - function definition / header\n", 749 "def add(a, b): # - function definition / header\n",
515 " \"\"\"Function for adding integers\"\"\" # - docstring\n", 750 " \"\"\"Function for adding two integers\"\"\" # - docstring\n",
751 " # the function body will not be evaluated (executed) before the function is called\n",
516 " result = a + b\n", 752 " result = a + b\n",
517 " a = 5 # will not change the corresponding parameter since it is immutable\n", 753 " a = 5 # will not change the corresponding argument since it is immutable\n",
518 " return result # - function that does not contain return, implicitly returns None\n", 754 " return result # - function that does not contain return, implicitly returns None\n",
519 "\n", 755 "\n",
520 "a_param = 9\n", 756 "# defining two integer variables to be used as arguments when calling the function `add`\n",
521 "b_param = -2\n", 757 "a_var = 9\n",
522 "add(a_param, b_param) # Out: 7\n", 758 "b_var = -2\n",
759 "\n",
760 "add(a_var, b_var) # Out: 7\n",
523 "\n", 761 "\n",
524 "# integers are immutable and a_param will remain unchanged\n", 762 "# even though a_var and a point at the same data (they are references: a = a_var),\n",
525 "print(a_param) # Out: 9\n", 763 "# integers are immutable and a_var will remain unchanged\n",
764 "print(a_var) # Out: 9\n",
526 "\n", 765 "\n",
527 "\n", 766 "\n",
767 "# case2: assuming that the arguments are of mutable type (f.i. list)\n",
528 "def addl(a, b):\n", 768 "def addl(a, b):\n",
529 " \"\"\"Function for adding two lists\"\"\"\n", 769 " \"\"\"Function for adding two lists\"\"\"\n",
530 " result = a + b\n", 770 " # assuming that a and b are lists\n",
531 " a += [5] # in this case equal to: a.append(5)\n", 771 " result = a + b # produces a new list that contains the elements of `a` followed by the elements of `b`\n",
772 " a.append(5) # appending a new int element - 5 to the list `a`\n",
532 " return result\n", 773 " return result\n",
533 "\n", 774 "\n",
534 "a_param = [9]\n", 775 "# defining two lists with one element each to be used as arguments when calling `addl`\n",
535 "b_param = [-2]\n", 776 "a_var = [9]\n",
536 "addl(a_param, b_param) # Out: [9, -2]\n", 777 "b_var = [-2]\n",
537 "# lists are mutable and a_param will be changed\n", 778 "\n",
538 "print(a_param) # Out: [9, 5]" 779 "addl(a_var, b_var) # Out: [9, -2]\n",
780 "\n",
781 "# since a (inside the function) is a reference of a_var (a = a_var) and\n",
782 "# lists are mutable and `a_var` will be changed inside the function\n",
783 "print(a_var) # Out: [9, 5]"
539 ] 784 ]
540 }, 785 },
541 { 786 {
542 "cell_type": "code", 787 "cell_type": "code",
543 "execution_count": 100, 788 "execution_count": 55,
544 "id": "ecd03ee2-3523-40bd-afd1-4263a777bae0", 789 "id": "ecd03ee2-3523-40bd-afd1-4263a777bae0",
545 "metadata": {}, 790 "metadata": {},
546 "outputs": [], 791 "outputs": [],
@@ -551,8 +796,15 @@
551 " \"\"\"Function for adding integers\"\"\"\n", 796 " \"\"\"Function for adding integers\"\"\"\n",
552 " return a + b\n", 797 " return a + b\n",
553 "\n", 798 "\n",
554 "my_result = add(2, 5) # positional arguments (parameters)\n", 799 "# positional arguments:\n",
555 "my_result = add(b=5, a=2) # keyword arguments (parameters)\n", 800 "# the order by which the arguments are sent to the function decides\n",
801 "# which argument is assigned to which parameter\n",
802 "my_result = add(2, 5)\n",
803 "\n",
804 "# keyword arguments:\n",
805 "# which argument is assigned to which parameter is decided by\n",
806 "# referrig directly to the argument names - keyword arguments (kwargs)\n",
807 "my_result = add(b=5, a=2)\n",
556 "\n", 808 "\n",
557 "my_tuple = (2, 5)\n", 809 "my_tuple = (2, 5)\n",
558 "my_dict = {'b': 5, 'a': 2}\n", 810 "my_dict = {'b': 5, 'a': 2}\n",
@@ -560,12 +812,15 @@
560 "my_result = add(*my_tuple) # unpacked and assigned to the positional arguments\n", 812 "my_result = add(*my_tuple) # unpacked and assigned to the positional arguments\n",
561 "my_result = add(**my_dict) # unpacked and assigned to the kw. arguments\n", 813 "my_result = add(**my_dict) # unpacked and assigned to the kw. arguments\n",
562 "\n", 814 "\n",
815 "# defining the function `add`with defaukt value for argument `b`\n",
563 "def add(a, b=5):\n", 816 "def add(a, b=5):\n",
564 " \"\"\"Function for adding integers\"\"\"\n", 817 " \"\"\"Function for adding integers\"\"\"\n",
565 " return a + b\n", 818 " return a + b\n",
566 "my_result = add(2)\n", 819 "my_result = add(2) # the default value for `b` is used unless a parameter is sent / used\n",
567 "# ... and the rest of the examples above will work\n",
568 "\n", 820 "\n",
821 "# assigning a varying amount of arguments to parameters\n",
822 "# # args - tuple containing all positional arguments (with the exception of `a`)\n",
823 "# kwargs - a {keyword: value} dict containing all keyword arguments\n",
569 "def add(a, *args, **kwargs):\n", 824 "def add(a, *args, **kwargs):\n",
570 " \"\"\"Function for adding integers\"\"\"\n", 825 " \"\"\"Function for adding integers\"\"\"\n",
571 " if args:\n", 826 " if args:\n",
@@ -575,12 +830,58 @@
575 " return a + b\n", 830 " return a + b\n",
576 "\n", 831 "\n",
577 "my_result = add(2, 5, 9, 11) # 5 assigned to args[0]\n", 832 "my_result = add(2, 5, 9, 11) # 5 assigned to args[0]\n",
578 "my_result = add(2, b=5, c=9, d=11) # 5 assigned to kwargs['b']\n", 833 "my_result = add(2, 6, 5, b=5, c=9, d=11) # 5 assigned to kwargs['b']\n",
579 "\n", 834 "\n",
580 "# my_result = add(2, b=5, 9, 11) # SyntaxError: positional argument follows keyword argument" 835 "# my_result = add(2, b=5, 9, 11) # SyntaxError: positional argument follows keyword argument"
581 ] 836 ]
582 }, 837 },
583 { 838 {
839 "cell_type": "code",
840 "execution_count": 56,
841 "id": "c67ca162-e8eb-4b4d-8c3c-246b000c5c13",
842 "metadata": {},
843 "outputs": [
844 {
845 "name": "stdout",
846 "output_type": "stream",
847 "text": [
848 "10 20 {'a': 1, 'b': 2, 'c': 3}\n"
849 ]
850 }
851 ],
852 "source": [
853 "# Positional only parameters:\n",
854 "# def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):\n",
855 "# ----------- ---------- ----------\n",
856 "# | | |\n",
857 "# | Positional or keyword |\n",
858 "# | - Keyword only\n",
859 "# -- Positional only\n",
860 "\n",
861 "# Positional-only parameters give more control to library authors to better\n",
862 "# express the intended usage of an API and allows the API to evolve in a safe, backward-compatible way.\n",
863 "# Additionally, it makes the Python language more consistent with existing documentation and\n",
864 "# the behavior of various “builtin” and standard library functions.\n",
865 "\n",
866 "# One use case for this notation is that it allows pure Python functions to fully emulate behaviors of existing C coded functions.\n",
867 "# For example, the built-in divmod() function does not accept keyword arguments:\n",
868 "def divmod(a, b, /):\n",
869 " \"\"\"Emulate the built in divmod() function\"\"\"\n",
870 " return (a // b, a % b)\n",
871 "\n",
872 "# Another use case is to preclude keyword arguments when the parameter name is not helpful.\n",
873 "# For example, the builtin len() function has the signature len(obj, /).\n",
874 "# This precludes awkward calls such as: len(obj='hello'), where the \"obj\" keyword argument impairs readability.\n",
875 "\n",
876 "# A further benefit of marking a parameter as positional-only is that it allows the parameter name to be changed in the future without risk of breaking client code.\n",
877 "\n",
878 "def my_func(a, b, /, **kwargs):\n",
879 " print(a, b, kwargs)\n",
880 "\n",
881 "my_func(10, 20, a=1, b=2, c=3)"
882 ]
883 },
884 {
584 "cell_type": "markdown", 885 "cell_type": "markdown",
585 "id": "26a4f2fe-b79e-4e25-9107-230a53d11373", 886 "id": "26a4f2fe-b79e-4e25-9107-230a53d11373",
586 "metadata": {}, 887 "metadata": {},
@@ -654,11 +955,15 @@
654 }, 955 },
655 { 956 {
656 "cell_type": "code", 957 "cell_type": "code",
657 "execution_count": 101, 958 "execution_count": 57,
658 "id": "edf9cfa7-d76c-428b-a39f-8c0697789031", 959 "id": "edf9cfa7-d76c-428b-a39f-8c0697789031",
659 "metadata": {}, 960 "metadata": {},
660 "outputs": [], 961 "outputs": [],
661 "source": [ 962 "source": [
963 "# example: function as a parameter / argument\n",
964 "# the built-in function map: map(function, iterable, *iterables)\n",
965 "\n",
966 "\n",
662 "def fetch_the_first_letter(input_str: str) -> str:\n", 967 "def fetch_the_first_letter(input_str: str) -> str:\n",
663 " \"\"\"Fetches the first letter of the string input_str or 'x'\"\"\"\n", 968 " \"\"\"Fetches the first letter of the string input_str or 'x'\"\"\"\n",
664 " try:\n", 969 " try:\n",
@@ -672,8 +977,8 @@
672 "letter_list = list(map(lambda x: x[0], ['foo', 'bar', 'test'])) # Out: ['f', 'b', 't']\n", 977 "letter_list = list(map(lambda x: x[0], ['foo', 'bar', 'test'])) # Out: ['f', 'b', 't']\n",
673 "\n", 978 "\n",
674 "\n", 979 "\n",
980 "# example: function returning multiple values\n",
675 "# A function can return multiple values by implicitly returning a tuple:\n", 981 "# A function can return multiple values by implicitly returning a tuple:\n",
676 "\n",
677 "def square_cube(x):\n", 982 "def square_cube(x):\n",
678 " \"\"\"returns x, x^2 and x^3\"\"\"\n", 983 " \"\"\"returns x, x^2 and x^3\"\"\"\n",
679 " return x, x**2, x**3\n", 984 " return x, x**2, x**3\n",
@@ -700,7 +1005,7 @@
700 }, 1005 },
701 { 1006 {
702 "cell_type": "code", 1007 "cell_type": "code",
703 "execution_count": 102, 1008 "execution_count": 58,
704 "id": "ea583c17-c938-495a-9586-2027c66328a2", 1009 "id": "ea583c17-c938-495a-9586-2027c66328a2",
705 "metadata": {}, 1010 "metadata": {},
706 "outputs": [ 1011 "outputs": [
@@ -715,9 +1020,17 @@
715 ], 1020 ],
716 "source": [ 1021 "source": [
717 "# enclosing functions\n", 1022 "# enclosing functions\n",
1023 "# used when:\n",
1024 "# - we want to dynamically generate a function\n",
1025 "# - we want to hide implementation details (encapsulation)\n",
1026 "\n",
1027 "# when we want to dynamically generate a function:\n",
1028 "# the function will behave differently depending on what parameters were\n",
1029 "# used when calling its enclosing function (factory function)\n",
718 "\n", 1030 "\n",
719 "def get_multiplier_of(base: int) -> str:\n", 1031 "def get_multiplier_of(base: int) -> str:\n",
720 " \"\"\"the function enclosing its nested functions\"\"\"\n", 1032 " \"\"\"the function enclosing its nested functions\"\"\"\n",
1033 " # this function is the enclosing function of the function `multiplier_function`\n",
721 "\n", 1034 "\n",
722 " def multiplier_function(x):\n", 1035 " def multiplier_function(x):\n",
723 " \"\"\"a nested function\"\"\"\n", 1036 " \"\"\"a nested function\"\"\"\n",
@@ -751,7 +1064,7 @@
751 }, 1064 },
752 { 1065 {
753 "cell_type": "code", 1066 "cell_type": "code",
754 "execution_count": 103, 1067 "execution_count": 59,
755 "id": "49d7f6e1-1f54-4b96-8203-5eae95f47ebe", 1068 "id": "49d7f6e1-1f54-4b96-8203-5eae95f47ebe",
756 "metadata": {}, 1069 "metadata": {},
757 "outputs": [ 1070 "outputs": [
@@ -761,36 +1074,49 @@
761 "text": [ 1074 "text": [
762 "7 8\n", 1075 "7 8\n",
763 "100\n", 1076 "100\n",
764 "{'num3': 100, 'id': 200}\n", 1077 "{'id': 200, 'num3': 100, 'num5': 23}\n",
765 "{}\n", 1078 "{'num3': 100, 'num5': 23}\n",
766 "{}\n", 1079 "100\n",
1080 "{'num3': 100, 'num5': 25}\n",
1081 "100\n",
1082 "25\n",
767 "99\n" 1083 "99\n"
768 ] 1084 ]
769 } 1085 }
770 ], 1086 ],
771 "source": [ 1087 "source": [
772 "num1, num2 = 7, 8 # module globals\n", 1088 "# module globals\n",
1089 "num1 = 7\n",
1090 "num2 = 8\n",
773 "\n", 1091 "\n",
774 "def print_numbers():\n", 1092 "def print_numbers():\n",
775 " print(num1, num2) # OK, these are module globals\n", 1093 " print(num1, num2) # module globals. Out: 7 8\n",
776 " num3 = 100\n", 1094 " num3 = 100\n",
777 " print(num3) # prints 100, num3 is in the function (local) scope\n", 1095 " print(num3) # prints 100, num3 is in the function (local) scope\n",
778 " global num4 # assignes / references num4 to / in the global scope\n", 1096 " global num4 # assignes / references num4 to / in the global scope\n",
779 " num4 = 99\n", 1097 " num4 = 99\n",
780 " id = 200 # new symbol in local scope\n", 1098 " id = 200 # new symbol in local scope\n",
781 " # id(num4) # will not yield the expected result (raises TypeError)\n", 1099 " # id(num4) # will not yield the expected result (raises TypeError)\n",
1100 " num5 = 23\n",
1101 " \n",
1102 " # locals() updates and then returns a dictionary representing the current local symbol table\n",
782 " print(locals())\n", 1103 " print(locals())\n",
783 "\n", 1104 "\n",
784 " def print_numbers2():\n", 1105 " def print_numbers2():\n",
785 " print(locals())\n", 1106 " print(locals()) # N.B. Updates and then displays the local symbol table (num3 will be included)\n",
786 " # print(num3) # OK, enclosed scope\n", 1107 " print(num3) # OK, enclosed scope\n",
1108 " # num3 = 9 # UnboundLocalError: local variable 'num3' referenced before assignment\n",
1109 " nonlocal num5 # assignes / references num5 to / in enclosing scope. N.B. num5 must exist in `print_numbers`\n",
1110 " num5 = 25\n",
787 " print(locals())\n", 1111 " print(locals())\n",
788 "\n", 1112 "\n",
789 " print_numbers2() # prints 100\n", 1113 " print_numbers2() # Out: 100\n",
1114 " print(num3)\n",
1115 " print(num5) # Out: 25\n",
790 "\n", 1116 "\n",
791 "print_numbers()\n", 1117 "print_numbers()\n",
792 "# print(num3) # Raises NameError - why?\n", 1118 "# print(num3) # Raises NameError - why?\n",
793 "print(num4) # Prints 99 - why?\n", 1119 "print(num4) # Out: 99\n",
794 "# print_numbers2() # Raises NameError" 1120 "# print_numbers2() # Raises NameError"
795 ] 1121 ]
796 }, 1122 },
@@ -807,12 +1133,18 @@
807 "def my_decorator(func):\n", 1133 "def my_decorator(func):\n",
808 "\n", 1134 "\n",
809 " def decorated():\n", 1135 " def decorated():\n",
1136 " # we place the logic we want to take place before the decorated function's logic here\n",
810 " print('Doing something before the decorated function')\n", 1137 " print('Doing something before the decorated function')\n",
811 " retval = func()\n", 1138 " retval = func() # calling the decorated function and (optionally) taking care of its return value\n",
1139 " # we place the logic we want to take place after the decorated function's logic here\n",
812 " print('Doing something after the decorated function')\n", 1140 " print('Doing something after the decorated function')\n",
813 " return retval\n", 1141 " return retval # returning the return value of the original (decorated) function\n",
814 " return decorated\n", 1142 " return decorated\n",
1143 "```\n",
815 "\n", 1144 "\n",
1145 "once having a decorator:\n",
1146 "\n",
1147 "```python\n",
816 "def my_function():\n", 1148 "def my_function():\n",
817 " print('Alice')\n", 1149 " print('Alice')\n",
818 "\n", 1150 "\n",
@@ -835,7 +1167,7 @@
835 }, 1167 },
836 { 1168 {
837 "cell_type": "code", 1169 "cell_type": "code",
838 "execution_count": 104, 1170 "execution_count": 60,
839 "id": "4346260d-76af-437e-9c10-1c1d0c478695", 1171 "id": "4346260d-76af-437e-9c10-1c1d0c478695",
840 "metadata": {}, 1172 "metadata": {},
841 "outputs": [], 1173 "outputs": [],
@@ -864,6 +1196,7 @@
864 "\n", 1196 "\n",
865 "\n", 1197 "\n",
866 "@requires_access(access_secret='b28cfeaa65b73cf')\n", 1198 "@requires_access(access_secret='b28cfeaa65b73cf')\n",
1199 "@is_admin\n",
867 "def sensitive_function(data, **kwargs):\n", 1200 "def sensitive_function(data, **kwargs):\n",
868 " \"\"\"very sensitive function\"\"\"\n", 1201 " \"\"\"very sensitive function\"\"\"\n",
869 " db.save(data)" 1202 " db.save(data)"