From 1227388ebe2ea6e63522f082b71dbf8e40a6935e Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 16 Jan 2023 21:27:40 +0800 Subject: [PATCH 001/150] Delete .DS_Store --- .DS_Store | Bin 8196 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 .DS_Store diff --git a/.DS_Store b/.DS_Store deleted file mode 100644 index 95b6c3cdb505d4398d5555bc76ed7128b38a2c1e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8196 zcmeHM%Wl&^6ur|1aDosKLNrTnkXTeGuNJyMN<)fN1X4v1UGPZlI7%$po+x&RiV4b! z9eW--K7a)qJ^&WL5AY-G;m(89d026~017kJ+%xga@o0`u#<^1fAl1HA0LTG=hLvIV zG=@2a^|LxtmgJQShy?inZScT_7RF#^w7Q@aPzopolmbctrNG~y0KT(X(PG~FqE|(w zfKuSURDkUdI#z}ii6eo0>%hQM0K^nt<^|iB2XKxqu_AFKkW=xVB6}c`N@R*b1ReWz zHXN}caU@XCfe1PfIWv(N3gNROPv^sdR0OK16i^DxD!_903~Yjre|9u~-*#xzbf}5_ z>??H>Yw-s!*oxtp1HUUdU(Bv!`$0bcjVvvvPMkcYX&EhZCiAe~p@Vv01bx41^zO4y zJ4VnkW&19r&bV!u_w3f7kv)H%dVyhktsW=aRttwb*tI>24yv^8Sw6o{U36$#T1z*w zxiBo{*H`s&ac#J&hgVA**eYVs9FMIUt*cA)?b*nxdK*69Gn%)IA|d!>Zb3P%I_Wp+)W912hKVSZ;s0r z&Nbz@bLgKUI_3uS(K$`@kS#rQ3q9n52^JWW9wO7*O`>~5eDqIkKZzDU$4rTMQA53b z@#cdxR6_27sSeAXW2{7TPMM2;4OKXj0?UGxWBLCU?pNv@;7Bqml2YJUD?n1Udaa5} z`1KojdNnN9*0JtkWrd9!3FH(EJRL{m={Vx}ABNc0aVXiy5{q(VXkegZsw6`BA5 From 1b0b58588026b8d32f619698e506dc7bf75629f9 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 16 Jan 2023 21:52:28 +0800 Subject: [PATCH 002/150] Create daily_knowledge.md --- daily_knowledge.md | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 daily_knowledge.md diff --git a/daily_knowledge.md b/daily_knowledge.md new file mode 100644 index 0000000..8c0aad9 --- /dev/null +++ b/daily_knowledge.md @@ -0,0 +1,25 @@ +# 2023 +## Day 1 +### VS Code +#### VS Code Shortcuts +- `CMD + Shift + P`: Command Palette +- `CMD + P`: Quickly open files +#### Code Formatter +- The main coding standard for Python is PEP8 (Python Enhancement Proposal 8) + - **Linters** such as `flake8` and `pylint` highlight places where your code doesn’t conform with PEP8. + - **Automatic formatters** such as `black` that will update your code automatically to conform with coding standards. +- How to install `flack8`: + - Step 1: Install `black` in virtual environment: `pip install flake8` + - Step 2: Open the Command Palette (`CMD + Shift + P`) → Search the “Python: Select Linter” and press enter. Select the “flake8” +- How to install `black`: + - Step 1: Install `black` in virtual environment: `pip install black` + - Step 2: Open the Command Palette (`CMD + Shift + P`) → “Preferences → Settings” + - Search “format on save” and check the checkbox + - Search “python formatting provider” and select the `black`. +- How to install `isort`: + - Open the Command Palette (`CMD + Shift + P`). Search the “Preferences: Configure Language Specific Settings” and press enter. And search the “Python” and press enter. It will open the “settings.json”. + ```json + "editor.codeActionsOnSave": { + "source.organizeImports": true + } + ``` From 67719c014b56f44b4a54daf5a513e8085cd983cd Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 29 Jan 2023 21:30:38 +0800 Subject: [PATCH 003/150] Update daily_knowledge.md --- daily_knowledge.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 8c0aad9..04064ec 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,4 +1,11 @@ # 2023 +## Day 2 +### Matplotlib +- Set params: +```Python +plt.rcParams.update({'font.size': 14}) +``` + ## Day 1 ### VS Code #### VS Code Shortcuts From 30d5938cdc1908f115b1587d1dd39726c6ec2097 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 3 Feb 2023 00:57:00 +0800 Subject: [PATCH 004/150] Update daily_knowledge.md --- daily_knowledge.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 04064ec..36d2ab6 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,11 +1,15 @@ # 2023 ## Day 2 +### Git +#### Edit Git Commits +- ### Matplotlib - Set params: ```Python plt.rcParams.update({'font.size': 14}) ``` - +### Python General +- `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. ## Day 1 ### VS Code #### VS Code Shortcuts From 413cd36748ceb3294dfc61c458e442fd3ce3f245 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Sat, 11 Feb 2023 00:44:41 +0800 Subject: [PATCH 005/150] update the dataclass & decorators --- .gitignore | 69 + Assignment/.DS_Store | Bin 6148 -> 0 bytes Assignment/A1/.DS_Store | Bin 6148 -> 0 bytes .../assignment1-checkpoint.ipynb | 454 --- Assignment/A1/Q1.31.in | 4 - Assignment/A1/Q1.32.in | 3 - Assignment/A1/Q1.33.in | 2 - Assignment/A1/Q1.34.in | 6 - Assignment/A1/assignment1.ipynb | 454 --- Assignment/A1/assignment1_Sep9.pdf | Bin 233554 -> 0 bytes README.md | 6 +- W1_Python_Basics/.DS_Store | Bin 6148 -> 0 bytes W1_Python_Basics/class_exercise_1.ipynb | 2637 ----------------- .../class_exercise_1_submit.ipynb | 788 ----- W1_Python_Basics/tutorial_1.ipynb | 725 ----- W1_Python_Basics/tutorial_1_answer.pdf | Bin 130604 -> 0 bytes W2_Function_Lambda/.DS_Store | Bin 6148 -> 0 bytes .../class_exercise_2-checkpoint.ipynb | 1518 ---------- .../class_exercise_2_submit-checkpoint.ipynb | 244 -- W2_Function_Lambda/class_exercise_2.ipynb | 1545 ---------- .../class_exercise_2_submit.ipynb | 244 -- W2_Function_Lambda/tutorial_2.ipynb | 730 ----- advanced/README.md | 24 + advanced/dataclass.py | 50 + advanced/decorators_tutorial.py | 86 + advanced/logging_tutorial.py | 29 + basics/.gitkeep | 0 27 files changed, 261 insertions(+), 9357 deletions(-) create mode 100644 .gitignore delete mode 100644 Assignment/.DS_Store delete mode 100644 Assignment/A1/.DS_Store delete mode 100644 Assignment/A1/.ipynb_checkpoints/assignment1-checkpoint.ipynb delete mode 100644 Assignment/A1/Q1.31.in delete mode 100644 Assignment/A1/Q1.32.in delete mode 100644 Assignment/A1/Q1.33.in delete mode 100644 Assignment/A1/Q1.34.in delete mode 100644 Assignment/A1/assignment1.ipynb delete mode 100644 Assignment/A1/assignment1_Sep9.pdf delete mode 100644 W1_Python_Basics/.DS_Store delete mode 100644 W1_Python_Basics/class_exercise_1.ipynb delete mode 100644 W1_Python_Basics/class_exercise_1_submit.ipynb delete mode 100644 W1_Python_Basics/tutorial_1.ipynb delete mode 100644 W1_Python_Basics/tutorial_1_answer.pdf delete mode 100644 W2_Function_Lambda/.DS_Store delete mode 100644 W2_Function_Lambda/.ipynb_checkpoints/class_exercise_2-checkpoint.ipynb delete mode 100644 W2_Function_Lambda/.ipynb_checkpoints/class_exercise_2_submit-checkpoint.ipynb delete mode 100644 W2_Function_Lambda/class_exercise_2.ipynb delete mode 100644 W2_Function_Lambda/class_exercise_2_submit.ipynb delete mode 100644 W2_Function_Lambda/tutorial_2.ipynb create mode 100644 advanced/README.md create mode 100644 advanced/dataclass.py create mode 100644 advanced/decorators_tutorial.py create mode 100644 advanced/logging_tutorial.py create mode 100644 basics/.gitkeep diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..afc9998 --- /dev/null +++ b/.gitignore @@ -0,0 +1,69 @@ +# These are some examples of commonly ignored file patterns. +# You should customize this list as applicable to your project. +# Learn more about .gitignore: +# https://www.atlassian.com/git/tutorials/saving-changes/gitignore + +# Project specifics +sandbox.py +sandbox/ + + + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class +# Virtualenv +venv/ +.vscode/ +# Project specific +*.egg-info.egg-info/ +*.egg-info + +# Sanbox file +sandbox/ + +# Node artifact files +node_modules/ +dist/ + +# Compiled Java class files +*.class + +# Compiled Python bytecode +*.py[cod] + +# Log files +*.log + +# Package files +*.jar + +# Maven +target/ +dist/ + +# JetBrains IDE +.idea/ + +# Unit test reports +TEST*.xml + +# Generated by MacOS +.DS_Store + +# Generated by Windows +Thumbs.db + +# Applications +*.app +*.exe +*.war + +# Large media files +*.mp4 +*.tiff +*.avi +*.flv +*.mov +*.wmv diff --git a/Assignment/.DS_Store b/Assignment/.DS_Store deleted file mode 100644 index 3023cf2708f31261b0f4b64b89abd93b6b3bc6d8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKy-or_5Z(pU1*1}!NO_GN1&9(YOb*1t&g6_1YT(Wza>;Q^;E*VuxhJr*(ATl@ z349t8XMaEl*cxJHlHG51e)i`(vda)cXtnPa3CR*d7&L*2G<0)B_(hwMgtjaLQZa|) za|iSfr{jAw(P&si2E?~ZkP0a}gI;Iy`}M*?;gcqksiox=#xg9kmbtcCd|-uk*zZ;C z?xh%=+F{Gl`Wff`Sht;XuQ{k^H;;G_+FsD?%4E-NLdeyH7r1;-<^90z$$2d0U@Xnj z^=xi9EEURmV|QmS${WM|(gEnDaulW6)^_pmq|v^A7(PZ%uZmF$KRziN8b|O3iaeZu zTeNO?yEAf(>}_7F=|i*iujiMj`(F9+xxe~4t@-oaS>3?r!7a=&+SA06s3HT%05Y&B z4CpJ0tuD%ja39D3GO#cVi2K2SCeYLvE0k9Ubg~2hOo3Sn=%SVoIfh14W2_K7AXKFS zs#K~=464$>Zs<5uW2{i66RL|3s#m7ELZNbXnBS1$gqjMmM+T6AX$F#Nm=*8;@$dEj zbP|q`0c7A`F+fu_t5$_0>9=*}aN?~spf#Wg5pl7?aSAB%DTY|_6z8Bx0lOg-KvQF^ S5G)}0M?lhm9WwBz415DV?qr1k diff --git a/Assignment/A1/.DS_Store b/Assignment/A1/.DS_Store deleted file mode 100644 index 5008ddfcf53c02e82d7eee2e57c38e5672ef89f6..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 max_chair:\n", - " max_chair = total_chair\n", - " #pos_m, pos_n = m,n\n", - " return max_chair" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "1eaa9db3", - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "96\n", - "128\n" - ] - } - ], - "source": [ - "import math\n", - "\n", - "fin = open('Q1.32.in')\n", - "num_case = int(fin.readline())\n", - "for i in range(num_case):\n", - " p, q = [int(s) for s in fin.readline().split()]\n", - " print(max(max_chair(p,q), max_chair(q,p)))" - ] - }, - { - "cell_type": "markdown", - "id": "7edc77b5", - "metadata": {}, - "source": [ - "### Question 1.33" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "fbe6b41e", - "metadata": {}, - "outputs": [], - "source": [ - "# %load Q1.33.in\n", - "# 4 18 5 0 10 10 60 40 20 30 28 36\n", - "# 20 10 30 50" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "dd179bb1", - "metadata": {}, - "outputs": [], - "source": [ - "fin = open('Q1.33.in')\n", - "\n", - "height = [int(s) for s in fin.readline().split()]\n", - "rainfall = [int(s) for s in fin.readline().split()]" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "27c57485", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[4, 18, 5, 0, 10, 10, 60, 40, 20, 30, 28, 36]" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "height" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "id": "0b6498ca", - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# function to add value labels\n", - "def addlabels(x,y):\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "id": "9913b732", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "x = [i for i in range(len(height))]\n", - "new_height = [4, 18, 5, 5, 10, 10, 60, 40, 20, 30, 30, 36]\n", - "# 2. Setup plot\n", - "fig, ax = plt.subplots(figsize=(6,8)) #Figure size = Width & Height of the Plot\n", - "\n", - "# 3. Plot data\n", - "ax.bar(x, new_height, width=1.0, color=\"blue\")\n", - "ax.bar(x, height, width=1.0, color=\"black\")\n", - "\n", - "for i in range(len(x)):\n", - " ax.text(i, height[i]-3, height[i], ha = 'center', c=\"white\", size=\"large\")\n", - "\n", - "\n", - "ax.set_xlim(-0.5,len(height)-0.5)\n", - "ax.set_ylim(0, 70);" - ] - }, - { - "cell_type": "markdown", - "id": "bdfdd782", - "metadata": {}, - "source": [ - "### Question 1.34" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "18a44639", - "metadata": {}, - "outputs": [], - "source": [ - "# %load Q1.34.in\n", - "# conjugate continuous\n", - "# convergence\n", - "# convex conjunction\n", - "# congruent concrete\n", - "# conjecture concave\n", - "# consecutive constant concentric" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "eff7b97f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['conjugate', 'continuous', 'convergence', 'convex', 'conjunction', 'congruent', 'concrete', 'conjecture', 'concave', 'consecutive', 'constant', 'concentric']\n" - ] - } - ], - "source": [ - "fin = open('Q1.34.in')\n", - "words = [word for word in fin.read().split()]\n", - "print(words)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "29de5070", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "convex\n", - "concave\n", - "concrete\n", - "constant\n", - "congruent\n", - "conjugate\n", - "concentric\n", - "conjecture\n", - "continuous\n", - "conjunction\n", - "consecutive\n", - "convergence\n" - ] - } - ], - "source": [ - "words.sort()\n", - "words = sorted(words, key=lambda x: len(x))\n", - "\n", - "for word in words:\n", - " print(word)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bd9c4a39", - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/Assignment/A1/Q1.31.in b/Assignment/A1/Q1.31.in deleted file mode 100644 index 55a6269..0000000 --- a/Assignment/A1/Q1.31.in +++ /dev/null @@ -1,4 +0,0 @@ -3 -21/02/2021 21/02/2021 -01/03/2021 20/04/2021 -10/12/2021 07/01/2022 diff --git a/Assignment/A1/Q1.32.in b/Assignment/A1/Q1.32.in deleted file mode 100644 index cdeebf4..0000000 --- a/Assignment/A1/Q1.32.in +++ /dev/null @@ -1,3 +0,0 @@ -2 -8 9 -10 10 diff --git a/Assignment/A1/Q1.33.in b/Assignment/A1/Q1.33.in deleted file mode 100644 index 29b0587..0000000 --- a/Assignment/A1/Q1.33.in +++ /dev/null @@ -1,2 +0,0 @@ -4 18 5 0 10 10 60 40 20 30 28 36 -20 10 30 50 diff --git a/Assignment/A1/Q1.34.in b/Assignment/A1/Q1.34.in deleted file mode 100644 index c4a0332..0000000 --- a/Assignment/A1/Q1.34.in +++ /dev/null @@ -1,6 +0,0 @@ -conjugate continuous -convergence -convex conjunction -congruent concrete -conjecture concave -consecutive constant concentric diff --git a/Assignment/A1/assignment1.ipynb b/Assignment/A1/assignment1.ipynb deleted file mode 100644 index 5a1a9ad..0000000 --- a/Assignment/A1/assignment1.ipynb +++ /dev/null @@ -1,454 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "17e335f5", - "metadata": {}, - "source": [ - "### Question 1.31" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "b3cefb27", - "metadata": {}, - "outputs": [], - "source": [ - "# %load Q1.31.in\n", - "# 3\n", - "# 21/02/2021 21/02/2021\n", - "# 01/03/2021 20/04/2021\n", - "# 10/12/2021 07/01/2022" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "a98db412", - "metadata": {}, - "outputs": [], - "source": [ - "def validate_hour(day):\n", - " if int(day[::-1]) < 24:\n", - " return True\n", - " else:\n", - " return False" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "34a9b35a", - "metadata": {}, - "outputs": [], - "source": [ - "def days_in_month(y, m):\n", - " y, m = int(y), int(m)\n", - " leap = 0\n", - " if y % 400 == 0:\n", - " leap = 1\n", - " elif y % 100 == 0:\n", - " leap = 0\n", - " elif y % 4 == 0:\n", - " leap = 1\n", - " if m==2:\n", - " return 28 + leap\n", - " list = [1,3,5,7,8,10,12]\n", - " if m in list:\n", - " return 31\n", - " return 30" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "77010103", - "metadata": {}, - "outputs": [], - "source": [ - "def months(start_month, start_year, end_month, end_year):\n", - " excluded_months = [6,7,8,9]\n", - " if int(start_year) == int(end_year):\n", - " month_list = [month for month in range(int(start_month), int(end_month)+1)]\n", - " else:\n", - " month_list = [month for month in range(int(start_month), 12+1)] + [month for month in range(1,int(end_month)+1)]\n", - "\n", - " #excluding the month 06, 07,08,09 as reversing them 60,70,80,90 over minutes as for min: up to 59th min only\n", - " month_list = [f\"{month:02d}\" for month in month_list if month not in excluded_months]\n", - " #print(month_list)\n", - " return month_list\n", - "\n", - "#months(\"12\", \"2021\", \"01\", \"2022\")\n", - "#months(\"03\", \"2021\", \"07\", \"2022\") \n", - "#months(\"02\", \"2021\", \"02\", \"2021\") " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "57e87762", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "02:21:12:20\n", - "-----------\n", - "03:01:10:30\n", - "03:02:20:30\n", - "03:10:01:30\n", - "03:11:11:30\n", - "03:12:21:30\n", - "03:20:02:30\n", - "03:21:12:30\n", - "03:22:22:30\n", - "03:30:03:30\n", - "03:31:13:30\n", - "04:01:10:40\n", - "04:02:20:40\n", - "04:10:01:40\n", - "04:11:11:40\n", - "04:12:21:40\n", - "04:20:02:40\n", - "-----------\n", - "12:10:01:21\n", - "12:11:11:21\n", - "12:12:21:21\n", - "12:20:02:21\n", - "12:21:12:21\n", - "12:22:22:21\n", - "12:30:03:21\n", - "12:31:13:21\n", - "01:01:10:10\n", - "01:02:20:10\n" - ] - } - ], - "source": [ - "fin = open('Q1.31.in')\n", - "num_case = int(fin.readline())\n", - "day, month, year = 0,1,2\n", - "for i in range(num_case):\n", - " if i:\n", - " print('-' * 11)\n", - " start, end = fin.readline().split()\n", - " start, end = start.split(\"/\"), end.split(\"/\")\n", - " #identify possible months lists \n", - " month_list = months(start[month], start[year], end[month], end[year])\n", - " #for each month, we need to find possible a \"days\" list\n", - " for m in month_list:\n", - " if m == start[month] and m !=end[month]:\n", - " days = [day for day in range(int(start[day]), days_in_month(start[year], m)+1)]\n", - " elif m == start[month] and m ==end[month]:\n", - " days = [day for day in range(int(start[day]), int(start[day])+1)]\n", - " elif m == end[month]:\n", - " days = [day for day in range(1, int(end[day])+1)]\n", - " else:\n", - " days = [day for day in range(1, days_in_month(start[year], m)+1)]\n", - " #print(m, days)\n", - " days = [f\"{d:02d}\" for d in days]\n", - " for d in days:\n", - " if validate_hour(d):\n", - " print(f\"{m}:{d}:{d[::-1]}:{m[::-1]}\")" - ] - }, - { - "cell_type": "markdown", - "id": "09dcec18", - "metadata": {}, - "source": [ - "### Question 1.32" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "c85cd2a5", - "metadata": {}, - "outputs": [], - "source": [ - "# %load Q1.32.in\n", - "# 2\n", - "# 8 9\n", - "# 10 10" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "3f3e6fae", - "metadata": {}, - "outputs": [], - "source": [ - "def max_chair(p,q):\n", - " r = 0.5\n", - " pack_long = p #if chair packing along width or length\n", - " d = q #d: total length of number of row of chairs\n", - "\n", - " rec_chair = int((pack_long+1)/(r*2)) #No. of chair based on Rec\n", - " tri_chair = rec_chair -1 #No. of chair based on Tri \n", - " #print(rec_chair, tri_chair)\n", - " max_chair = float(\"-inf\")\n", - " #pos_m, pos_n = 0,0\n", - " # m*[r*sqrt(3)] + n*(2r) = d, with the constraint: m from 0 to d/(r*sqrt(3)) and n from 0 to d/2r\n", - " for m in range(0, int(math.ceil(d/(math.sqrt(3)*r)))+1):\n", - " for n in range(0, int(math.ceil(d/2*r))+1):\n", - " if (math.ceil(m*r*(math.sqrt(3)) + 2*r*n) == float(d)):\n", - " total_chair = 0\n", - " for i in range(m+1):\n", - " if i%2 == 0:\n", - " total_chair+=rec_chair\n", - " else:\n", - " total_chair+=tri_chair\n", - " total_chair+= n*rec_chair\n", - " if total_chair > max_chair:\n", - " max_chair = total_chair\n", - " #pos_m, pos_n = m,n\n", - " return max_chair" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "1eaa9db3", - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "96\n", - "128\n" - ] - } - ], - "source": [ - "import math\n", - "\n", - "fin = open('Q1.32.in')\n", - "num_case = int(fin.readline())\n", - "for i in range(num_case):\n", - " p, q = [int(s) for s in fin.readline().split()]\n", - " print(max(max_chair(p,q), max_chair(q,p)))" - ] - }, - { - "cell_type": "markdown", - "id": "7edc77b5", - "metadata": {}, - "source": [ - "### Question 1.33" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "fbe6b41e", - "metadata": {}, - "outputs": [], - "source": [ - "# %load Q1.33.in\n", - "# 4 18 5 0 10 10 60 40 20 30 28 36\n", - "# 20 10 30 50" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "id": "dd179bb1", - "metadata": {}, - "outputs": [], - "source": [ - "fin = open('Q1.33.in')\n", - "\n", - "height = [int(s) for s in fin.readline().split()]\n", - "rainfall = [int(s) for s in fin.readline().split()]" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "27c57485", - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[4, 18, 5, 0, 10, 10, 60, 40, 20, 30, 28, 36]" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "height" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "id": "0b6498ca", - "metadata": {}, - "outputs": [], - "source": [ - "%matplotlib inline\n", - "import matplotlib.pyplot as plt\n", - "\n", - "# function to add value labels\n", - "def addlabels(x,y):\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "id": "9913b732", - "metadata": {}, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "
" - ] - }, - "metadata": { - "needs_background": "light" - }, - "output_type": "display_data" - } - ], - "source": [ - "x = [i for i in range(len(height))]\n", - "new_height = [4, 18, 5, 5, 10, 10, 60, 40, 20, 30, 30, 36]\n", - "# 2. Setup plot\n", - "fig, ax = plt.subplots(figsize=(6,8)) #Figure size = Width & Height of the Plot\n", - "\n", - "# 3. Plot data\n", - "ax.bar(x, new_height, width=1.0, color=\"blue\")\n", - "ax.bar(x, height, width=1.0, color=\"black\")\n", - "\n", - "for i in range(len(x)):\n", - " ax.text(i, height[i]-3, height[i], ha = 'center', c=\"white\", size=\"large\")\n", - "\n", - "\n", - "ax.set_xlim(-0.5,len(height)-0.5)\n", - "ax.set_ylim(0, 70);" - ] - }, - { - "cell_type": "markdown", - "id": "bdfdd782", - "metadata": {}, - "source": [ - "### Question 1.34" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "id": "18a44639", - "metadata": {}, - "outputs": [], - "source": [ - "# %load Q1.34.in\n", - "# conjugate continuous\n", - "# convergence\n", - "# convex conjunction\n", - "# congruent concrete\n", - "# conjecture concave\n", - "# consecutive constant concentric" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "id": "eff7b97f", - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['conjugate', 'continuous', 'convergence', 'convex', 'conjunction', 'congruent', 'concrete', 'conjecture', 'concave', 'consecutive', 'constant', 'concentric']\n" - ] - } - ], - "source": [ - "fin = open('Q1.34.in')\n", - "words = [word for word in fin.read().split()]\n", - "print(words)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "id": "29de5070", - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "convex\n", - "concave\n", - "concrete\n", - "constant\n", - "congruent\n", - "conjugate\n", - "concentric\n", - "conjecture\n", - "continuous\n", - "conjunction\n", - "consecutive\n", - "convergence\n" - ] - } - ], - "source": [ - "words.sort()\n", - "words = sorted(words, key=lambda x: len(x))\n", - "\n", - "for word in words:\n", - " print(word)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "bd9c4a39", - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/Assignment/A1/assignment1_Sep9.pdf b/Assignment/A1/assignment1_Sep9.pdf deleted file mode 100644 index 4ee5fd121415482634145e79d9e9584d181c087f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 233554 zcmdSA1yoht+BS@W3W6YAf`oKzx&>*Flz@{5SL@8;c1q4L8OF&XOrAu-X64K4L z_C}va&vVXu-v1xp82|VgFxau?ymQ|3zOFSFm7AG_aSZCS<^6rhrzuBH%0h^d(= z#1w1{2w~;rhJ7O_c<-($*aWT(Ozt0Q!PNnY+Bt)r$hbi=mL`tcWN^u3tUR#6WNdI% z$=KjR$k;jIAF^M6$H4-7r%U#`1lZtzNC2z`baMJ>wvwr%oihZ`5HL!@4(tT`$4UmD z86?3*#(M1>33f784%qx42@Wz=xOl*9aW^MPWhX-?Q(%y!GAj!i@C&;Jc+E-%`~t6m zs}v!2#>%En+8`h-AQe+LCy=x);CGShf1=m_q+yB!el)Q(6tQ#D28ObbaRI`)dD(Qy z0GEKB0F@odu62-v*g4w+GU2g=zX2(OR3L_6M|+rQ#_k|dWssPui>0xtlB5VQuZp3O zBXG%eRIklo@{lCS|R6EiioGcg6pnu5)pEXdedIJse?9GxJh zhPLdxuG$-zia)eZiuvHV($=8VKk=-$!-MYWeF z?zy{1GsR0GUi=%VSjR~#6yrEKG*=f?ALJF78grZe!{>51gda#{|}HbQ&OaCBzm zJY%@nkmO6nRfIFd*0NW1^DJwq;StX$rv2QuP$NPq3)^qpQpU?=Jch{JH$I;UBKlO< zaQC@4(_;T18|xELAH@om4S}praJU<0mV(Or*0-tB1>-+P0u7F3E1L6UhVfQ953u(G zQ;&6@UzDWUL36qBDMl|ujI?!k9!$wr&F7ABzcd}In437L+y3rWOZ+9ruX44&%q@wl zN5(RBXwN>Sn!9k8_*nh+TO?4@>EV8xD^d24m!d zy`bVx2gukuo{ai>J|e>LAtmah^Q{B1{NET0Z0CITq=`=T@lhLri30*$Bh{>Qmnay| zg<~FIK^uj6A1P37DTOBuP?9xeer;>+p-E=!8fx@+P!fYo8=s?3zANvZ^h#PHzg3;| zT5|jw-2}GfgODE+>}BYzMBlPR-rrtRXGx&8_wD7hCY9_=jAHUf%tOa_98r>ePnY#Q9yWU5fj-RnJF?I{O(Mlt| zo|v&G`C&+orM=WACx89=ogIdSauV+`s@T&IVoqU}Ocadc8;4-~zUg==f)KW?=7Uhh zHL9C65-qJVJp>58VjrWG!0u^5)>B$moy~X-s$#f4rteMbK;bo} zrg#mxd1isPZp*0h4;C+n+H5X^QM;0F?cHMOXK{2v2z`!$9gaKfazh}niu%}5`yD3b z8{F}+1a6uaoXf3&9hA$2)lJq7{uRzNa{#{;9NL3l-A!QtUS?U2qL96tXJThF2tYrTBf5w|B@*iwhR9-))6qZVrR_k5%t|BhdF?aeemHQzYYv!i9=ka%pWeMy*?Tr}xt*2K&od^|R#Vd==BPZ}xt5AJ>%c=v2< zy~s+)t$kyPbN9=~nNzK((Gh5f+=a*Fvrjr=nub=0<)VE!A8+s9{r-_=Cfut6Tjqla87I7%$+?4s= zPJJ%e)qVe7Ps)70w=SXcP+d9s1x^A%Vx7_c&1hX0sb|+s= z?zT%!75Rx1QF)f=nCl8~My=GyojPk4=Y!*?vc+Vsz~!--T#K`gss=wK?wsa+nv$`%`!3@GesJ#~se zvI=H%l$C45;NDd;@<(G?q2%xt%RdT3v2`Dz`c71%N3NFr*t1y;@vXA0)t06R#hXk< z(((Am(9Z}jy(pkgcD8+P)(iH{7~Kd6t$5X~s7G0w+ zvi}qQm&CT&%Qp+`YSGyaqsq{;E>esN)VZz%)=!BebISg6<4!b62bEcJ#oyU(d%hZ5 zMx=hSe>3ymh*=%+L$E95%*nQvBwq{4%*1e)#1RMTwAMk3S-%f$^+JZDwSu3DL0{wD zdO^8HP~KCJw;e6Jnf-B~{vkE}!diN}ilbd1Bc?Rh?G+SG#>;$P7JJ;19r^iLX0~(L z2KT@%%P{mjWI+{cn-eB&y6~~DLEkWV321=NkgW>Oy9c=C%vwg$hNic^>iDR~& z-$!!AIh8Ew)*}Ram%gxk4G(mV=DZ!*5rkFc^P#d!-?rs=H^v_ir+il9eTGRb>)TQ? z8$I|!Ot^0PPP5KC?HC(0vk^MVK6Ld`@}0o+52woPiCjS7ec2iEF2&y`bE&PIr~L3s zxPaAzrdOx}NrX+SpsAJ|*3`C3H|kb@utFs9g;1x0R)ag&=MId1EMI{|GF8?A_K7tt z;#I;8tzGeb8^6ehsacn9?Gm<*Y34zr$E5umqcfq)h;fW9j71Bn5yMM`K`m zL$DKUkR#bOs#LL41zW=K2!IFSxbSxb1G@ySg*F)+Y3h>wjWl5&{L=7$(BzlOqS9h8 zu`tcqu0a-Db>L$aJ4tCVIYaxubOnj21E`OM1q6Jl?C$7fY6}C%WN=6d$CEHiAeQz{ zb`UaNKno=ha6JzkUjD8;?D}5{DnLw3A%H(V@k#X5{5;> ziHwJr^=DL^$e7qzxd0BqUdq(c+`@^Bi|(BNX#zk*4i;8`9B{jS!^XwR0T-!$ zeI*CrD2<<^*f?1LSZN50JQ)WYfK5$p)qv6P%SGTAn2D2%2QG_@jfH~?CI*1Qut)#^ z)f9l{Ja9DpyBp#7`w#Q~g6JR-Igq>^#MaOTWDM{We~kJEKl1NJi3S&Fhb(xK z{K_E}fEj@Y0PbxGw*S=%P`3mNgB>mZS`n}r{|+7*D?I5z5|$80Cs7MS2rO8#hCg4k zvax~SUI(}qo}UcG-zxw<^dH*(J@^0b6XTD7{?2CnwF>^ONPmWg{Xd3=NyN^^d2kDvWxLOI=efD70A2DB~7|8ix|Qlw2lIqtW~kBh4*tnq#M9sU5?e|J>f^khfRD zIOXa29^&OZWpwa`)aO^*l2{TGt8bPT9zxBxZ+zZ{nuDHn1sVoEezLw(@gd3%7cnI2 zsPU6r6e1rlNeZE#%HtS}YV7bda1046FPf{N#-k+^wq4n#1lF90FO*h1$nKcHN78(| zHXQ;tr(bti5NtjFAoW4n>FaV1LBV&z%@)tE(}9MO5jkre?AM z(>CGe!1S$WgYUmMEx(-4(bzPuXk!6p9xRqr*M0jPr_4LQmf&SQ3nS6tY8R^R3r3UB z@&}i!3Zbt$Q8P2T)rv}m((x*KY6d>_Om;KLx2@~hYA_%)Os%~k{t ziwuOv_L3a*D)=RT?M=}Ql8MIn*q+j4C+c=$FSX=VvJ4AYPkO`3 zoGQ~9{J|}JVf>ZjPOK9J`9l?IY9+^rU85GfN=Bc`N`8f5{-Ii|{{c=+D0@3^kDj-DqX0KK%3a*V&JPQ;BEm{6gw8ZE z98Y^~zE;Mk+{ka_^S)xEh(UYSB{nlg*Yp$vOCZp+^bK_J75^~d21Pwd*x*N;al$1M zb^B*((Q=xLwk`Xc^lcQ7Y}C}!M{q92dCOSWb>M~F$~n+XIj)#{06 zkKMFyF2am=Y^~+baIe>0jCI&4{PD=oQm8D!i%Hm4Aa9QlcU|7M+MqU#b=JfCSwU?N zL5I4##|@mxt$o!IAipy5)7oXx6Hy0}L5#Y$WiY@h06+nw1-1+FIu$*=7v z5nVy%$4I4!3%40cJJdG1&2A@Y%=JmQ^JQV>qMBt=baLHBc@_NBf%-!Y_m&yzsO4mt zTZqb7)qMzgxst7BF4~zlCQH9p4pu~l1}S!Ph#C`({kt)@)Fl4?CJ2}R47c{ULtNnx z`Ic8q(sVp~v{HgYcQ}olYi(SzLVhwr0gzL$pZ( zI`YYH^3<$NR;iYY{0!79VxqmWLbo1^z2lLp227jB4`pBl28o$-Z8R^BG@?~u-p6e#OS zeA|k#T;PaOy!h!J-Qt7sx2oJpHEH_-CmXuF&ckt@4^xwv-#5#dKdlbD_nvFD`ND3@ zXQoN`)9%JL@&&`vW+cg}MWXR{n}!A4uM!rBYHq5V{j9?BMW^b|8yf>P6c#ZgPbfRfB83ZzAM*{5qNZt|5>3C1I&n3cO-r7h(}q^+HDoxM=#1T z@xS6`-%-pdhxW~E$Dd{0Hzk|X7%^QA9l~(k8+!anH&B}FrQFegTH|rLk3)`r#t2Af z%TG{|MM5m*<)@S{ZhToqhI->KF!G}PGHS2zHjS6R64%Vs3L5T`NUZ8tNe!EE(oe3L zA9+OZ)m-2ty$AUzx*!p?Bq%AESrku{(6|@erfo z6QxT~vxsmj#@gKX_4m%G$nCKtidmeWnc;&SM^aeMN6Fh!(qB-J?NNiFNS(>f)oX7 zs`O+yUgL@twlSV)6xfRqSDjy_58+?=y?!kF`ry`1Tu4rf>JO}Jl~B4@Zv!8{IPKwX z_P)VI@hu_y{*18NJ91LwVrk(=866Z9uZ}*W9yRYgK?thrzwF2vixZ){K~6KC)AO=e z0sTsK#o_FHM0>?5B=?T4Q3ClL?-N7BWrM^(5!JXAX~bABWW;4fvL(qJH3EwIVtNXH zt-36qZ#S!p%kd`h9fH9jrKy*jpU zrns;!8$Ms&@reoHqznc{p$q#_TYAtHey)&q;Bg8GsQ1C9kkOV7FFV?>Gn1NtFm5rG zatz$m)W*po>?2Mi4DZ(Ss!mh=zTAy3)aZT{*9N*|%^PLZQX8HVl+~*@Dw=CB^wraE z6KKDJL>9j#1PFL+I#j{lZaB%jfGEnM4lEEgW3C?n8XRj^` zlos;2&#GOuBT-oy->iG-=6&GFk@Vq%R&l4w%AlF;LioOaFXSX!bOjADk zF(b{efL3#$_d5#*`J0r=B&y5#39A-iRWqnij6?R7NuLS%Y>@%fS}OT$=;DXMoqCtM zY$`WN)(X`R3KIxi2k}BoJ&hX?gQ6|h!8YdlcfG#2R6Q2d+N^Y>Fa~Yl`VeXL+@_(- z&9J2LEq)`UtABw&aj|^5o@832+S8`E|Hz)k4DZz|<>F54RC99`(sh!Skw~QpZ{9jl z!-$5R{9%9DB2Df%{_C6H zCw}xwGDTEH*S{n8lK@+EsSBH`M=^0a^=s7Xj%kCHZC7g{7}4G z`GCo7D}9i&&4z+9ssPpRLjwEY2x<>OPUg}}uNhpydMQN5sc?y9_J~R>$~<9kL5SiF z=bY1vrmm}pS|$Sn84GV|az2v25DRBjgbosiVlWfPvMJ@y^cdC29Zpfp&W!dB-BPHw zx|(L988Vu=YL-1ME&hC9l0{lVLXq|ai84Brh6qfo@!?%tK?5oRnrYYa#H3~XsF97f zVll)1haIQk6ngAlPXu%Shm3Ax8TY>jh(n7jiJA{R6g~*@XWv)7iUXxAXXXy(93C<^ zL2UcJ-D*guM*0!PpUqRYBkRc2Zo1DFuHUVGSCGR3sn{#Oj7M!EFV|f<&1r+l`?D&o zSQMr_fvVOARZ0_y@kPxF55x_u9j%kQDghy~hC7^vL+BrI%)K$LVsM`$J)?VjJ~Y$s zz~X<#dk?8A+o)4+0aLDucPTP`AVwaE!V{z3`|$#_|4@}Iw+~S@u$z7~$vx~9HI5uP zRewFlod(wk#!~~lsqx6y$_Wa}$iz7GLih)TZ4tp`2xnuSZYWjkm+1KS*>)oPahQl( zuX118@S(7C5pW4&1m9&*Q{VD*NrY6JJT%LXld^w@>aNa=CP?y&maKK*_hQrTt0ODl*DK1aamaZg!N|N0%%W@2f8s^~kT zclw~X_jt?VhmZUctB5&1cL~X`sNCqiy^35+I|nd5@N?B$lV=czEyB*HtGI0%HafJY zXQkVsT*mgLWxH*tP~(Q;OAUNKA-3Vj>HDQ`vZ}-ck_={s%4pQ%-E|ywAiS*|)6o(8 zC6`ebWdj{?XyvA%t~sxQq?K||2eQU4=j3Pf!3fM}B_h3(#P`24z8~T`9+|3<>!I~o z@S^vsM2}x@2+w@XQs_JzioJ1AI<;RCC&K!!(A&=4Wys~w-pfd1vCP$)t$ER@if%lL zENoz9L>*CARnk}WYt#H)Dnr?Q^yh9QjKN3rQp*~cab&b?rS%|BOn(BE2L;FxH;JFt zKE*>LwQBX|C1Mz1NQ@qAlj7u8%)f!kRbxkJs#_3ni_=a13^@=r#qWvoLtJ%tN=c;j z6}9s2zDa48gr{iEdI?d)I3Wg_j}gwMWxi97C%$ifv4Yto@+y+>*j8rw(!fdi$1BFY zw<^a6tTHUJln5D~`1dgBRlqM3J_kNVlo{IbNF#gZaZ1}0KxQhy^SWtjkMhM!2EJpI zSUl6|jT)y?$JZn(ImS7Rb$Gkv@m9&H><=6=plCNTJ&PTYq?~JF1epT}4JeFKmjv17 zD~T>Tj8Z+q@3TqK_zbEoixwl;(moHvULZ#-|512n&v+!~3wl)g0bcqCM6BLVU)95j zmInhU1?int+=gb6WYc0I-&(r4O<;9gC?O$o(JNq{>yNuTCEFW+>JzO=8=xC`)0{Iv zWDv_EbjI%}Z}k>|*+X3Wt=$)Sba&^ucmB@XiY06`kNEqns>!HpumtJxc`uZ|jq3%c z*P>&^3W`v@-QN)tIsI@xs)P%%GBO`9;M_#x{#sDSr;yj2E<3O5&2v8`8;9ykCt9)@ zLe0ww)^mrx=#9nJCTWQeui^}DjJ22v2hnQwgR2vHZVx&{-7k~dU&eB{cewJ%`%{hi zI6K9cF4V2|^m;jiF9f%^UvQk_3`t#)Yg}Q;*8WgJIZBk9lR?DT4iT?%aJ8dk%zP=M z&E6Ed-}!##>sgoTn+VLQa73M$ZruC=NA*0Tdh1h48E)JYBt~!k8i%|`*jN!vSUn!? zHA(742o}rO9;$tV%cRj`gt3yYn-GTp(~%a<&4$@n)R(elCsF<()Bd`o)7vg0;-uzx zzF3X9(P)FmbN8MrdW5z=kg9pooC#?gsc~VQHFDo3B`%j=pY`v15wleD#_dCj(g(CR z4vVyR$etI#y3o1-fY&Mtzl;qd%4Q9(`w6c$C}MR&H&fM zj-#^;d)?l%7G;XwT7%&!yDXPPKC=6IOYC!daZ=+Jgn|}{*C#9jOX)b#(l*h%JJ}?X zH1d+n-MW%2ySsLL%s7w%X%^bY;{$p}O%t4K-Vp95Ia?DgIM6Q_(KOIR4kLcb5vkOv zTGxZy%gv7-yQrOHBfk4g&xN9}$Ii+eY}-%y2<%*Z9D$&^NJ-S=jD3L|i{A23Vqd{# zrSFSKUvNDoi*+mY;hgIPI?apF#{=9cY@Gs%0R2*|nbtOp?i%_wL_Bi}RoVNLvZbpYNa! zw%(-VuPUrbT6#vD$nsWwtD>l&`*EUz82*ktOEW#!tFqMW!II)+J(GBZ$4ka5b{UXS zrIiQfgCFxZ#M64(x5i9G9tF+CwZ5mttaG{YFsCtK(0U9ip)!&|jMy>CeE$96sTNOhPTtc%2>F0)@pHVZ@ck=pIyF9A9Ji;c=d?UZEa%{00 zr2o~=#PcnJSl?5ISyBCRe)kZjuLU2nERRt^wFjT#bc=4Z88<>S@3*+#r${ma^BYAG z+!xwK`XD4tVWs9$A5>XFOr8IfgN+z6n8*dj$uG((3J}p}d@SONN>JypK?Tc=9gebZ=t2qJ2BhrW4eOi=TqZBk?`FVY z>@ovm2Z&d`&Cjz?@8iQKvEL~!nt&jt)R^qIUrf+-Pl2@+i{dMPZY3Qc<=M`lmxW)cEynF477tm6$ZwsiBUlx|3q*igfNZW+&8&f%^Bs1kjhsMozvCL z!Km+XCTFj=`6m z{_E6&tR>hQIBa6Wab8L407-=bFu^HGT4|oc!67m9L(&z0FDw-29TLL?C1$d zf{X(s{Oe%^VPhvtJ23F5fvS=;?2p#M$;qA%1aftCWdS$A z{&DmCCw%~)+tdKRne0IJP_U%>}MevkZFvl*3qRulU{3-%EaSC!H*SMiiY){`? zco4nFrWz3C5L2eiN`D(H{YJ3?H|@-Qmp9zIPtdxctg8PihpDyK`S7yD%+zx;cF{5X z%?*VA&5wpKI&j%H%FQZH1G-RNHCmjfSwlTNXcxSKg7W(5LM=td4gJ*vul%d2ZVa*` zIv_&cUsSpg&@?5)V<d+67bwvc7NqpVo%Uz;J(<4$xV5)!-pHCl+&pO` zEdL;S9?hJmg|H9O$JIFJ@AO*R&IYWv|4AhC$MMD45lXxu503>0QL3whBYR4kWUqfU zxyP#{?UuID7x((O#)t{mXn?^mZE%xqeHszhuWXGro?K6!Zax)=BmB^KxvsnaXh z)e#AWo+3Jk?%(Hzz6>cqkx8~KS?`$+gojow>moKmm_)V zB19bQy^X~z^46~}1+36p?+uDhClfPQQs+Y|Yi0>Heb@jm0QzeVPplmAM=*hZ*4K!}I&qqEMR&R4m%nC;!HhCWCoPk(!R zn}K04cx3%SLFx_-Yr${6s(|?_bL^M3Im|Z(tU+cQ24b$}*b&hIb(7<}k2w2x6`0ubR!$p1l zOVq}-sIr6hSv}^otEY`}PI!Y%a z#@yQ2g*-qihdvP^?CbO|L$@Ej(Z{#%TzPVV{=R$7!`Ri;#^Fa@dDv-jwVV0^%7G3% zbE=r*zA!xiqOaosi@rY)eNDfggOmRnoT>CR*^guohfvt_zCJ>Q2f+X4_?JKO|Emc8g-q%z*kKEBVIcX&1it{sTF++OEeLslJEDfQ^N0oYgQg8uOXc;xPV{#YFd zTljGK;Dczp83^d!w|oS+ba{UG0uF>^j?m{97G^VHq3qgJTwb!uy22%MA>=KYvjjt3(>o{x)+P8Lwz+Gm`64!d2Fit?i*cYaq>t8MF5q;LY!Lxy2 zPBQ(=WQqGdS+O@J@pH&c)~QDKNviz#lV!=Ni_M z_lAa&d!g3&XPwO1HKMlwz!iR`sR)A`7tX@i-K)@Wzd-S!#~VWFVb`9 zbN9InZat};uvy{j>Fax`e*zV{BJ?qJcjrBSTA_8XQ3QnE7q|1ZfpSjjPoMBbB$(DFO=#*Q+km%`>xUVWLI2_^&pKJwik!)-R3srr;44^ANEXu zy6;23#iJZXn_iBXXfw+5jHw2c-GnDh2OsKIzxe9}|6Z{o?#uH%1x&;eukc;sl8cLI zexi|ow}W%EK>O3y6i)fQ0~_S8?C$prGFVrzd5_h(M*2k4;&Kx*z6L6Gz6{j{67g%c zfkv%SO#@%_6lGrhtKDu;j%PQNd`bcDiNHOiU+Lb#C$rU$#g3TtTEi~pY1W+Ym2T@3 z>J7elvQ$sWh0M(9Nv#GYLX77VBO|_T-tv#@eVm;+kqcGn+bSxeCvNM2>3>Rf#WP6} z8Lb&lq{X8_N|9VW8jC?GD=V8H(FrK)X!9wxAwmYy99~}{oZGjHZeR~?ge4>-%=w(j ziHT6B@mCGh%vQaao&L1y9w@Q+g$;($fNsHBtQ2Y;`G}Dpr?#9NMBfGVxd-H~1Lqmwek24@U zr5Pm$dN{6{n|TUGbgM?Ne##F)2ITLR_O*?Q6}X5Fzydo(mk8ZxygcpR`?Nz;U_aBu zP3lmR#+Y>bCcG>F{x(TzJA^hhHX&t-O?w3BVI#47s0u zPCB_+xs7kxW^W0J2);HrX3~q1}qQYMSt%LhPjptaG^>tf9{QKVZ|Hj3`Kb{(y z8IU_{0MAU-cu9+iQ>S&CZnp$QKX*4bXH2_VKiPv~HW7^5{wq(M?g+frx`4 z=z!4Fe8&>bAFGk?%RXN|s8s&iHx?8W1SFI1#ew>Go=5zY_U-JrYD$U_) zC)7aA?yJ?X!}c^Wihn+3zt-lGOY6o)pw+>~#fA4F)ooD*wLHgiK3=IdIbbWmLl*<_ z0SP7lrMGRgbz>~*XK3@d!bkabgt$P>(Ahb5PJ(Qs zqikgNg8_3qjga?gtDrBA#SFwf_`&-HYClzn4ZWg}Rq;ET=Iv`R1Ibr=>V;fWoY%v4 zMpI_YAjh%8plU~`e7|~l$|en^v-rJ|VQHIl%l{!{(pFC-%uf+jfLEk}i+pr%oe0Ten zA5dL3etF$i?0D5z#@TU@mMQe|&$R>zDagrL%u-mgm?+WXrU}f46LaIW_a4!pW0;nP z6QgDZ<+GFZ)Y>&TWO6>sm37`$AscyVG?S*l4{X2HBMPHZh-&bv0#r02z=&UM$Kon2 z)Ez%TIgxXt!xmEdVb4Bol_RP5hr?ENiIMsA>bG6hc@OnSO*-UY?w^wd_Ziu`E zfG$L!)ea6T&n*@5-8wmOx1`;Gf9YQ9Wd?p0h|nACH8L;P6> z-z~xFpjV3ALTZt#t7AxrD`7k|F<0y2Fefdp#>_ZJ?QHAPyP^7rq5E|6<6z#6<6;31 zV1>|b6zY~$aXOqDTjbpFB@VXq72NpVdNR4|Q>sVA@=N;x$Di5*>z@b}HG0z}$=W^6 zGO>4M{O#sgm8_huSqL$pT ze+Gw*Y0BrE8$9+@*ZPBJN(-}wYu5C0?XsHY&IMK`($4tmAPtpeY56I)AN(qtDnQvZ zPcABZEnF{bYzK<(*EevpvR%kWP1EwcIBjie5>_HKoNe^oKEoDpkO|dx$WsyM%LiTz zijERKaj0|Oi?U@R+2s`ws2VZ=`;fAK?}zf{sM;}tKp5U(Krl8rq<(eE!c)NJ0MwBr z06Nc)PY~v*K?S`}V=PWgG$r$*TZVH2feu(oG=%J}=V2%%xYM2$e0Jug8IOh!kNQGo zg{iuXxt*QSldPuca{>8UAq;zj`fq}_qR zC5>4HdGdSTV1US ztDxsTx3bO~VujI!1rMOP)JP6bx>xY}RjkC3`HQ9rCtuR_WVLz+XkSWtQOT#YWD%mz zFub|f!T)pBJvxx!adD9^>}5GW4tO>?s8wz>PJOyVuFmX9Et7*Z5#=~kO~^{*VBEn+ zDM9J+N}I9Pp)8#f)0KsXc(eZ*4C*s()8s__!!@_lir(-)^xe70=#)EOFefQkIE$Xa z;IXlTJ~v=KtX;!Is_NjioL*pm3bd08&-2+Aou-Fu<=%$9@B48CeFXzTTu0Hv(ui<` zOzLi4a`BT0=pXx%l61_(7z$#Z4Ld47;?b032Qm9J7Ax|3TQ>mCFDb!1ON${jk?E6O z#0!cHCC>vY>1OiyRU-Iu}@B`@s)Gxp*HEGH6|Kb(wIFC$z7gtAE3o|y? z==;#}#6nXNXk)rL_9k+Ait=MBD=R4qOz)V~l`hbPX>&*jf?w&00Yxb}Ok1nq^`n+) zUWn@bv59o3zT-;{2O-`R4nH`n6Y2VMG3y+(ua(re5AHE@5rxew)R0v2jjV^Y8zdHCdIlwI)D%1Dt)5$h^ctGIOg4atet-Q^30SRRrQ0tZm z>Mfd_=-*-h>^&1=3tn}TX2@r2Z!&fpz>FT3aK6#vFjY3{Na}R|Q zzL0c`9)+MR9-i!(1Fa#vX-Ribww7ZFC+NGFCDBNhT=OEKeE<5abM5^NI4|_(6R-h> z?m2Ts3hKLl*%+&ld;`HCRXp%n1iDF}>!ZV?vA7m_G9P5;b6)ZUklNlg1=4SzMG8jc zd*2#tK3BaAP(UDbSoixyu9lOW^(Ei1FDp3|lV4vF&2rZVLT`xxr_d<38LQwG{{6`M#H!#L+VckYBqWI77@ zUs?}hG}|>^;2r2&-$>!d(pMm=GBlwFznWD976n=_U&ScW;;VUq)xELTu##cZpeJJ# zYGREH=NFB6yEprwbNHguxNgQK0BpG` z(C-c40?!j@&6_lzRL?wB3$7$qHQA)FurRf58KNqlP!k~cHGte-O>+KXSxy~=fero8 z-x$6L)KN^T3qbP_>rkJcns1K7`wB)F1J`#%Gr2jhoRY$~nkp|K}cnR>fLl&Cak?1_o`QmiYyqt4-e{8i4dIEF?~{B(x3-)S+jF<+^Lh_&n()koWs>} z=&UN%s?%;rqweO9c)hF!_Lph5(mtHA%%JMF44RGKYqh*k8bjMgMX2P8mMA<^AE1`N z6E*7n?7QbRI;rRTYsyi}VU4k)Oz}A#>2Mw?k)Kv1wIJ@x{VJqtV(!X(8NWJ!0$v!3 zcFwJ$UO>NXo_WC=Tvi9&a4H&OBi6LJ*92!u8C$Pg35R-NOW8Kq2X zJwbc{28R>u;nh?vZPkGolHWROO{xhVo21;B$uE1)iJ8~)&4FtsEr^fbqoH!%qoA5H zvw$4Fzk~-~R}0&_z{KRPfy0Dwq!Zpc<`eU%9=6r|8uW$*a(}MDQRolCb({EEA@&T zd)xc!J%y(0xYH`dA2Pntu5b8Ma+sdsP8=`LPyT>d9xaNdZedB zXGLQ};Ic=ze|68Bzq;p9;@IFXCpZEP`ILEUYf;nKr%_MTl$GNPoXdE@^X3K#zj|}B z9zJVrKA_Kbbv;ujI`5M`+tY-tpzE3Ke-R^!&cJ31zjZNGz|F-C8r^8=Uo6QsOU{Qi z@k=H58 znlv-~qjSE#xABu3Hn{xy$a*w#>g(5Km%3gabI5g*p2k(d0!|?{kbbnGQNj-EoB{WI z%EH!bm{qoX#k05B{}@)fT(_nPPl?nE$A+xS{@MKl^bUZfGJiz4yKm)t9`8Wc)}-?U zg_P)ZJ$7I4gQqnJxaZOY1Y&-I$UZ-ojmzT}|G02y7zxRRu9;Lt`tc!@6y~OD5r4v? z>pMI^1iFr!nr@tZ{j~QC7a%iE&Tn~c`MO=4BKb~Nm#~06J%Q5!U%~=`#=I>n$yvVK ziSG@@S=~?s#Ox=AegRedt}xeah_Jn!k<}qxfWg*8S&5Z%-%IGx zV{fhduagke+HB3uL!(6LH;{_yJvwTull%D8wfJI#UDw%o3C*`WGB%RL@oOxQ506-JU$%%Vb z@a6cf(G^H-yj-qTnFjO*&p+AE2*_v8q}fQemh0ei-0s&k@9rN1>lRVXn$7>pd9tm) zr(G_kDgV@(Z*n%@()nh-Po6og@tr#&l~#xv8i<4HPHuIlf%J5<|25Mw@f*{@B&5&p zT92nCI&|#^sNkz>B>n0DV7*b8K&;mHrzdAGU7J2t#qV8Y^cnkE;LfF?+4YDAz$lae zDxf(r@&`I^8yL~(cA+(N&4R_H73qG`LoFbGcFhDhKD@5E(lJ+Cfg*;+#-bMPuQfX> zN9dipS6W)8o12dp7IbTJ&IWrzLgqk>F%|_|wM%3_nM{04p!bHF!q`R0H;+=p3*-4M zb2NM!T(&%zCb&WnezN@lk8{0eU@bR#=Bi9iPGV{48L5@(YX0!-v#zV7!N@Ec+xS$q zpEI$3V4CRe>Y8uf7K>W~ch7ZWOpxph+(9B0czfRoZ#=EVC3qQX4J{mtvMu|KEB)Dj zKfA2!hx6-7a9dm~Eep4Ef!;dsqqH`6L(u~5)vO!;~k?Isa^(LW`vJr)O;JKksOVM@9Chnw1w%ci>tHb8@y ztSIn}o%+-U2IN9@`q@dX%YDl2|3loHheO@|@5AjYsYr{h zk|mMK*tetz*-ElcQFbH7zE+~_Nyyj<5hi3`CM7~+XR-|0m$Aec41?!-&(P<-@6Y}H zJ>Tbej^}ueqd)x7@xJ!g>wKN(d0pdPLn+tkeF(_@mwmdg91m=Ar7@daDJWcK2T6K) zHq6_%2%9{pFr8gJD&%wIzJ~{8s5bQMorYndt`#r4-*eN&$nXvAh7TR}Bl9DGvCPet zlijDau34onr0pBEv8FZtRp>0y^MhZxz z5s9r5aE!~G@wk;ixsggC_UzyI+4vab#95EeH{Q7USSA6~{gPiWyh+O%Ak6neBtmbB zV#!{H_ih-w)kS(f-N0}AQBSEo@LC>-;qc~f2Ayb0KNduzPUSmOUqeef4*xUdjX03y z{=MZ&`;h>^4BIESvkVOld9Rbxzt3l^ue*6~42LKbpzd9SA9xmX#EVlz5uMdhzhF4q zcY_ZHA_Mh2ymHKV7?+a0U(W35nz%zDdFAncuWN5YAT-5^T6}8&Z=bz$&}+SPDWn?T zLcVSW!E%peB0Mc&yj(kj3D;@wBfI~?KS}*WWBF#+VJ~mC-HK@3HLIJaXwkAaaEkP4 z+rk4=)6t@SFUDxS-|GXo)yQUmsE-58U6-(mq%!yt&gW*}IfDPPEA2>=$K=d1n&9b9 z8^3u8r7jhb)-gA>Z3W{jAun%w9sgwtVS3soX@tvkT55-BVY*8no{b=->8$(9zx4l} zslUC%fI$$+-2m}D?BV|#H*VG|D;0A+L-c^}wKt&_F(3pHfP(g6#BnoD3=a-2p^YkD z>x3jmTde!~+Ub2LLww+3rYS9di4=O%eu??*M6?;CZT)i)AftG!tvCXyX9To0E-ZH% z>Fyfsap;+TPtQh9^wOezrECjAl#6*X36EIy3e%>G;@*s-G-wa7H#JcF-W9idaqMH9 z@xPB|tgB0x+K3c9sv+umWYpUNgGCt+vGZ@8w-EWoTxGal%s+av` zax$}ee(KI^vkxPhRR$N;y;c_dJ=b}gOGoCJHVORB3Zvt+8oUh(IoFz_-Mwcd{?Kjz zHU@~leF^dDw;FB^uYBz?YpTiYK)3PX051Fj%rsg>OC$ByvX9b^e|&|?D81k z>7jahq$=YOs5sh92mXsoPsRcI7LOIU*!M_3UXTE~@4aFXZ6)GlSui`(KNiTs0URUz z4S#9^pS+oFVRwDTbir^*>E#{`YE96P;5}VU(sQ$6mf6aY%9~`sInaEFuWuay>IG5_ zFpy2Ge=M#8=>Dj%`0@a#mu#oTUkVf6K0XTo`_At+)>E=m))Njgu*;oG9@u_AK=Z+{~Jbq(M_O3*Kfu1CODx8hyVey(9wM`{ z$GaDsZc*xhxi>}VURwK5(8K@V+$OuCt}|)5^-q!w+|L3=M^yHJ(f93xu9Q?0+nZu-1**<_wV$TtP9?0&G`K zx)sa(q0}WEDrE|1-2|rpStl#mQz`ZLFR!Ruw`HXqvoPetSp?|WtYBkA{dSbTGRxLB zeHn8;r#6^}aLY~_BD{f+>DO7^d?m%q%=9spJ^-=sddY|Q5u8U)l#_Ct1C{L&m{*n;ZNV2pDh5zcC+5I<^kARNdUeZVpkN-tw(Z z0_6%MbYI`r3H`mF^n3wDcH%-BJyjC;_TU`g;J)nuXjr}XwzcYs(CdwtKRg?U>R2i; z13X!S^}}4@T~z)wm!`RL*Aar-Oq@mUWw?;sr0XAz4YX?--Pq#Qe`Wu#dG%4ZucQCu zn`r7lOA~J3CuDj!&JtYnJH7W%gG6QrOK>d=vVB!r0S6}V)V!Wf;A7~zD1hY(?zwd3 z7;r%Fg6V1ujPbHMOTJ_mqH*jkWXJq>zKm-IoP!okgiUaLN!{tUhK7dHOCeQb57}t& z9e802Bh$MY_07F1A;@3iEh+g>Qr4TxqPOu(KB&0%fb!7faW71t(SS3a_&M{mf4+Xx zn1t;(93A2DFm-droTeaAl(ElkXzKq{UVX@e?GTnwP+T)!)pP<7O~C*1>n&<;WRtr;w@M}}KPqn% zT#2&4jO(S|HqdXNU%x&!i`j@jy{+3prlo5`=I7->r$f=fEXkrLKyuW~yU5y_z2EQAw_ql{(nN zFWo3kB^Mi?U$udY57=+xnj{zCRu&cz;18rUsU|eC`J;LM zx-I=oS8%M*cT@4(*kh)r=6w8C((nV@#!6>Xm}Bp0dGuWeazA z$yPn5=KlqE-q6q>4>uu_^ny&P^*4#!hD|l~aR*D>7*_S-MK8gP@{+l>rWmV&16Wg` zngEOZ+}svR*S|?^p7}Fk!JXIV9}KdR$hh1%8s-0Y;+%@Uu6*kI+0#H?zg~uiz5V}# zIOiODXD4I~8?1Td2-tH-L0x!g7?8bxDD1oV=sGJN$RtCJagwxoQBo+}B)F|>sS65% zCXjyt)LmLyqK^{AO6cY4#ievW2}NSY>}u;XDJ$WGGl;ZecG37Op>HJM2hSa^D|OIk zH08`dQr5(iA@d;?XLU04M*;2pi8F7RE*d|GZdqU6JhU9LO?7M-Id5-XZ~!QIqlW@s z0SJG&T44K3O|Sp~Xw0DR#h~w#e@`Z0HBC7Kw~hi}xoNqilC&rF@-bVb1`;HT-#N3i zkRik|N%ssOcd@}py5mF4GOSN|2(Jf>A;1f;`s>c?Syy~&w-n_gBa3d4aP%?fhoAlt z;!QW*$N>Y2f_9x@@-p57HNj_R4UeA_gUl~y)q9T)Y4`F)oc|;6H)AD$B;HcCV%=Dm zBY5i9)F2Tp061<$RdmayR#AKHkEZ|P1y2IvSBd#^PQv$hT6{9D^I~MJWGRnjVms5F zUf@hX1lJ4|6iAtM+Wk_7d?L?v&Gc1x>do53;=-q!cE-j@!h4Vv+6Qcy|D!BJqMEUW zEkA!yK7QuOc>>^VmzQtEc%N55goodV>$!ft*1y=*Xy7l1@JrU}5CcI^VpwPyk@~~t zef28QwGk1Awkb1GDZ}pAk_|VFA)PG15eLYz%NLu3?-Z=q0CE9rhwO zPgf-I3bGTpL^iwqKqVcI2=92J?9&x(;ypu{Y9@DoAryS-;rHJvF3h)zi(-;O>Y$y> z?odGj1jElQJ+D0X3c}@9cS#`hAN4gnof&FJViH_vFumO};Km#hrsgofF$5ujhpvlZ5OUoIfNQ^d$yH2+|RLFNGkt54DQm`4T}W zSm^%O225-O`pu;t8pTTzAeqI@tu?bL^o?><{C})b41cpm$*w<6OdWDH0o72{$=f!( zm5}EL01jFc9$RC01C4>|(s&N0{)*S*$Dd_{XFasOfnX-%T@}B|VT6&X;(&_Np1!{4 zTARhA-Gpfzqd;8a(AV`G*t=NWrLngE$d)g1aJMb<|4z(9zNI4s8g(A*?fNw9;Ik5H zc`eQo-@mkAA$Jb316Ziz;w~#6%E)5;oC#IH_7VgGiwP~hzKn+9hp{Du;2fkLITfc=w{r%sRt0@w#_`^v-KqCAy>nph7LJ~rJk8M~gE{^@Ks zOC;g89q9L8?TWx?N1(d-K;no62dW(Vh32aR=FeV`k*K!`4vr|4Ozl?{xO}0@Yx(iK zNpXHSD1*%VuKIT-ANzVxwN8!?^0yW}KJC^51aLbM0=NsYZ6z0jZMyVV zPt#5+;Q8e)Q3-ju$5!sE{kw^fvKuH7x;+`-?JMP%kJJB~qmyK%1QCYTRAPJ1P2iK? z^}pK$b$!mfQ~g1KeOdwNiHZQy!O$e@xC-qNfec> zl78*LTw*lyF3y-t?k@Qk?hP2MAcj8mwuP0I3XRo%^lergJv|dI6;x@2Cib-^n0~-T zS&RZTFaFp)?R7!-F=AUy$C|ewsx~C}>wV5!+)p+3IG*(u$v8n`;bPGAJ?rTEoT;Sg zSytZZkcBCo!^d{Jzo?hJdUamnw&;<7yn_?TlFx3pJMxL>K0I<`D&^&DRa>bS1v%O% z?L1S^FBp9I%-4!paaMQ&QVMx72Jg~bjreE;|K(`BuqeT(!st93a>>$ECt=M#V3b^7 zw`4UJse9sysqoeOQ;E9t<*2SsvtisYqYmd41PS}U1_k?;@Zq1%&<=lzgzf2|#44k1gLniwpG#4f;j6J0X#8Pr3 z^9u`^7sU@rBzQGArnA=S!PP}1G6DQ5pUb%3F*Ohy3#9O$9Xewpfn7OCh znvu9SIx zf^eO*u{pB?g@if%Wtnxm^; zJo?1Kfci<_>4W<=2#tO`^CYe18)IWFx60vxML)i5gMHXe9sjS6AB8gNw{ATSqTBQ2 z7B_L=>)yyDlQqi9_;`6r*qE;G7cN`{^Do9+U5Pg0fdzfrzFh}!C4U`UQtE!{Vxo1& zDBabo1uhNzbhP~fR@4X^L_kKGJiN4Rm`Ej$>6bEZGy_1C|#G+Ri<2H_Y zCKCgO9^!C}6$#Hr@@T!c+G~{l8QLrwAFJNG{*u8|+6^i6Bk3yO2UE`=z;1;03&MBF zOYf4yE`L#O9v*nPOVt%=la1dQA!i&aIPEeGybgQzCjiaCzQkbmX0NybT+cY4_I1Mc za>-Q1xiC*aag3L{Aj39bLbCJ$O4NMy;-%DkQN zkq%qfZ%|+<{ADyey!y+R@xei7z{?N54M_~Mp!oXIVLRRy={?%){K0*o^9ZQ(Ux;a- ziD_?X#(Q3D!>JDj*YwICG4I)&9qpZH(?XJ~rDcH0!$fhpLHYn+gQ)ZhsZiOnnckTh z_+?_1+?PVd!a_b)#)6Lp1&?}kQ7s85*yGLfRWW)X7dWOl&gJ%jVyP)0M{`683a-*AKL`t(5gx z-;*{Kj@J%ueXf#&wV`*u4R)lYa8BG=@H6FSHnVVQ{rpID&!@Z?@6T>kPjUV&)}kQF zq2b8QAlFDP@c*|U7q=R`O=d?8ONXVUjZLtL+l2h$z5E&@_M|Nj(0Kf4T#zf6BvZND+_Bb;Z#c+S#bpp*e?#NUXp zK5>V=y&kbHP-b9M`$QWYW8c&P$C?Okmj;bI+?by!mT1K|i@Rp=@)$Kgl?i0h=48N1jw(Tdr|h4OhxaU zwzk)g5e2Qno0IhC>&EgKIO+>ytYM#GY(isWf4jtiKiSLGw)GP#*SmvSpAQY6iaStT zuW=hUW{S1@#v+&X5VSJ&h`H-euyDd!6NKgo1Ly9S%fZ#u86zDv?U{Hw2seAi&9$+k zGF2H`e9=MHWlA^H%WQ0H1o$87l&kT%=`k4b>~Y0UO}$*_V!K^j8E-v|GkC!7tVynU+` zCW}9<&~Lm4S84)_-l+;U5dyy1&fxVUg;5Stvptf|!(FQEs2(gs1DAW86s!oW4&8j| zg?kGEs<3`;oX2FKvC)Q&3XfMwZcp_0ClYNnLF-h92(#7h7} z$7SJ(z-1xJAJnhuP1f_j{sS&1Vfooj65v9si$xt;UF~S0G+#OaO^5#AtWvq~dq8<1 zNk>A#nmy5sR8_ z`gS+(m2-!3!#^APj(!pTan8@1mG#`~x`RiZvV*4_*K-Q)+~KUPt=0T?iMTq8=~;Zq zT6Uv`zf3%YtBr8hBoZX^9k1{?hGp;cm0m2w#yY6xa2=OzI+xXihsC^xt6bE*S!&tw zi23B79i6&)aQt<=RBQW;N_ApE__$L&kwOu{s+|%Mxt-(A^_uQ(@yt{>&y^`=dT?3E z;an3T`9U(REhnc1z6n;=poN#PbD*WR=4Y~zqEKr& zQ%>9Ac+qtN8gt-)#=(h&@@Kos{EbWT!!B{WY5ELK2XEx#9e7n2=!NvOP4}a2;KnLZ z*m`u6Ln-`%-<5+fc_ElQ@w3(D20lV0l$s>qLU!3U9iEp!1)474m+@uSlkWT9Vq<(4 z2~#YHIqdU5biWZ#^?e=a<6jXHZ@9m(AB7#vZjytsM8Oj*kQi+pjuWk|hpFF2^8TcO z)&CJZcLqr$9~X^WR65kl){*E`|b{^eoP8{+w#gxT|*3<2pxlnAyzK z)YR-O2RnPE_r^MLtZ5;lGCiTWX~NskIkIt~e8*a6je=C_8FN2V@XrLMSeejSy(D>9 zP;TA|3Kt{ zMHCe)Gin~P!#+)U_7UY6BI-~ExAO3CKwO+H6|%D0pzkSr(g@erN8&FO#x;(0MEE5} zD~@h#!#4NQn}>{e=`n)q6y>{`&}$~{tI3ZH`J)=voJ*$19GN~uH87Zenx4)LK?(?{ z&dkoLlxcb01ov&NwaQ2)?*XbO?FOhsv@AnV^}6hJ*xr{1s-dvhTWpsyE56c;Ce3<# zi(bB5nKy6ZAewS-slL8`+O3y0|y`Hzkf!Tr1=bcv^KOUlX~0gnKj&;t`u0Zl{? zf=`7pFXS=GU17H-3`EZH$C%Cv_lA<*pMaoGJ^om#DJ4u?S-!bf>IzIWln#sKlt&W3 zpRx$?kj?go;_0q=Le1Q$YO-E|6k3BfsAR^VA)E>3&=bytq!kpyEt(s1Hj+r05b;-f zJ&g*V^wW7X?gONG0f45JZdF~2YlBCwA=BSq4FJ0%*ahs4<==AL;p>Y%8zyU?-s{9R zJbVWhpo9~gWc(9THsL?(uL-ri;yAdzR*f%Xs!)exWIW09*F_|+$+z8GiTAQ6j^g^g z6OxhRKQz2nM;fAv1(f_1=B!M9r14!pCx`@Z ziS4(San2q+jULOtpZ2S@?pszewk;#gB#Qk2XHx>4P0lws^4>cZ&q(8G(Vb@8Sne5b zw&9od7_iUzqAALrMSa2abDL+7c;7t4OEwz;P4?TtU^i)5PqW8<0rOsF0wIMypO z9t}N=a+mgIQzCvI!^MSOO(1R zVqq-cvgm}HY{w%%FHi7JS%+n|P)^P$u;gydiCA!&qn$ygFPd|apasX@=wu%}4kk;!9^4F2gYiM~Z1+Qt2 zy?gy1&R-xEDHqD00?GJY`t04!X-hO6#$DyRJxFh_)x+M^ow@H8$D$~>#bPbl<6`lD zh}?L>AfM`W@oM3{MhRanK^q%};}P%k>eOv-?w^=gJN|rhoR*?}QcjYEUnwuRfLm|^ zefu@O6DVp=*6G=2`?wDHs+_%33o;Lxp7Cs#>dUH+F}u)=#+S18miZ=sBN+3m?&Ao9 zy)a1du?o4+w{O0yB9G$s;7m$Q)H8W+x!WB>M-z1qP&tjSPs|m(=-(Z^-1oA3zeYO& zCAr88m0qMEmgVp!3P-y8^4h$Qp5QWq6QV?{0O0B-CF6kFSeaRqvA zc5^+&=z^U9+Lhub8L&s6QdyZjazgV~iLr<|zvpUCj+E!L?Em<;WUng0d&*4I!sz&R zWH#t{D(JYN>T~IH=FEBtKIWj~F6$K6ek5oj#AHs|`0(!ABVr{XD@nR%XO?sxi0d0JfFWCjXCd#jc=^C z8E&YeRxbsUiRJ-#%Bd8@8jor&0IW~^Z~(3NKVW%dzI2?_41i=+96TW&0P<9#%9BsJ z+NG{$Nb^w|w?qASVr-;~yeZGslSYcl^W>?oFBp;;zJa6=S`ur-#uWTfzl3t%Q##|p zh7xDiUNqy^B?-K;L}rnkf1%9M=J&(l5e*mY;Ey;a*Ed4#%}saEx~@;1dfL~OjP7M< zU5O4v-K$ej%rAA+fPFzkMo36^0!q03zufU0-sbmOH7n?qhe;(dqYwHL8tkqB zw0Yp7$bp5Uk6Aw?v7(}BaQH`O5arZOF6;6$C5(wu=nKr4^AXB<3gL|)r`Yz#hw9(h z3oDA*a0n_~;}NFf_|7m_7rH>*89r60F!;`l=K-R_&O6>rI>s+e$4M5QJH#7kJQw4>^sZZ#ue&>&Ju+Q* zRyHFWpjqQ(qjaQ_B3^{|b?2B9Rz3zEQ@G(i@S|LskQB{Etz-uTLAZIU^{keKKWpb40&}9 zT)e~lZjoeVZo0X}w4f~(^=odA3eVLpqoTa|q2=ZG+5-ObWEBRE$v!zv`LeFX@jCyL zU@|vLR^Zfs@;W5hMq@a;NdWai1S9f@=*)qOEA!?+b6M5(dVc=p)(pQ%~y|q7x=9Uyk4ZlAteTrwD|e+ z=E-(BO^&kZ>C~oM1lf#GFvkxp7A5W|OYjxSg{@K4pU?!Jq*=Pf>2cP>e-^Po%ULG zI*b!bctIF-)M)>TSl>?Ay%!+3K-|fDs9zoY?w$xJ4i!_`Jsl$9>sR^RQRffdb|=s8 zf+2TOOWYHgP?%Qv?Ber*@pLFItlN3EvBJ$(Fzl9*M%PvU(d3hBEUHRApx2Hc|4=3Fkv`B~)50#Pjj1kJDKwn;i}$xRlh1W4p*&IO>0>8|;aZPw=?e_t^zWMc z>!dw0ClUbG;Vr(U+rGL@U0z6(7F3d;pi;7nTsB5@-E0KFs?w5`zq9^@!iVG3F(ajS zLQJyJJQkl2jM)Ds{r@wdQCwMB859;sI~rksTliNhuQ2Z1;RCcO>nzOo^jycrTraS6 zHA>Prfy9@9XA|7~HJ25)%Le}jmtj|w``gsV#}+UShvFt&oeCr-W(T`hKiX_gCphQ) z5G@O>njfi4FrCf@(6UeYJ>Sbdxi9yRK?aEyOKhKaiR-VpR7}Kp#T9$Y${l<*rV2o~ z>KQA5!8x1%iNVq5ha`9>0rqDwIvxn|vcK?qe5tYq2&XAe*=e%~X($jdvj^&l@I9W- zIGWE2z>6boKH{4QUw zps_JA`Z(=i-iP9p{XAI;984;uFIBFsf^%*+H2tYrG%Qx4mrW8bD6KaYWryXmWZ{kj z;95atc4tL+4c5M<4+e;W+n;?)&|w_^{vJ*#~mo$&D20k-#5#{lvAl|j2|6M zgI^_v{y*aOp-q$n^ajw_vvQaY(Q0K zmpDS>^vwFm&%Jy1Q!(@7TkT&uJ0oq(EEK#gTkk8A8x{U@2 z&mYB6?HS>D+V@@lKOhM&PZf^zrj~GEHvwOUME_5`J}p>Mc6J^-1cVA^v`{Xrs*L`? z*OjTLI}RbD#Y93|+w(_;?PL?SR#V-KQPU^QKep5IUOANa#P?U`q|+JU#*LPj?J{-B z-5eawc?R?~2Ynml$9kC>@4X>CHOleP=rM>ZupTU6+`+m~<;0WSYb6xh!Xm*)Wv<=0 z3kn&Z$}6Nh&$6RZHxmh(iuY-W#0N)?+jjo`MJ5ICn9Vs)%IW5E-)kYT6JXmimXQOG z(kd1#^+0RpPmxNJT)z_u`9vN@qzBuc{5l3>VpBaX=m~$!lpY+QTj`emR8(z92}8gU4v1 zG;-+!+DRq4fV$6L(RL`5&Wzp&Ewqi;hqd1e`UQB3*w1CUs2{{HWMX)3U3zHH7Sq2e+=gFip zXMa4N*g5mz0~yc;WOBKUnYlSNJ89pWwj@zlC5Th#wSKdqo(<1WF{8U^H0xpWnOvY0 z?YZ@-n&pb*cIEj}Dz5fYF}o<5roZ+6{$@J3b>ZJKwYOO{rqW<8!#PVG`W-S?_%zlI;Kql^pg zw)~iDMI$RKiy|hIa}VmCwr$`$lg&!aryPM$D|;O>X`}HltBDPgE%puL($mKTMp=1= zs5Imn2?sBu$IsO|tao>#2u8Wn4l)UMha3S}Oov30Wl&|?u-l)Sn$PTk5mHO~SEj^t z18&4fCY;9XIbsni`p$7j(3GPW&*zMcFrXs8H-1ZATk5xQzy9G+K-y2N9e=dZ@ss&b z)%aw}X}X(hvv4ezac%?ae?$Z-d(Cw-?8$N)`d3yAg)1&yj_8*qno?QNK~d)%+0D&a9>p`>wo;2wNzPkDvH!^?e>!aa75V&%k-Hj?qwp z7xkzph11pOI6Y%FwI7A~Dfg5VNg}*0on!1Mu)+Bvl>3p-#z1W8w#&M0A#VQZ6TV9-SgDPRFz=`i+i;C6%~7G)J(XM8zm}-bDT)MYl_+U-6^|I#y@u*7z4D7gyT(H}Sy*O8g3wD-o)6gQS|_I?iOei0BA+tS}Le%bpItL;B2G|vB(4zQV zM9JqgeOedff9Te)=|^#U3pn)a)4O;l9kFrSfciTnbQ%H>=+jk*aU-69iB2E< zHK6jcDKl;lw~Btm+d?Wqo2C#6K0eQFLalA??n+}=Wr zRf=V8+YT|r+W}D>ye#|zo&a<%Ye|*aec#b?k}X5v$=iK#+kDF#XLpTzUzwjVOxE~# zJuPJaZGtEz^r7gPJzo(=%hdo^#6HCw;0Ng*f4CMAQ4F`b8aL+lhF4K;7^pv+E-)Q1 z$&oyss6Wd}1Cu4WVMlTNw6mK30L3}N30l1{KS{n8w{17!MoO^Rijy;AjwFj)-*RH= z6Cj4@yX>h0I)M%~5eoFRKL2^-E^?V9o@gphB)HWLT6!#5r8cg2m2~JC#_8&zPzgm7 zBL@98B7n%2lg*gzwOpG;QXN7Ifg5mB?jGPQShEDQ8Sr&KcII(S0;7k0k}D zt_oh#vES>_Ybn|)?W-AkW_F!OhWB3yHuzBB#h+J->hJ2>4~t@d)!lJdG86yo@^8TQ z?tqjSJi;!5JDGJ5wNr8T17RTY;Ph(@J04(y`b5vx<5JLAU`iGUQ%)0V<81pYj}^Z!2DMaI34_zVGRFtz;Czwx0H)+H zn#eHIx~sP391!ibyR6jRi?ZYWQrQVO zO$V)uQ3L@8iKc>2FfzEI^zj}OCn&k@fV~@QjY^>7#=C<@*D7x32J%-GvBbO`o#0PW;r zlNG)2%fqP3Bu3so7xFyUH};UBWm((x>|b*VuRzei6+O{4{kc&JO0>mv@C!pkP}e^l zZS`3RDHQ@TL(tPAATt~WCri3~=9Z1cwaz1I$R?6_z$lRVH_|%20+&-1Ln-?C-5kYf z;cF84KUeW9Zg~bq`?>OD^HTU%By-RkCU=>!d4GDwx7o8V=$orD`+mz5T95?A3bI$1^fe#?d;yzdYLYryUNsb&49c3b?-L6ySlIj8kGmu_I)#LZ4cTD$lgJaUEQy@TvNGvmJ0)3l<$A4 z_D;#m1>Mu#oi}Z5vU3TKe@`}}wVjWoOjoiAelWAmdqcdUlSbxLRL`dw-nlgDuG?h`=P zshY<7mWOP4zSg0PS$yt_<1MBG%oZV*|Hzok=)hdq8IS9&toELVa=;mEDHi-N!fcmD zDW$3!zO?2YR*G~UTbTYaaDJq@2UuQs=Q}qD37N2j0!GJeEv`+y%oL}ruxjLAEpJ(W%s3$X06%?? zlK!5x)}l1=>a4SYQT^dZ9TlJM|GIE+iwFKGOwBsMDVnXejcL%%ki;yqe1nNh2E2yf z`D{QF=qRVoy0BsOd53TM*pWp4X~EDdzqr_X{ipmh(> z=fdGi%P^iiTo|>Qbw z1JaI&NIAmqOOV3%7S>mvq%h3SBPjr|mOluI9XtGJS%~ItlX)q_1b!hxcGUj$6!*?M zQ`-IVm(I5lfEj61-OyL!xk)5O$egeYOr&OJiaJJu zE`y@C39k1_U__b$8DupVXcraQAcN@In>{2A7)nwN{lPdkAY&X z&Y+zvf4Nme0(G~|RZI->TiyPP-|ES%qcQ3cqJc>|HF__VA=_HH_&DJSZja_LkkHo` z+SI2x%-rLb##>T8h9(J{H=?Zy76u24TA3P%V?gx*)r1vnqPNnMxHwHNzUy!mSr(z( z(9>h`xUG|HXXzm&cqc~c=3P*|W{bp4kIL@6&_x(dDuF6;AUD}4nE|U! zcBgnrBw82Ju*7pHr2t<@^UyrrkKE!va6@81lqvfb!UC4r8j^Se&B?03xv5+>#2RJF zy7v`<%I&pSB0tqv7j8*)2)gOSN6tFlZs~-Ibq{n~$-ANBaor4L6jyfBG-{|G?ejxr z4E#WeFXSkf^=P^rZUE0V7ojY$*H}xX2kw5Jdv2v+QgEe-i}&h~Bl8%GzWC zlB6hNRCmkq2<8$MA$vO#?E(+F=K(ZJ^I!tsHJYTA%iBp)4u*~IZq}4y$)Dz zaJcZ1`GAFqk&u5#VSntK@qe>#(zLKgsp{$*N;xI<8e2_~J=Vc9mDHwW!@vKnDd@~^ z{2n;x;x#Q6Jv3x8(FXEXvRDth61U)ZerjWT`%90qItBSMHrAlWt~96UMSgm;Q1ZJw z{W4Pt6qHIn#3C>0?Fs#LIbQ9w#q_#3oXPspSg(fzoJ zFPAG8&KQE?INTvuY;~fIXToRi3sW9?7MAnOWtS5p@QaJB!>s>t)^-tYou3d3=~x&R z4mIs+nuWm#vG6e>8ILzin-EvXp4~5r{pZ-?qoW6)%L1P_(~{jSLC>45!0Hgnk$%9} zz(7tCtCBD4B~?%J9&Jhq$9$GG7Xua8^o(men_x6^%;|Bk^@%1A& zM^`Wwys<(+v(ntoMo<0H5-W6K?|Ku?V{Z~y1|*{JCz^q2_+P~}%%S<05*A3jZsde( zPPgOOOuyMblSYd7@?$_<@-n&93qsOPe}!adM=SoWwS4h3rOu$*AT>n@*srN?WAjj8Rou+>L+J*Zd;{SBg#)@2p z1=@tJ1ec7TrmyMP;|N)bAeYEA#JMK3TYt2m-bGP1n5zM7(Q3TOuQk2Gr@+XzDed0J zQGpM;+OullqX+eA_#?N%F}BPOElz70aV38Khs?)qE5HLuCKAsSj0`A<2WQlg!lPXD z2Afw>sAe`Sbj#p(->=$M@A>lBqauCF;&kAZBC{g9XHvyx#+V~g-JfZ)>^3aheW)Ia z`3AkMDb?q)IHe2zS2YVQw5P4?v0hsN1YD#?wzi5`$X&jO;hCc{f&OcBzyAq;6gxy+vTKkZRvjOpeo!) zy&WPo%a>wG6{~=%8_F&nko++Rh=#f)1#I5tB||NQFLw6ydre#TX&Nuc42jpk1)U&D zH~*JWoHQbupdyn1c)vHi>l`lSA?=M#>JEX)>gtRH!oobOBR(2PFdv)jn#l|LIg%q{ zohxpy6$m0N6sawBQ1Z9LZfLy+S4dVtH19vO1_CFbpXv$oULJUX7}^z$YeLuQ0}&|c z`l4c?w9=UgYq3j#rvLGdAEOn7rgCKa&#%4`rB;SoMcHci&pS6gyaJxxi1OU+t=e>% zFQZ`EdUjzttJ2o`uOc5dE{^TM2Jf%*BQoCWx382cQo;5=QcaB2rrXI8x z9rz8}G6t1WRhzepZq3zzH+9|n(Z{4PGSaF#oj2+@!fsYrQss@;M*>YV{#33vHY?Y9 zb=kEyH_Csy5gg!Pv3VC9Ip4hwL?Aqnjc-@)Gh)? zGsBaDCosAD@AG4?8S*b5$Pjq1G;r-w``)L0oFNqtZqCg7m=gbba?<1DVJ0_WB0l_U z7qW5YhZbM);9-^zTBD^rlE17Je1&74QvX%GGR>QdCKBXslq<3GVARsvz{1pal5*Vx zw7C*qva!aZ&9yF?9rSHTZH+prUd{dMhkeO5Z>~t)mvp#{DFq)cClf+0j`WSdDxiAU zlKVu0uPG1E9EiGJ;y)ax=5kJH6*MVW%f1pGszPBuQ~%vp6Y5(2K_(?0mBloU5kZyx zjn<$(`m|Hd%_)xTlW|H-Dn+Ia>x#|_V~$M?{DM4R%)Z?23f`kKRntlEt7v?JE73uH zf9SVgxNH%+7qw3mgAid95^`=?7%&umf1ulSyRHy>Ru>)Z-zY3RxG5ISz*nFrVCv;b zn(P4R$(XS6Q~Jh-Y%T}H0!5}!`<&X{51~Wqy<$>QS=t}6kNLa5AmryibV{i@T9!+? zb|2j)Uqdhed#udKS3{_SVl_hg`bbP%JUStvR9AP_X+4HU#}3U%b6r(>dh6 zB0gYj1chxBTpv6ejW_>Tjj*n``IE4)Z%N{~3S*IND5GVXo-D=BvV87rfL^wUgajY( zwn$3KP5;1RZ!C6%!8tg10=|VMc&#WYJ=SQO>)FPYxL3=!I`%E<@_+i2P3=>+z-f30 zop^Qqz>_gox#{mv;LbEcn`AB}&6Rd^bSQB4tnZGEXOE61Mvdfd!=XdQg{=MYiQC^y zP1C>F75g1!@)e~kWMzsyWX{c!AdYc5n7W1rKYuf{uv_4bGNVqtBr46kK&!N%fV6ZE zt;1@h|KW~9dsTP0Uhdnc>^E?UPwNpd9b?hL_@h&fZVv8ofvNs`8SBKGz*ZK(On|A&{;hS%X$RNF@nU%?; znHfZEWuou3fh&>oA!+CJ1eo$>`#dSFT;U1P9{AlW%G|R3eKNCbFb(Ramr_iqOV zjDIq&`1U2pu!YfywZLkh(E1bCve}=o*%$Ibc7U-Qg}->Sz%>+X?|RE|#OVCK@^D1jH7hlYoDEgU-aeoEoVT_?u9`s(b964Kq%qacuztdz04hVpsS4}W8M zjPr@KD$t8ncs5T^H^?%9w5-fvwi0nbZ-kET_*bML=_!Y>XR+s z4{xfg6SRISy94fYuTQL?9x)hU$cN_q%m*S=#-Mu~GIf9V6{f}IDJyO)TK-g2^au8M zc!H+^*Xfk}^Fb?j;E*evmVU~l-0V@$K>N_1HL4W0)> z;c^%!w+e5lWr>ff!e3B?1^4uUV(Gd}-LTnWmbaLU+I>-L{!cMFE&^5ruReQQWs>v)~s;ZDhgt83StS*Z0%0nlO%e61K@@D-)ch!jyXOwK28D$9m2+I=umvSm zUYE*uP1a1@)55T@plGb;a0ZSr0V~97X!W z3(cba6xr7F8{y$a_dQ;eG?|eSyn8+8!lKR2t+jgzs;F0VO(|mmO!PM_YFJ6pv znxNaZX&GYT^Gjfw89y9xO-l6|EP@})+$iJ>`RDLEG=zkx> z$qAu%XU-|)N573O33NK?Vk9a~CNaqVcu?S{Rzkt9t-3gU{c2z4|BQsbH0`uc!< z;!e)a>S}6VdRktJf{fi9Nl=_Gb^E_ad+VsEyDolI1w}25?pDMd;eM7pG#QE7=GgrNo`2N=3*;GXXcKJW89@B6#=u6x&Vx%|U5-xK@nvp=8D zK6}@Q^BV5mimw>Xh<-^jY4gK!V7_zqW)_lp>^0a~-eWJNqz(&Gx2S*?F>6YhT1-|hP_(sTk@`mx#9oh7k43Ih;JF8)= z#4E8^jGm4)72LU2_4IcDN~iTovMc?mJgxUNilobxx@9@HW{at?t^UJJp{+`nChQ)! z^Ec7@tzi~k25x#qRbK%92;7(qyzOx?p2pb_P>mg6LiA}a=lV_I0`rAn+PW1a&zI@L zgQdfOhNpB@4UHUCE(TORm}e7_xY<;B>`WOA$qFa2x|b=Fhzw@~RyJisLaJ;kroiyiXW-Tj z=;|z2th+3q*_@%v5A+YjncRG7!Bfpgpi_(%XVBelIxBaQE;`l`L1E#+;bA>(?G?1t z!uaqo{rQ?+;Ud(h*1UF}?d#8+oVFSQsn^!l4nA^$ zL|1OFOROWN?O(w4Ir!Wel^#uTHCV>%#fwKU-@B3~DWTF|b_O5y=uRfB^*k=z zI(6a|%H9TLDQJ)$i0OM?braNCrIjU@6|kpkubi;^VjS!|vAleHMiJ@R8s`3i{#EpT zd0jhmZ0n71)po~ADG z{Vj^3G%j15$~O!hDi_I*CfWED_Jm=1*zcEm zdN2N9C39+HLoVWH+{cshCkFeF4@ByVjP13GXuzL1B(x`I5Nr1QqgfRdDL zNcPW}5#AaR6c~{! zt4VYK3`?3aE?O&S9)IQuDuripi5x2l3~VTO414|?3@Ge1h>|R;HnMri(49zjdddtl zFrfR%444A`x^jy$lKw_Y=*k>w&YFTg-tjoVilOAoWX1cRVimv_s zP6-x~KU)1ru=sHA`}YcqKKZlwsn_AA-kjb&od_#qT&6VVEu69iX~P^5mbrO(pf&YA zsCaOp{9vVtv6FZI_2?M+Hr)YbhYwHd)Uy;Db@xYg@1NcA7zq*a9(;C(yvGu7POL-0 zxvZpMAwnH_G-4!0DR{RkMUqTee&#puzTBqy)iFFACl6C=e0(i#=ny*}#Mko!2XlXa z#o5Ehoe~KJuyAh*oFNJ!U%U`Ky0@!~N1_$Tu!foNjXP!Xpv@NWv z!dU&LEc7ft_hqLfa1UN&tb#u*bba8k^xT_27*NizLgX`3kR3*!)|b%p6I?m<`f0FC zmR<+d*(kYGuImY~$KRrV&n;_SIFK%dv8RoKwoa|##-Z*XFIkouj0uC4pgs*&Le_wl zL8BN-MeKqC*e+09l*UV+C zZEZiAF1Vu(k`tAjF4(yy$y9f_p1d>bGTV3S?O|8Emj`N%yS4S*G7Y4?2irOLy=b4A zuOTUYg*s9G6)+8N>I~BTgOKlhD|zqQ+&5cv^$bqa<{RlB9rdpV)$Yr%b&DeOU&h83 zhAZq?3%R=Y2P?3njAGB)C;v8##&nJByMkj@;DFwOZ;En>R;0ZZ(2<+@lGWSPMcgan zLjN`&;Q#CPu3LN}ZX4iqIO(f=!+5^G$OzTov*TY_n zL+`D*tDsQcGn)pjzx%=j1E;?C-S_vU9u&fWN_=}eh%HE*raW=ImsL;a$;2H7w;$|*yb zUG32;V^4!a)tGZUXP)l+g|z$r$PJJM>QvvGBQ7py*7sIGQBl#XWN>E26d}fa z&l_%5l_ZWvaxNZr{A0=FML>?klr1paWBVUHI-$4q|tlKM3=!$ z)!qHE_LQ%8hs@Q$CuNt)%>{V#1AVGMK#|!!=HS7lkil>|rliq?2AscB*N~T^OO9EF zzNG#ID*gbY|F8MEzjCaK{0`I66B+3rVR-eM!?K(Kfk|>YJ((b8XRKn9X}`8(cdn|T zPP*zH*3qV#lYvtQ1f&F`81|bA87#=tF%C`Whu~W>xfsS5w$4rBM&&*`hh?9;zP^v!ObvmwxENnafEvA9i%?-RS<$0YhR8T|0do3*S{d*H@ z>ebZW%gbN2+J5(Q@LLYFui1Vwpr$R$X);LnS#sD6x1WSjJm{fY!hXI0xg501JFnVV z`q$;Ge*4+-#P&NSc6;#ATCsnwb>|MP$NMRR=AUV$&{9+ z<&(CH76a>iWP6(8W91r>GpxADE?16vmF0aQaQz|h?H;F814E)OFJ=l^ZsJ!g83lRP zJzpa2e>xSyG3}y}=)1*`JLzm|6Btx*5D4z=o}5HR$ezsRv&VziOwa5YpD9NWe}Hf* zw1$MVH5WfSVmV=eyOY=^#Y1vvp1Ut*0^7V07#klKcRzt90S4s=aC3A{A@kV9nQlZ_ zin-RuwEWEn1U<2{BR`1B&B?+2cYxgzq5#Pnku~@stw865`t#>5@-LmeL4B29IxqQ$ z6xw{GH-$yn%NX3^PyN8;aLl%~4Zq}f8?9gAyBdr@#i&mN@9gYs8VO0AM&uhYWPX@N zb}Sqo?DCnj_~U77WhlOQRaaM6FX6;+=87m>BS4@J$)(O_m!(n{D`SzPcQ6gQ7rj0I z><$ioCJmmaG+*dD+v>kuLqchOH0@Y9;m%e3s7&E)o{#v_UeB6F}#M6$vV zc%2k+S57L{bGsMNo6#c#Vxql2hmMymmmnC83s4 z*}?*|HOXJ>UiYFyUbwv|*AP`>r)gsXe8RjhPypx4qQ-W*IQSAE>TPoX?6lcBVS7X#F@8xPiuBgvFJ^{|@0DMQ zU)X~?y)|i{ISP96LF_e6{%nFH^lo7AU2JZ7eazTFwmtJ+#KT5fv|F9BMUf&i}vj^Y$^)EEd0nDO`9328m&qO>6Oz$5*?j*pyBEuG;qpu&FUqQrc zKx9T69KJNv)bwt4me)OE#?15xLb`y+iTa50KZ0pY5ShI)LzZg%af21ndJ|ksH&~q5 zVGvNm=Iu$Tw@o6g^#Kc6a!>=OnQ}riIne*GE zKO)cq{QSj-qUSE>6F{Jlgw%>3u(P>9!3*S&GzYY5@vwfCuHLmG+Vhe9M;L9)01Y^P z5Nh7Tll&Qtv|>fZJEZD+R{{!!$IB)r?iZM%4wg`?+Z zJ?#$wG8*(^I2DZafiPf#XKk(L&Da{XT#X4U6M_QQlHE%>7=!M+bpJ~e3vY$t)IVvV zH#gv$Fw9vq&`wu`+k;G68?`btV(_CBJ9;%AP_K~CLZpP7{EnJVn;v+kGCvR^Umc1- zd+jZh37QckuLvuN@Ht#>?gfH%YwH;V?ac^FP7aPt&hv!mI#`6PfGAg0b)3a$P}0Pw zm@7xifIROOe;nEi&@3tHNc`z?lc=7k0~6DHiClm=Sh<@KAsHh^)KY zgM&xaj11ARz@B;*mO+oyo>_^5Z7G=fX~-A?8|1$r;4WdN|HhJ%+eF7DikH!eUOygh z(~J8c#$aP~f<=0q{FgNwIP=CH6g)H*xXfNatNXqtj|;a&0P_7AobG7Ob1QQjb6-+W z_XG4Yy-zaY5yJ*(zM{Tq`^fo2POq=fVrj2QzJNB0+2A#%e@F*44FQd_)dlH)oF) z>^qJSd$%}XauCwL;G95REQE~Ks}5C6hwviInsj$}fA{xqcj**cA>A8#oDsF*&R6)4 zn?$yr+|CxT`V3dSkf(a2;pV@!E7}SAD zh|)Gte2sXWdbCo1Sy*VxIdZeo=^cm1zZW+@OFPZc6FPX(8=QQVR+la5F>okmJQZ+c z=#qAmkkTz}?Bz8|DkQA3#AJ8?hk@)D04gt?aI=5hWoCXRo>mN7U2?@HOUHxGYn1Wr z3=lEQrN>7`GY7P}tGb@N1K^JtfIsF52To8oRln+9Mzq;M$?EQy)`cl#p?Z?{$WXRq zui5ybKHy?4&SI$JZl#_k`7Xg->qm*4_rVagCtjXHo%(#WoX)^-W3C5V-Wm& zfD(E|?|_G&aMi%TKbrRy9Q6We-ov$Gir}l*Wm?~G*ex}m&#qh9k`ZSY0L8oqzd93f zt8cz8=44I!s#v@QfS+mYP%J{WMZTvGlkgcR$v{fR>}{^tJact5G@jO- zV;fkvuk@(fmGNym5^=8qJ%G>!Qc-PP;(*G2fD|CQ3fIUx(V|}hJGq;9_dJ}0M<4WysX5eJTEhLIhUW?dsBEW ziLdo4fmlG^U4jU_s4jLLL}W9YkaA7RV0h-QYh^zBLN|$qXRh{1l?pTEle=4R|19-5 z?5KIkB>d20Koa+LOD!IAk{?vsCzY8;Z6w{!wo%|h(o6yid?F* z+66PCo1049JK7Q&H%0$nsK)EV0k__MpwOMZD`V)H3p=S&mJT}^0Im=in_;jWoatv?a}5qO>2KD~jB>i&?36STIFVBrE7q{kwyhSbzn9UUW|V%P#U`p3|} zeo=0JDJhcQOspDPudr>v3$mr=jhBFA&u}b!74zxPZVW*Sq1KC$+nZ@!v4ru_2|ftCsRN8~GwtG0zY z9zi$cA>|n$gNos=EoZKdd4F^lUzn=Yqjjucl=+k0c&SjR~uK;YS3<7z&)^9J+9{0RS7R*I{Vwzl>e7YV(aBU&)H8c<=u08lk< zqo^u@H~mahVPUYVU;yR|{5*DL1J{;?)pAOp?}KJtnk>)Vz?c={6Al1KVUrpQM$kiY zJCJslH`;kuF(9tfp*%gCCB1Ox+I0P|AUtsnap%fMJ1kqFN1{C{&o{DMO*hTC=4?O& zUK%UoP;5a#b;+PbX{>WH#UBatvUe5+X~!Q0+MQKwY;=X(_Wg414Fv7d0tJ365@|bj z!m~z}V%n3VqpdpY$Mj1w#5T_fhW@XlC|i5`;-VruTifn6SnotIp)*O0plCkG@Yn^~ z`&S*QbO_mch*pg~tw7z^3Ym9s*0K}>X&&D&d9boF-Y)UAO6)f-DP{;q1L7_N8CKNS z7v_sPrvBggP%!!8ktkYiUER7lhScc)h@dxOP#>)Sj~Xaj5a~&ZwSrcqhZA;X#=XwZ zy}aNW*&FV+J;2Z_D!}t3;_WkV|FRTu#JnA1AQaTLpx_dBfP$i05R?IRanLIb14#hM%n^ zsxS}evHcNC(Rvf04ySb^IsrhV^92E?hgXHgLG~jZJ-tG40jRXo9kP$j<4YAY+HpM64~Bk#=I;MuG<2Z=cJM- zHP78yb^rj`W}b?+Y<}8B8$5sr*2PPmn^RFyFK^9yGrVh1Tj6bjNE<+eJfjQ^vAr{l z6#j@wa{G)J)>~f-DaGC>$d>F^j?56-)wtdjglC5#>pO$DK1*gQ**6&}6Ltl(nnWlg zFUB3`lnK)XwD{9H&&B_#x)KpN8&H!{Lje7F|I6ofc^^AQMywy&2J7vM28!S*tNP%a z6s78lidp0bC*8O9B9or11IU4$wpw0K%F`l0SIys#GyTuOtjcsM$0mc0bzS9&}~?l%1r85z0GcZtxR|FSk=6_8%5l3nzH4hwWh%BKQuKykjtUD3$y znb1I=C{=G@$ zGEf>ocBn+frUZpm-y4K1G3yODRSOBB@-9Nw9!QX{J(>0VS$<9x03k(P)mvNAq(V>f zYbe(4B{&7WSrs(4ul8nz}|Ah)~mRBbvcSi zj}thp5fIb!e!m@nHoMVpDZA}hl+2s#%4FJiInfBRlku9I&9bkr4BF2E#>=$ET2b}n zmA8faY##zaY;~k=5mexkHOGJKZe7O1i60(a$IIF#f;47S|yb> zrAVx#cpggA5DZ4A%+Xa?3<$6<%bY0leIrebYvU6-%JOA~OuuMoYDREndU@+~(jhI` z&V2#Vtt=FkJS`KCWGQ~H6+@YF!UZCD;o$>yR0rMh^lJ(A`{sho8S$<)3gZsHxn_T_4;%CT?w0Pxh zk*X4kid5{tB$db-k?2_Ri!cVVb4~-${bje1K&h%+E67|x=+ua%1um;`rc@U$OKwBr z(cZ1>lLfpT$g!)3H|^M4B{B!Jpjtgk^?_)fNuf>omgVP(5>ke9BL5y!o!FbtMt&sl zFQbZEB+27zNgQ8|#?SBU>(F5^Q6Lqn*No2SX%gWK+lksQhYIb7U)M@K6kr zKPxLM3kr@OobtgidhH)qsQYict>Fal_9tt7vX1 zFfp8saYNB7@ot%m$4su7XR%#qSN9zRs*~Wqw+vQc3-+whHe=2F&>1VdGNU~Ho#5?A zlhr7L|I$Mio^$vS>?~I0*B*+WM1PBxwHXAy#^{@pmgL9JhKK}5xv#*m*&x_vB{0`b z*g%#^bMT(*MX3--vTgx~O7pzgSm3PQf38Iz4W6;>xMb7l0=l{V%Rj!#Tvh)o@fwlO z`dj|=&hLDt{Xh%2mOR|+aKtxcgbVU{0_d=1t-n@XLD`W65Vm;Wqy_ymu1YtWQZ z2VBwBpmO8vxR*T|2HUD`TeZF7E`uH_vwD8%8!yPiu0ej+_^Nx1x(|q+)&MGfSP`~S ziekAD@~~YWk>AA&$#>dA9PupKCzQqEj*z1~k57k?%#Kck$mM!k9gKfEB&`NN*jXDJ zds?FNk|VjNDt}-g8$7BFuhAhk&3)*8H4pWps2+tn^;>Vw=T_6Bwl)I$`mquHpRsT|nW4h@$7z3)wD=?T$_S*O3vh98Q8ZCfZqw z1uibG2nfBlHut@`-dk@L)%R(1{5I3mdpe^=tx`g>keIV#o3S{oOZyK8*Mr$r!6#Cn z4t2Ec;H%~|Tdind3$OQJ@Bhndj8?mZK_+N89^AYS>gp-8ljP@03-qFj=U_Rxxs-u4 zGs^ZgB@s6w^ageE)GANLfJw&REd-OK1e2_+$%Cc76ZEe&o?X#aFKS=%PgjA?U$%k1 zzQ-~X=AVW)upQTKd{f8xlsD)m@E^g|T<8C*;5rls^X11KuqfFw1~J?Ge;9^^d+Cm6 z(|Xj0{oUD~Uz3y6L_|b`3K%T?I!LEKULysv$Un^$-ou`N(whmZX2&a0*42vC$lN1k zS2w0pWZX=HG4VQ|Zmk5hI_2BxEaErw806x=eO(+3COri@aVonAvBjd$Dkp~ANKNEx+nhTmfdN}~&9_4K`L(UqSz&eD|?sMj;|D;oW_B@BYCRjz=P7a?1o%5RNZLA4cv7`6-F)%Vny z*xCv4#60->gE=nizV?$T4wU`>l0{2J;eLz>50p;+s5OJ1y+(4ez5lQ8e8MN!gOteT zd~jAwZ_QkB(XTOhoX#~MdfywD2OQx)1tngB+*yiV48R{CH59LCVQ`s>1nftdibdF+ z4G8`=QEu<-+-|nFxAPl~mY)}GoThEpKOhbux zsNioYe00jivbxfkUdCMrI>p?>0D)byw_l4vm6id@%`MT0ZFeNMLNdA0GeiPTSdn1N zp)b4Cxk}I5;E2}IVYnA{!CiJR&x0`{wJMO3jM90!bD{Q6ax#z|?H;9jT-Mq1$)|bY zzSw7BSG|I8we1*mwf#z)WY&n!_5;s?zQ=*+ZeV(kz6Ulq5+$d7ATIMSQFCboNRNHy zsV;w|X){-MtbSCqzQd@?bEG&nLeCr!J81We`nGchl&6=nq$x8@+TP{Rkp8u3cK=y4 z8FMk8laq@DHI`6jYynwzdclikiAbA4xcm6dJdr(DiJ>J4G z!<_rFk8$-%g;Y`diVV^<;i{=R(-&~zB_$kZtu?-e4|~AhL1w_tU)GM^!A|vfUY`ZY zg6nBEL%uiiwCEIBB+5+W;%No^Ru=q%-#88p(Wb2mgRg?4%2taMQtp1iA-}t|5G%_w zw>_LUFzuXz^bCIpzJtB-hd?-vkBb3>djX=EqV_G3G`P1FaN##1@>F?)M+`wXm;Iei z5Ig#lGIr8N5xEkb2SDy2?xn`ih`3jY-%rfxuRo!O0)P>_b)6p3x?5(&*51G7+P&YCELlOO+^h4Q!) z8YF-ZXaOIuGY)WJ$0DJ4pkPIV(=zYNQ{q0o@czU6Oqxc3Y_I1ilhaqxp zGg}g1q|(xk!*njrX%mxtMTM!r23}LY#AOlp!g4JO-VTHh4@c&ISid^}<8J{HDqBukCM1%l*7MD94t}IpZoa(FM^Yb#c@DdLJXv@6o}lpQOT)w!w#;iM(pB#g_(?mSSU*KL z>utpp%v>Jq?kcxTrb4SU@gpL6ZuB)W*I2Ht`qNUbTrDw>3Gr9odGPRQWC=@t{>ScobDrQv>SUdu}g}K|Lb4umafE zo{ERawdq;;fK5^f!x^XN(G{OOIn8#f$MxbkHe{5flJGE$~bb?r&OF0Y8F+aZ_ z*}u1U2H8HRO%ZBlgVI}?BE~h~^Q%AKMSQYQF*s1$Wa3wStiZ>P6AMKW@y}+rh3D8m zbgQfC!@NAEI^u^gn8VW|q4&`F`T2-8LCw6Ggo;;1r+()U31XOyO?o$XhS|j$k>6OG zM**Mz(!%02_%z!<=}@MDC3t9-)hnO7`N58LS3>GK(ri>S`^|w70j{;+rHi1?HdC`O zpPx~DuqyfEgona`IT9}X@z0jFg}d36wzJc8&c68pngk;{9k9`WpmP_`e>r`&gIy!V zhbPYexXH_fwT30X+qI{}?;b3MuMG_i-RqSLmn}6nU#vK{WPdUBqiR0V#pzvY_uK|0 zTZNZ^%b}Jod0^~0X!5kgVDeqK$#-{$ClyKV%|A}p606lnJbBixS8WyKTpg}P!RZ(o z{WG2ks)3H5&q{PChf-{;;t2^{)Z&@bI{~x#369+PX%t=5CJ3n$Ua6 zd%3HuD7n@(WhGp8Xs}ZJYu=PmL3zuQhr<_Y$e1v{PJeXZS5#1AD?1r~a?r#}_AEEXH2gC*V9m#G~tSZF=7;7zMYy*Mxo#*Ri9&Ev(HP z4dWtcN>S~xr}4!#I_K(8Lj!G{3U=~ZmxT)a2HM35iA45}tS(n;@4EBFK4N>RB^?;} z%qHynhjM0D>brd}nuTf8Sr$QI>lyY=@x7j#EL#Gv-sejpP6St(Rnmj9o4m2@mM>ox z=p&di+_T=8gUzV(#%;w!96>SSF3tc6LAeHym2vlrDHwt-vOT1I$Jh6M)q)yZ!?Tr2 zGzXzps**Ksmm|xVQ}1(4YE#Sg4G8kx)#Nx@8c-HSC%3QPj-nA+^L(BC0;QM* z)eQV_uWx@pSj(|4IuX7BJLJo~ZFdsa$~LOe<^CSsTvf794R<>=u{_g5FVMNreScf| z%dQq2o`#UCidX43dhZ#yt9-W-bo9h;3T{QZGtb;L@!1@3;;(>{8M&iGM&J^YN@K4wcT;lqgQ0is?kdrMV)tL zw)O-5$$cQMLB}%;s#9ldY-|AcXtKFpYuZf1_Iz9;@X z|3nA$MXqF?Mx=Ly_a1C%ejf5iW=_PPs?glkJ&&BWRJ6%J*6Mri%g}_AYn>J}w6U~JA zH(5}Wnl0k&YD}rl#>G^SNM1aoc=(`7r@hx~)PKla{2Y9VFLCzpTj|grLqC4EFY^vN z#v(2zLv5NcK6Mjb8@R$pAMO(y%drzk@_l-mMLW2hP_XD2{xkKs&wM-ZL%09av74+J zyNVC4`#7L1mI}!Kmt*h#_~$TRf;kD#>MV$ykD`mzSs43j67ak2ble8`gx)EWp#0;v zj_=VnjPoVWU6Rm+7S{^7 ziv-b7dn(gJ>?}o4zTEW(i)Vswd{EB}XPhB5k-=ROW88wz-Op=*Gnk>4R+l$S`_*;x zN=uQ7kZ#EK&YD_?l%FTg#~|<`z0RU@77^U&u-+a6Bj=cJv0b zYqDftW>+G#!=R0A8A1$QzDs-S)`XjD_XH*^?DfPKXX?d?H^X$SD0nn|+;#6F1~36k z{GHlUIfV08bPPX5-`rT;A45fPDGV4bH4vL82=cL69$c+b(Ps5l?vmOQ-@zP&*O-p1YG``>M7IwbQkI!p7O`xI*|a%^Xp!F{P~r*}Xpv%O@HGqHWfkSSebBHQIt0 z3Kh@)tlZhTxt4BU`M&tNTbWhniyM8L6{7=_2Yxf#m${hUp1_&BbzhxT$0ZoS!ul>P zD&iQXTAGJybEeDp!Fwti;>pi?2a!USIhSY!yqxYGv6l(XRv(T|R zJf)#IZc@9s6IaxNJ>Rub@{)Ll^6`T1I%&r^IJf`#^(_I}R8h2|qr3J4jh%gm=S~B$ z37nTO#v;jwR}6tSH|dcUlTd+|Sy9i%BD!Zp)E-&LUV#PxKKHeT_whFi0S7_1M#u!HT1vzjmF)!0VGJlm)R#LvBt9py0T z5C;FiFN|(kTYSun*IMP_??k_6W{F(Fk3o`sX-)!q!iD&8!Z&R?yy5(U+(F@Pe7B0eU(s$>nG%%gBA9RJWCDE$Fs3?|h0;}=; z9wqsOHEHxadYF}kg=x7wXS3sr7iT-VaVz7S3az^V#V$yN265v`&Tea{1FH99zL=Zw zE~i^|wuHiCo`zro-SO!q#pY-Sy8eq|hVhrf9f*k=6=vwtj^c~X_(|Klazk?=2uO?>vHhmFPyS!zG9K$@$i-B zn#233GoY$2x1%(vcKWe~g^qahG=5nO_AQ=>!ZJY}v2!?xz*2=V137Zj0__4)b=h<42n= zteu9I-wT9Ebw;*#LHl8ff3D5_c`K##cwyx^(AvzHzW3pViWBx%qyFaSCI!l&iN-L8 ztbPXYs}xupo~LG4ew~kR(k}5}z|d)WU2V>C{XBsI{3&FWi4tCl-?SP2W;b%{2aSu1 z0~2optoCmj(f3O8?T!Xjds%^OkV!f|OIf{;@;ip{7o)DazSX_qiu?Kb@4s_?i4)mC z9!IzqG#q&jdS{$Cbi477)n4Z*g%`jRtx-8YD@(?TLU3p!zBZnI&vD=?I>Uw-VH807 znVJe13)Uvk$?V?3+c~;g50V)$=n3!&O!x7i!fV-#$K%s$2!oCEYov_jNZqkG;*Aa;UYPVhz)o%P&+LWF3VquIfnSIefe*TLu}=h((@=>7Q8tnUG1-c*?%a? zD0cODBfDtd;l)u{s`1q_s-}cbz-;)H&FqBV%t=D+^u~tr20lKrDJ3V8;ajIM7Peke z_U=brT#~BZFVOvCXLrvGjrI>#&IxML1~+c&TQ(WdZ}idzr>hP2^=A2EDmVf1ScmC509CE?^1;!9qFU1)!K8Ve?|T$F^&VedevlnmQtVk0Rl*Yq7q?C z;dGYr5bKVsZYP!FSRK7MF@22AtAs~>^T<1V*`oz*z#NA%)dE0kTG`)!0IS$s`7UOo z3%)+OPQELIg$euP1O4e`YxkYJ*aFKaF=V?;&=BapN(Rs$bjvq3Dh&N1oFMz*(uwkE zaCz1Q+F>3v8s;Wqfl~uRiSC@n8S-y8cez z&W|mmMF+V^ZQ7@yRh=s(rw(8=9iQ>Oy8-gu8rQ&`dEH(mxUpx2xHlvl3m)2Znc7En z(&!;qSA(G6=R(K?4+*lcf#GX`;Rm$~zf>g;dT<)8yaan-o6x_)hn2IL(04RAvCAGM zyYsKGB4>G1KseqW#MG2N*nG@7*^GS$vi#_9lvF8CPzA{`9)WuqLsaHS=9#>!acj++ zLIKdd2{Hx>&=22(H0)~)u(}2rpK~omCL|`z_?@=I#iHQ9fyCsJnC#x#!>K6PJvBxa zOokyFT&G=0zs7ZFAsozNhb#SlfbJzuBLJk8py2(JL%NMTXfvr6=L;GP4ni@-`u6VR zwJ||Wg##Ub5ZLt|8lLz^U^hquj^pU#^2J}%#&XFsU*Vu|#B8N@R#(2ONmGobsJp0@ z59C!uqizDP0$#Iayu9be8bTtQGIv={O_STj$Z0EQb8Be<@3<7+wUP<=<*1I^-Y2yo zZm7r!v@yH4^LCQ1(1T(^#fj{JdrvlTN6lU{EAh91VU9It^*kb7_y5Pw57P9FCXv_`eA)wzal=1Hcty-{ zP_0cq`5zY^x{z}-^W9e>-y)Sgx_W3c5&*{OHM0bD$roF(KD>kc`&tiiY<$qBiu#!4-lrj*h?x-hTT%!oT} zsW7V5Xd_3Ij_%e`Fea}>27<8@o_*NeY#UYKN%G%!M8(m~3v0K*$oAeZ*6r_Al_ z+sPP;++l?)8!eAM56DN#(jcm;Y7gEgi&T?l#&^IVFRt$=~PDPrnVYqiq)KGQ(f;BXrz?^6y@FwIy&Pla94vzwerPU#PCQ7pho)QzutL z_~q_U+NnmcJ4)9uT6cJkcE??|$;%x(Os`iTo$n!z#)X8eSLU~4t~`FJma<~+J~ojD zo;{d4IPgWaihJ%WS-Sem9v}|)4;q7KdwUZ<3y@heoQfM0Jtr7DLzm=X$$L4(&cU2` z!u)o^Z)`9Q&T?xa;vLqRV-onyqiXJr4HlUU+e|cmE8nRi4=|(`I3)ujcJD+7_<`B? z@Q{fwdnR3}Y02AzXgkPX0!k5!rkmS{ND3u&>{ZhNZDr8;NQ}b>Xq&h>@&1_({vC(#PibtyXMX4!9z1X z9@ht?LHVrF-q>K!umX)5&o^Mgh*}*?$*DRHxUF2dei6q#z(tbP`p!I2gJAqDLRdG= zUiNyr6By03r&l_(K`Fgv!D1%!+pb=R7UaAU4uf?tzB7*%Jj4W|FttMEdAp?(^TTnf zHw<-i(N9lO;3-!@(yN~6<%Koy(h6fd8{)mfSN`zZflO8W=U-FMIGT%4j^_r99~L)(pU`RD~8Ys0FnojO<*h|M>G&Bz1at1a;oWG^TTsFxhQ>u1bsbw zeSskq=+Oqzncb+0-kmkj^CC_iEIsgsv2j9!z?a>2JC&Bc!}5j2#-i4Q z!=#)4qNw!RAc~3*|JmR@JBP%=W@*=-SAM7;9)ve^a>j+*5∋?7(G{f=!wUOv|+= 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 Q(?8dJYYQ)>jQ7I70dXvvMgRZ+ diff --git a/README.md b/README.md index 9dab691..7624291 100644 --- a/README.md +++ b/README.md @@ -35,9 +35,9 @@ Python Programming and Data Analysis - [6.5. Flags](#65-flags) - [6.6. Module-Level re Methods](#66-module-level-re-methods) - [6.7. Look ahead & Look behind](#67-look-ahead-and-look-behind) -- [7. Numpy](./Readings/numpy.md) -- [8. Pandas](./Readings/pandas.md) -- [9. Matplotlib](./Readings/matplotlib.md) +- [7. Numpy](./readings/numpy.md) +- [8. Pandas](./readings/pandas.md) +- [9. Matplotlib](./readings/matplotlib.md) # 1. Basics ## 1.1. Naming Convention diff --git a/W1_Python_Basics/.DS_Store b/W1_Python_Basics/.DS_Store deleted file mode 100644 index 4a24e09d48d255db23d5067c605171411fd2a0ca..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 6148 zcmeHKK~BR!3>=ppin#Ow;!EG0g$d`>GA;Bu|$pmSck{=6In#Hb%SSH!`5_ z?hFM=++oA(>-`m2vOlM1gdy7xc*P3&b-6C`a-B1dn??r2w+|Cr-k>$tlv%gPanGDj zEtxNBnfn~QrLMWRmYi+bJ~Mf*#h)IGpEA>mGkUf?JLD>7STxrtm$gi`P&dwiGvEyT zVFq|+tMpDHx^)Je0cT*xfPNnWRWVCgMYK-`jggbn6T_1N#gd#cp5E|Euro|NS8E zIRnnXzhXeTlbgwyOG;;JV{v-c2I?(UMaNYUcOh)pQOvP=6rWQ~=nvW;W(li^^icdq Mz-Vye4E!hqpQklf1poj5 diff --git a/W1_Python_Basics/class_exercise_1.ipynb b/W1_Python_Basics/class_exercise_1.ipynb deleted file mode 100644 index 724277c..0000000 --- a/W1_Python_Basics/class_exercise_1.ipynb +++ /dev/null @@ -1,2637 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Python programming and Data Analysis\n", - "\n", - "## Class Exercise 1 -- Python Basics" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Basic data types" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "True\n" - ] - } - ], - "source": [ - "a = True\n", - "print(type(a))\n", - "print(a)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "20\n" - ] - } - ], - "source": [ - "a = 20\n", - "print(type(a))\n", - "print(a)" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "20.21\n" - ] - } - ], - "source": [ - "a = 20.21\n", - "print(type(a))\n", - "print(a)" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "the \"art\" of programming\n" - ] - } - ], - "source": [ - "a = 'the \"art\" of programming'\n", - "print(type(a))\n", - "print(a)" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'0b1'" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bin(True)" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'0b0'" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bin(False)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Type casting" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-1" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "int(-1.99)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2420279590275804445606588463955072096420804747701564608" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "int('thequickbrownfoxjumpsoverthelazydog', 36)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1.0" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "float('0.999999999999999999999999999999999999')" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-inf" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "float('-inf')" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'170141183460469231731687303715884105727'" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "str(170141183460469231731687303715884105727) # the 12th Mersenne prime" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'0.9876543210987654'" - ] - }, - "execution_count": 12, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "str(0.987654321098765432109876543210)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bool(-1)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 14, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "bool(0)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Binary representations" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'10000000000000000000000000000001'" - ] - }, - "execution_count": 15, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import bitstring\n", - "#i1 = bitstring.BitArray(int = 2147483649, length = 32) # this line gives you error because largest integer for signed 32 bits is 2147483647 = 2^31 - 1\n", - "i1 = bitstring.BitArray(uint = 2147483649, length = 32)\n", - "i1.bin" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'11111111'" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "i2 = bitstring.BitArray(int = -1, length = 8)\n", - "i2.bin" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'00111111100000000000000000000000'" - ] - }, - "execution_count": 17, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "f1 = bitstring.BitArray(float = 1.0, length = 32)\n", - "f1.bin" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'11000001100101000110000011001101'" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "f2 = bitstring.BitArray(float = -18.547265383, length = 32)\n", - "f2.bin" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'00000000000000000000000000000000'" - ] - }, - "execution_count": 19, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "f3 = bitstring.BitArray(float = 0.0, length = 32)\n", - "f3.bin" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'01111111100000000000000000000000'" - ] - }, - "execution_count": 20, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "f4 = bitstring.BitArray(float = float('inf'), length = 32)\n", - "f4.bin" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "@©®§ǖΣДЖ१२३€£¥円元圆圓\n", - "b'@\\xc2\\xa9\\xc2\\xae\\xc2\\xa7\\xc7\\x96\\xce\\xa3\\xd0\\x94\\xd0\\x96\\xe0\\xa5\\xa7\\xe0\\xa5\\xa8\\xe0\\xa5\\xa9\\xe2\\x82\\xac\\xc2\\xa3\\xc2\\xa5\\xe5\\x86\\x86\\xe5\\x85\\x83\\xe5\\x9c\\x86\\xe5\\x9c\\x93'\n" - ] - } - ], - "source": [ - "a = '@©®§ǖΣДЖ१२३€£¥円元圆圓'\n", - "print(a)\n", - "print(a.encode('utf-8'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "@ : b'@'
\n", - "© : b'\\xc2\\xa9'
\n", - "® : b'\\xc2\\xae'
\n", - "§ : b'\\xc2\\xa7'
\n", - "ǖ : b'\\xc7\\x96'
\n", - "Σ : b'\\xce\\xa3'
\n", - "Д : b'\\xd0\\x94'
\n", - "Ж : b'\\xd0\\x96'
\n", - "१ : b'\\xe0\\xa5\\xa7'
\n", - "२ : b'\\xe0\\xa5\\xa8'
\n", - "३ : b'\\xe0\\xa5\\xa9'
\n", - "€ : b'\\xe2\\x82\\xac'
\n", - "£ : b'\\xc2\\xa3'
\n", - "¥ : b'\\xc2\\xa5'
\n", - "円 : b'\\xe5\\x86\\x86'
\n", - "元 : b'\\xe5\\x85\\x83'
\n", - "圆 : b'\\xe5\\x9c\\x86'
\n", - "圓 : b'\\xe5\\x9c\\x93'" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "@©®§ǖΣДЖ१२३€£¥円元圆圓\n", - "b'@\\xc2\\xa9\\xc2\\xae\\xc2\\xa7\\xc7\\x96\\xce\\xa3\\xd0\\x94\\xd0\\x96\\xe0\\xa5\\xa7\\xe0\\xa5\\xa8\\xe0\\xa5\\xa9\\xe2\\x82\\xac\\xc2\\xa3\\xc2\\xa5\\xe5\\x86\\x86\\xe5\\x85\\x83\\xe5\\x9c\\x86\\xe5\\x9c\\x93'\n", - "@©®§ǖΣДЖ१२३€£¥円元圆圓\n", - "@©®§ǖΣДЖ१२३€£¥円å…", - "ƒåœ†åœ“\n" - ] - } - ], - "source": [ - "a1 = a.encode('utf-8')\n", - "a2 = a1.decode('utf-8')\n", - "a3 = a1.decode('iso-8859-1')\n", - "print(a)\n", - "print(a1)\n", - "print(a2)\n", - "print(a3)" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'01000000110000101010100111000010101011101100001010100111110001111001011011001110101000111101000010010100110100001001011011100000101001011010011111100000101001011010100011100000101001011010100111100010100000101010110011000010101000111100001010100101111001011000011010000110111001011000010110000011111001011001110010000110111001011001110010010011'" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s1 = bitstring.BitArray(bytes = a.encode('utf-8'))\n", - "s1.bin" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python operators" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Logical operators" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "not False" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 25, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "True and False" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 26, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "False or True" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Arithmetic operators" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 27, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "355 // 113" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "16" - ] - }, - "execution_count": 28, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "355 % 113" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "2" - ] - }, - "execution_count": 29, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "-7 % 3" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "120390229192789671200196730675808906407818580678535565853604471040981468330576609422256057752381687848600439581729091776513008621150593910720527739772380453052486767498034969314002237284144953291103458547532810152608127216408475325114421897897408047581395677670971695493487923933346069636224032935216763561673143257907287561970520670661943292226106584203713841952673366886865445199267790891789863232017223226748196794533959989836805876911810211481167739679043319937687835412885323948134322098370385629943305785136881090458653857068542385988740344220360507575957485047851613181253218943644136742478444626968576" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "2 ** 2020" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Assignment operators" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n" - ] - } - ], - "source": [ - "i = 0\n", - "i += 1\n", - "print(i)" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "-9\n" - ] - } - ], - "source": [ - "#print(i := int(-9.99)) ## warlus operator not recognized, to update anaconda soon.\n", - "i = int(-9.99)\n", - "print(i)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Comparison operators" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 33, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = True\n", - "b = False\n", - "a > b" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 34, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "a = 'ab'\n", - "b = 'Ab'\n", - "a < b" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 35, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "c = 'a b'\n", - "a < c" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### String Concatenation & repetition" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'newspaperman'" - ] - }, - "execution_count": 36, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "'news' + 'paper' + 'man'" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'eigenvalue'" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s = 'eigen'\n", - "s += 'value'\n", - "s" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'----------'" - ] - }, - "execution_count": 38, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "'-' * 10" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### String length & indices" - ] - }, - { - "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "16" - ] - }, - "execution_count": 39, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s = 'machine learning'\n", - "len(s)" - ] - }, - { - "cell_type": "code", - "execution_count": 40, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'c'" - ] - }, - "execution_count": 40, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s[2]" - ] - }, - { - "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "ne le\n", - "learning\n", - "machine\n" - ] - } - ], - "source": [ - "print(s[5:10])\n", - "print(s[8:])\n", - "print(s[:7])" - ] - }, - { - "cell_type": "code", - "execution_count": 42, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "e\n", - "earn\n" - ] - } - ], - "source": [ - "print(s[-7])\n", - "print(s[-7:-3])" - ] - }, - { - "cell_type": "code", - "execution_count": 43, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "5" - ] - }, - "execution_count": 43, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s.find('n')" - ] - }, - { - "cell_type": "code", - "execution_count": 44, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "12" - ] - }, - "execution_count": 44, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s.find('n', 6)" - ] - }, - { - "cell_type": "code", - "execution_count": 45, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "-1" - ] - }, - "execution_count": 45, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s.find('n', 6, 10)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### print" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1234-567.89#" - ] - } - ], - "source": [ - "print(1234, 567.89, sep = '-', end = '#')" - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pi is approximately 022/7 = 3.14\n" - ] - } - ], - "source": [ - "print('{0:s} is approximately {1:03d}/{2:<2d} = {3:.2f}'.format('pi', 22, 7, 3.1415926))" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pi is approximately 355 / 113 = 3.141593\n" - ] - } - ], - "source": [ - "print('{0:s} is approximately {1:^5d}/{2:^5d} = {3:.6f}'.format('pi', 355, 113, 3.1415926))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python containers" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Range and for loops" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1 3 5 7 9 " - ] - } - ], - "source": [ - "for i in range(1, 11, 2):\n", - " print(i, end = ' ')" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1 2 4 8 16 32 64 128 256 " - ] - } - ], - "source": [ - "for i in range(9):\n", - " print(2**i, end = ' ')" - ] - }, - { - "cell_type": "code", - "execution_count": 51, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "m-a-c-h-i-n-e- -l-e-a-r-n-i-n-g-" - ] - } - ], - "source": [ - "for i in range(len(s)):\n", - " print(s[i], end = '-')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Lists and Tuples" - ] - }, - { - "cell_type": "code", - "execution_count": 52, - "metadata": {}, - "outputs": [], - "source": [ - "orange_peel = (1.0, 0.625, 0.0)" - ] - }, - { - "cell_type": "code", - "execution_count": 53, - "metadata": {}, - "outputs": [], - "source": [ - "l = [1, 2, 3, 4, 5, 6, 7]" - ] - }, - { - "cell_type": "code", - "execution_count": 54, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "4" - ] - }, - "execution_count": 54, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l[3]" - ] - }, - { - "cell_type": "code", - "execution_count": 55, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[3, 4, 5, 6]" - ] - }, - "execution_count": 55, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l[2:6]" - ] - }, - { - "cell_type": "code", - "execution_count": 56, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "7" - ] - }, - "execution_count": 56, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l[-1]" - ] - }, - { - "cell_type": "code", - "execution_count": 57, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "0.625" - ] - }, - "execution_count": 57, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "orange_peel[1]" - ] - }, - { - "cell_type": "code", - "execution_count": 58, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" - ] - }, - "execution_count": 58, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(range(10))" - ] - }, - { - "cell_type": "code", - "execution_count": 59, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1, 3, 5, 7, 9, 11, 13, 15, 17]\n" - ] - } - ], - "source": [ - "# print(l := list(range(1, 19, 2))) ## walrus operator again\n", - "l = list(range(1, 19, 2))\n", - "print(l)" - ] - }, - { - "cell_type": "code", - "execution_count": 60, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[5, 9, 13]" - ] - }, - "execution_count": 60, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l[2:7:2]" - ] - }, - { - "cell_type": "code", - "execution_count": 61, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[15, 13, 11]" - ] - }, - "execution_count": 61, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l[7:4:-1]" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[15, 11]" - ] - }, - "execution_count": 62, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l[-2:-5:-2]" - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[17, 15, 13, 11, 9, 7, 5, 3, 1]" - ] - }, - "execution_count": 63, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l[::-1]" - ] - }, - { - "cell_type": "code", - "execution_count": 64, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 64, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l.index(7)" - ] - }, - { - "cell_type": "code", - "execution_count": 65, - "metadata": {}, - "outputs": [], - "source": [ - "# l.index(8) gives an error as 8 is not in the list" - ] - }, - { - "cell_type": "code", - "execution_count": 66, - "metadata": {}, - "outputs": [], - "source": [ - "l.append(19)" - ] - }, - { - "cell_type": "code", - "execution_count": 67, - "metadata": {}, - "outputs": [], - "source": [ - "l.insert(1, 2)" - ] - }, - { - "cell_type": "code", - "execution_count": 68, - "metadata": {}, - "outputs": [], - "source": [ - "l.extend((23, 29, 31)) # extend by a tuple" - ] - }, - { - "cell_type": "code", - "execution_count": 69, - "metadata": {}, - "outputs": [], - "source": [ - "l.extend([37, 41, 43, 47, 49]) # extend by a list" - ] - }, - { - "cell_type": "code", - "execution_count": 70, - "metadata": {}, - "outputs": [], - "source": [ - "# l.remove(4) # error if remove 4\n", - "l.remove(9)" - ] - }, - { - "cell_type": "code", - "execution_count": 71, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "49" - ] - }, - "execution_count": 71, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l.pop()" - ] - }, - { - "cell_type": "code", - "execution_count": 72, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "15" - ] - }, - "execution_count": 72, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l.pop(7)" - ] - }, - { - "cell_type": "code", - "execution_count": 73, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 73, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "l.pop(0)" - ] - }, - { - "cell_type": "code", - "execution_count": 74, - "metadata": {}, - "outputs": [], - "source": [ - "l.sort(reverse = True)" - ] - }, - { - "cell_type": "code", - "execution_count": 75, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[47, 43, 41, 37, 31, 29, 23, 19, 17, 13, 11, 7, 5, 3, 2]\n" - ] - } - ], - "source": [ - "print(l)" - ] - }, - { - "cell_type": "code", - "execution_count": 76, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['mitb', 'smu', 'edu', 'sg']\n" - ] - } - ], - "source": [ - "s = 'mitb.smu.edu.sg'\n", - "print(s.split('.'))" - ] - }, - { - "cell_type": "code", - "execution_count": 77, - "metadata": {}, - "outputs": [], - "source": [ - "s = 'machine learning'\n", - "tokens = s.split()" - ] - }, - { - "cell_type": "code", - "execution_count": 78, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "machine\n", - "learning\n" - ] - } - ], - "source": [ - "print('\\n'.join(tokens))" - ] - }, - { - "cell_type": "code", - "execution_count": 79, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "machine\r", - "learning\n" - ] - } - ], - "source": [ - "print('\\r'.join(tokens))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Dictionaries" - ] - }, - { - "cell_type": "code", - "execution_count": 80, - "metadata": {}, - "outputs": [], - "source": [ - "d = {}\n", - "for i in range(97, 123):\n", - " d[chr(i)] = i - 96" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "19\n" - ] - } - ], - "source": [ - "print(d['s'])" - ] - }, - { - "cell_type": "code", - "execution_count": 82, - "metadata": {}, - "outputs": [], - "source": [ - "d['s'] *= 10" - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": {}, - "outputs": [], - "source": [ - "d['s'] = 19" - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 84, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "2 in l" - ] - }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 85, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "'z' in d" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "False" - ] - }, - "execution_count": 86, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "2 in d" - ] - }, - { - "cell_type": "code", - "execution_count": 87, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 87, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "2 not in d" - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "20" - ] - }, - "execution_count": 88, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "d.pop('t')" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [], - "source": [ - "del d['s']" - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 'u', 'v', 'w', 'x', 'y', 'z']\n" - ] - } - ], - "source": [ - "print(list(d.keys()))" - ] - }, - { - "cell_type": "code", - "execution_count": 91, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 21, 22, 23, 24, 25, 26]\n" - ] - } - ], - "source": [ - "print(list(d.values()))" - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[('a', 1), ('b', 2), ('c', 3), ('d', 4), ('e', 5), ('f', 6), ('g', 7), ('h', 8), ('i', 9), ('j', 10), ('k', 11), ('l', 12), ('m', 13), ('n', 14), ('o', 15), ('p', 16), ('q', 17), ('r', 18), ('u', 21), ('v', 22), ('w', 23), ('x', 24), ('y', 25), ('z', 26)]\n" - ] - } - ], - "source": [ - "print(list(d.items()))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Sets" - ] - }, - { - "cell_type": "code", - "execution_count": 93, - "metadata": {}, - "outputs": [], - "source": [ - "s = {'deer', 'hawk', 'wolf', 'boar'}" - ] - }, - { - "cell_type": "code", - "execution_count": 94, - "metadata": {}, - "outputs": [], - "source": [ - "s.add('bear')" - ] - }, - { - "cell_type": "code", - "execution_count": 95, - "metadata": {}, - "outputs": [], - "source": [ - "s.add(('goat', 'pony', 'hare')) # do you know why you cannot change the tuple to a list?" - ] - }, - { - "cell_type": "code", - "execution_count": 96, - "metadata": {}, - "outputs": [], - "source": [ - "s.update(['lion', 'puma', 'tiger', 'leopard']) # cannot add a list" - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'deer', 'tiger', 'bear', 'hawk', 'wolf', 'leopard', 'lion', ('goat', 'pony', 'hare'), 'boar', 'puma'}\n" - ] - } - ], - "source": [ - "print(s)" - ] - }, - { - "cell_type": "code", - "execution_count": 98, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'deer'" - ] - }, - "execution_count": 98, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s.pop() # pop some element in the set" - ] - }, - { - "cell_type": "code", - "execution_count": 99, - "metadata": {}, - "outputs": [], - "source": [ - "s.remove('leopard')" - ] - }, - { - "cell_type": "code", - "execution_count": 100, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{'tiger', 'bear', 'hawk', 'wolf', 'lion', ('goat', 'pony', 'hare'), 'boar', 'puma'}\n" - ] - } - ], - "source": [ - "print(s)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.11: count the frequence of each unique value in a given list\n", - "Hint: use .get(key, default_value)" - ] - }, - { - "cell_type": "code", - "execution_count": 101, - "metadata": {}, - "outputs": [], - "source": [ - "long_list = [11, 230, 127, 183, 142, 186, 256, 182, 184, 50, 266, 179, 22, 30, 59, 236, 155, 57, 262, 279, 107, 98, 271, 240, 276, 23, 170, 207, 123, 228, 231, 205, 30, 161, 125, 212, 224, 34, 272, 106, 164, 26, 263, 3, 234, 244, 3, 260, 135, 29, 116, 44, 206, 131, 218, 201, 140, 208, 130, 247, 256, 272, 208, 262, 227, 242, 112, 138, 192, 7, 268, 184, 168, 5, 246, 199, 6, 26, 300, 54, 260, 69, 64, 61, 15, 288, 190, 78, 165, 7, 178, 71, 62, 131, 26, 75, 2, 52, 164, 195, 75, 80, 212, 127, 201, 184, 78, 106, 90, 256, 33, 241, 208, 39, 32, 240, 160, 172, 108, 144, 116, 251, 106, 278, 120, 99, 22, 148, 6, 185, 136, 235, 208, 114, 22, 229, 88, 225, 112, 236, 250, 32, 152, 195, 0, 160, 252, 15, 173, 283, 72, 94, 76, 226, 4, 44, 28, 120, 175, 56, 262, 178, 249, 246, 19, 203, 196, 207, 33, 94, 216, 280, 102, 250, 74, 277, 159, 23, 80, 63, 124, 240, 166, 137, 14, 255, 252, 112, 41, 90, 187, 108, 2, 60, 147, 114, 266, 173, 183, 84, 10, 173, 35, 248, 124, 207, 163, 44, 2, 171, 142, 174, 219, 114, 30, 290, 239, 63, 42, 103, 61, 58, 181, 18, 111, 119, 99, 171, 210, 59, 142, 278, 213, 35, 286, 285, 227, 91, 232, 196, 11, 91, 192, 241, 1, 275, 76, 210, 160, 32, 272, 120, 176, 33, 65, 26, 2, 248, 262, 286, 199, 12, 107, 253, 150, 138, 157, 31, 250, 30, 95, 96, 105, 261, 276, 146, 195, 190, 217, 62, 138, 268, 134, 39, 164, 8, 46, 152, 93, 263, 232, 264, 272, 53, 283, 286, 218, 293, 238, 5, 122, 241, 76, 106, 85, 103, 221, 77, 74, 236, 1, 13, 144, 235, 27, 50, 7, 17, 157, 296, 111, 1, 176, 297, 286, 115, 187, 272, 66, 185, 145, 254, 20, 232, 49, 289, 285, 222, 199, 103, 65, 33, 3, 88, 157, 276, 29, 88, 226, 194, 219, 98, 58, 193, 2, 255, 126, 41, 112, 83, 104, 296, 219, 148, 274, 34, 2, 15, 267, 286, 252, 275, 126, 173, 225, 223, 121, 136, 257, 214, 7, 291, 84, 60, 93, 284, 112, 195, 162, 296, 277, 204, 297, 120, 62, 218, 247, 150, 274, 108, 78, 146, 180, 168, 231, 39, 79, 45, 139, 75, 0, 83, 158, 273, 258, 242, 36, 268, 287, 106, 284, 184, 64, 235, 14, 159, 57, 168, 4, 3, 185, 180, 132, 132, 270, 148, 39, 18, 178, 121, 250, 29, 96, 190, 234, 34, 225, 187, 57, 57, 260, 219, 126, 158, 72, 248, 47, 180, 219, 253, 10, 84, 86, 5, 210, 147, 122, 61, 143, 84, 164, 250, 233, 225, 73, 133, 123, 148, 124, 214, 5, 48, 172, 102, 133, 100, 57, 253, 13, 0, 31, 272, 2, 87, 292, 243, 53, 298, 35, 116, 282, 187, 287, 30, 108, 298, 63, 285, 289, 132, 204, 30, 230, 95, 117, 254, 128, 203, 55, 36, 147, 2, 285, 168, 214, 239, 93, 171, 288, 265, 202, 168, 161, 217, 189, 36, 101, 46, 100, 101, 50, 266, 263, 170, 19, 126, 35, 67, 122, 147, 109, 76, 147, 177, 183, 51, 124, 220, 263, 265, 3, 41, 188, 234, 187, 157, 287, 21, 99, 46, 214, 68, 8, 230, 284, 234, 258, 296, 192, 6, 281, 31, 238, 297, 34, 120, 20, 6, 230, 127, 242, 248, 147, 294, 165, 266, 268, 258, 82, 121, 221, 9, 80, 240, 67, 271, 35, 78, 253, 207, 161, 257, 38, 128, 281, 281, 170, 167, 40, 113, 12, 93, 126, 41, 258, 233, 71, 242, 209, 82, 97, 150, 90, 276, 264, 51, 222, 6, 204, 118, 263, 102, 177, 113, 106, 288, 58, 94, 299, 131, 95, 183, 184, 108, 190, 273, 279, 99, 227, 10, 274, 81, 272, 50, 65, 114, 52, 52, 10, 181, 36, 281, 6, 97, 214, 279, 143, 203, 244, 250, 151, 180, 185, 169, 66, 51, 21, 201, 275, 250, 58, 108, 1, 87, 127, 95, 81, 212, 250, 222, 171, 83, 145, 149, 185, 67, 275, 206, 242, 67, 229, 118, 124, 117, 179, 141, 65, 40, 111, 81, 152, 79, 104, 67, 119, 27, 107, 295, 43, 97, 193, 148, 255, 247, 284, 69, 84, 268, 234, 251, 169, 99, 233, 126, 103, 233, 24, 196, 70, 181, 150, 181, 110, 257, 31, 299, 195, 25, 289, 36, 75, 152, 37, 115, 116, 171, 218, 278, 198, 200, 204, 260, 211, 97, 220, 167, 261, 168, 281, 67, 161, 297, 202, 56, 53, 230, 27, 64, 171, 299, 179, 66, 276, 209, 204, 282, 71, 132, 64, 299, 158, 163, 111, 252, 14, 180, 202, 286, 250, 142, 48, 271, 148, 151, 282, 116, 232, 188, 5, 150, 242, 292, 48, 119, 158, 10, 89, 124, 211, 253, 182, 295, 81, 199, 126, 139, 59, 154, 212, 101, 89, 45, 289, 69, 120, 264, 217, 279, 163, 103, 153, 159, 183, 81, 282, 77, 77, 4, 229, 10, 292, 222, 235, 205, 283, 194, 166, 63, 56, 92, 57, 184, 48, 285, 146, 184, 233, 76, 164, 83, 74, 178, 263, 137, 272, 4, 102, 111, 83, 229, 7, 268, 26, 274, 100, 231, 80, 223, 226, 151, 219, 5, 144, 169, 68, 175, 257, 48, 243, 185, 145, 115, 239, 259, 36, 192, 256, 19, 252, 95, 284, 62, 192, 281, 299, 34, 290, 70, 166, 9, 102, 279, 225, 147, 175, 269, 16, 115, 181, 150, 200, 89, 1, 298, 132, 93, 24, 209, 231, 225, 67, 239, 47, 280, 101, 210, 164, 241, 115, 259, 261, 157, 224, 296, 223, 127, 22, 280, 28, 170, 15, 201, 102, 245, 266, 161, 20, 210, 251, 249, 53, 282, 76, 126, 243, 196, 220, 265, 110, 146, 242, 248, 17, 181, 23, 77, 106, 296, 290, 243, 93]" - ] - }, - { - "cell_type": "code", - "execution_count": 102, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Python Conditionals" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### if and elif" - ] - }, - { - "cell_type": "code", - "execution_count": 103, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an odd number\n", - "this is an even number\n" - ] - } - ], - "source": [ - "for i in l:\n", - " if i % 2 == 0:\n", - " print('this is an even number')\n", - " else:\n", - " print('this is an odd number')" - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a prime number\n", - "this is a multiple of 3\n", - "this is an even number\n" - ] - } - ], - "source": [ - "for i in l:\n", - " if i % 2 == 0:\n", - " print('this is an even number')\n", - " elif i % 3 == 0:\n", - " print('this is a multiple of 3')\n", - " else:\n", - " print('this is a prime number')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### for loops" - ] - }, - { - "cell_type": "code", - "execution_count": 105, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "1\n", - "2\n", - "3\n", - "4\n", - "5\n", - "6\n", - "7\n", - "8\n", - "9\n" - ] - } - ], - "source": [ - "for i in range(10):\n", - " print(i)" - ] - }, - { - "cell_type": "code", - "execution_count": 106, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "10\n", - "11\n", - "12\n", - "13\n", - "14\n", - "15\n", - "16\n", - "17\n", - "18\n", - "19\n" - ] - } - ], - "source": [ - "for i in range(10, 20):\n", - " print(i)" - ] - }, - { - "cell_type": "code", - "execution_count": 107, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "3\n", - "5\n", - "7\n" - ] - } - ], - "source": [ - "for i in range(1, 9, 2):\n", - " print(i)" - ] - }, - { - "cell_type": "code", - "execution_count": 108, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "m\n", - "a\n", - "c\n", - "h\n", - "i\n", - "n\n", - "e\n", - " \n", - "l\n", - "e\n", - "a\n", - "r\n", - "n\n", - "i\n", - "n\n", - "g\n" - ] - } - ], - "source": [ - "s = 'machine learning'\n", - "for ch in s:\n", - " print(ch)" - ] - }, - { - "cell_type": "code", - "execution_count": 109, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "2\n", - "3\n", - "4\n" - ] - } - ], - "source": [ - "l = [1, 2, 3, 4]\n", - "for v in l:\n", - " print(v)" - ] - }, - { - "cell_type": "code", - "execution_count": 110, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "3\n" - ] - } - ], - "source": [ - "d = {1:2, 3:4}\n", - "for k in d:\n", - " print(k)" - ] - }, - { - "cell_type": "code", - "execution_count": 111, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2\n", - "4\n" - ] - } - ], - "source": [ - "for v in d.values():\n", - " print(v)" - ] - }, - { - "cell_type": "code", - "execution_count": 112, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(1, 2)\n", - "(3, 4)\n" - ] - } - ], - "source": [ - "for p in d.items():\n", - " print(p)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### while loops" - ] - }, - { - "cell_type": "code", - "execution_count": 113, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5050\n" - ] - } - ], - "source": [ - "summ, i = 0, 0\n", - "while i <= 100:\n", - " summ += i\n", - " i += 1\n", - "print(summ)" - ] - }, - { - "cell_type": "code", - "execution_count": 114, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "i\n", - "like\n", - "python\n" - ] - } - ], - "source": [ - "l = ['i', 'like', 'python']\n", - "while l:\n", - " print(l.pop(0))" - ] - }, - { - "cell_type": "code", - "execution_count": 115, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "' # comment this line to run the code below\\nsent = input(\\'What can I help you?\\n\\')\\nwhile sent.lower() != \\'i give up!\\' and sent.lower() != \"i\\'m frustrated!\":\\n sent = input(\\'Pardon?\\n\\')\\n#'" - ] - }, - "execution_count": 115, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "''' # comment this line to run the code below\n", - "sent = input('What can I help you?\\n')\n", - "while sent.lower() != 'i give up!' and sent.lower() != \"i'm frustrated!\":\n", - " sent = input('Pardon?\\n')\n", - "#'''" - ] - }, - { - "cell_type": "code", - "execution_count": 116, - "metadata": {}, - "outputs": [], - "source": [ - "while None:\n", - " print('this is evaluated as False')\n", - "while False:\n", - " print('this is evaluated as False')\n", - "while 0:\n", - " print('this is evaluated as False')\n", - "while '':\n", - " print('this is evaluated as False')\n", - "while []:\n", - " print('this is evaluated as False')\n", - "while {}:\n", - " print('this is evaluated as False')\n", - "while float('NaN') == float('NaN'):\n", - " print('this is evaluated as False')" - ] - }, - { - "cell_type": "code", - "execution_count": 117, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "value of i is now 1\n", - "value of i is now 3\n", - "value of i is now 5\n" - ] - } - ], - "source": [ - "i = 0\n", - "while i < 8:\n", - " i += 1\n", - " print('value of i is now', i)\n", - " if i == 5:\n", - " break\n", - " i += 1" - ] - }, - { - "cell_type": "code", - "execution_count": 118, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "value of i is now 1\n", - "value of i is now 3\n", - "value of i is now 5\n", - "value of i is now 6\n", - "value of i is now 8\n" - ] - } - ], - "source": [ - "i = 0\n", - "while i < 8:\n", - " i += 1\n", - " print('value of i is now', i)\n", - " if i == 5:\n", - " continue\n", - " i += 1" - ] - }, - { - "cell_type": "code", - "execution_count": 119, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "no multiple of 37 found\n" - ] - } - ], - "source": [ - "j = 37\n", - "for i in range(80, 110):\n", - " if i % j == 0:\n", - " break\n", - "else:\n", - " print('no multiple of {:d} found'.format(j))" - ] - }, - { - "cell_type": "code", - "execution_count": 120, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "no multiple of 37 found\n" - ] - } - ], - "source": [ - "i, j = 80, 37\n", - "while i <= 110:\n", - " if i % j == 0:\n", - " break\n", - " i += 1\n", - "else:\n", - " print('no multiple of {:d} found'.format(j))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.12: find the first value appears 3 times in a list" - ] - }, - { - "cell_type": "code", - "execution_count": 121, - "metadata": {}, - "outputs": [], - "source": [ - "long_list = [11, 230, 127, 183, 142, 186, 256, 182, 184, 50, 266, 179, 22, 30, 59, 236, 155, 57, 262, 279, 107, 98, 271, 240, 276, 23, 170, 207, 123, 228, 231, 205, 30, 161, 125, 212, 224, 34, 272, 106, 164, 26, 263, 3, 234, 244, 3, 260, 135, 29, 116, 44, 206, 131, 218, 201, 140, 208, 130, 247, 256, 272, 208, 262, 227, 242, 112, 138, 192, 7, 268, 184, 168, 5, 246, 199, 6, 26, 300, 54, 260, 69, 64, 61, 15, 288, 190, 78, 165, 7, 178, 71, 62, 131, 26, 75, 2, 52, 164, 195, 75, 80, 212, 127, 201, 184, 78, 106, 90, 256, 33, 241, 208, 39, 32, 240, 160, 172, 108, 144, 116, 251, 106, 278, 120, 99, 22, 148, 6, 185, 136, 235, 208, 114, 22, 229, 88, 225, 112, 236, 250, 32, 152, 195, 0, 160, 252, 15, 173, 283, 72, 94, 76, 226, 4, 44, 28, 120, 175, 56, 262, 178, 249, 246, 19, 203, 196, 207, 33, 94, 216, 280, 102, 250, 74, 277, 159, 23, 80, 63, 124, 240, 166, 137, 14, 255, 252, 112, 41, 90, 187, 108, 2, 60, 147, 114, 266, 173, 183, 84, 10, 173, 35, 248, 124, 207, 163, 44, 2, 171, 142, 174, 219, 114, 30, 290, 239, 63, 42, 103, 61, 58, 181, 18, 111, 119, 99, 171, 210, 59, 142, 278, 213, 35, 286, 285, 227, 91, 232, 196, 11, 91, 192, 241, 1, 275, 76, 210, 160, 32, 272, 120, 176, 33, 65, 26, 2, 248, 262, 286, 199, 12, 107, 253, 150, 138, 157, 31, 250, 30, 95, 96, 105, 261, 276, 146, 195, 190, 217, 62, 138, 268, 134, 39, 164, 8, 46, 152, 93, 263, 232, 264, 272, 53, 283, 286, 218, 293, 238, 5, 122, 241, 76, 106, 85, 103, 221, 77, 74, 236, 1, 13, 144, 235, 27, 50, 7, 17, 157, 296, 111, 1, 176, 297, 286, 115, 187, 272, 66, 185, 145, 254, 20, 232, 49, 289, 285, 222, 199, 103, 65, 33, 3, 88, 157, 276, 29, 88, 226, 194, 219, 98, 58, 193, 2, 255, 126, 41, 112, 83, 104, 296, 219, 148, 274, 34, 2, 15, 267, 286, 252, 275, 126, 173, 225, 223, 121, 136, 257, 214, 7, 291, 84, 60, 93, 284, 112, 195, 162, 296, 277, 204, 297, 120, 62, 218, 247, 150, 274, 108, 78, 146, 180, 168, 231, 39, 79, 45, 139, 75, 0, 83, 158, 273, 258, 242, 36, 268, 287, 106, 284, 184, 64, 235, 14, 159, 57, 168, 4, 3, 185, 180, 132, 132, 270, 148, 39, 18, 178, 121, 250, 29, 96, 190, 234, 34, 225, 187, 57, 57, 260, 219, 126, 158, 72, 248, 47, 180, 219, 253, 10, 84, 86, 5, 210, 147, 122, 61, 143, 84, 164, 250, 233, 225, 73, 133, 123, 148, 124, 214, 5, 48, 172, 102, 133, 100, 57, 253, 13, 0, 31, 272, 2, 87, 292, 243, 53, 298, 35, 116, 282, 187, 287, 30, 108, 298, 63, 285, 289, 132, 204, 30, 230, 95, 117, 254, 128, 203, 55, 36, 147, 2, 285, 168, 214, 239, 93, 171, 288, 265, 202, 168, 161, 217, 189, 36, 101, 46, 100, 101, 50, 266, 263, 170, 19, 126, 35, 67, 122, 147, 109, 76, 147, 177, 183, 51, 124, 220, 263, 265, 3, 41, 188, 234, 187, 157, 287, 21, 99, 46, 214, 68, 8, 230, 284, 234, 258, 296, 192, 6, 281, 31, 238, 297, 34, 120, 20, 6, 230, 127, 242, 248, 147, 294, 165, 266, 268, 258, 82, 121, 221, 9, 80, 240, 67, 271, 35, 78, 253, 207, 161, 257, 38, 128, 281, 281, 170, 167, 40, 113, 12, 93, 126, 41, 258, 233, 71, 242, 209, 82, 97, 150, 90, 276, 264, 51, 222, 6, 204, 118, 263, 102, 177, 113, 106, 288, 58, 94, 299, 131, 95, 183, 184, 108, 190, 273, 279, 99, 227, 10, 274, 81, 272, 50, 65, 114, 52, 52, 10, 181, 36, 281, 6, 97, 214, 279, 143, 203, 244, 250, 151, 180, 185, 169, 66, 51, 21, 201, 275, 250, 58, 108, 1, 87, 127, 95, 81, 212, 250, 222, 171, 83, 145, 149, 185, 67, 275, 206, 242, 67, 229, 118, 124, 117, 179, 141, 65, 40, 111, 81, 152, 79, 104, 67, 119, 27, 107, 295, 43, 97, 193, 148, 255, 247, 284, 69, 84, 268, 234, 251, 169, 99, 233, 126, 103, 233, 24, 196, 70, 181, 150, 181, 110, 257, 31, 299, 195, 25, 289, 36, 75, 152, 37, 115, 116, 171, 218, 278, 198, 200, 204, 260, 211, 97, 220, 167, 261, 168, 281, 67, 161, 297, 202, 56, 53, 230, 27, 64, 171, 299, 179, 66, 276, 209, 204, 282, 71, 132, 64, 299, 158, 163, 111, 252, 14, 180, 202, 286, 250, 142, 48, 271, 148, 151, 282, 116, 232, 188, 5, 150, 242, 292, 48, 119, 158, 10, 89, 124, 211, 253, 182, 295, 81, 199, 126, 139, 59, 154, 212, 101, 89, 45, 289, 69, 120, 264, 217, 279, 163, 103, 153, 159, 183, 81, 282, 77, 77, 4, 229, 10, 292, 222, 235, 205, 283, 194, 166, 63, 56, 92, 57, 184, 48, 285, 146, 184, 233, 76, 164, 83, 74, 178, 263, 137, 272, 4, 102, 111, 83, 229, 7, 268, 26, 274, 100, 231, 80, 223, 226, 151, 219, 5, 144, 169, 68, 175, 257, 48, 243, 185, 145, 115, 239, 259, 36, 192, 256, 19, 252, 95, 284, 62, 192, 281, 299, 34, 290, 70, 166, 9, 102, 279, 225, 147, 175, 269, 16, 115, 181, 150, 200, 89, 1, 298, 132, 93, 24, 209, 231, 225, 67, 239, 47, 280, 101, 210, 164, 241, 115, 259, 261, 157, 224, 296, 223, 127, 22, 280, 28, 170, 15, 201, 102, 245, 266, 161, 20, 210, 251, 249, 53, 282, 76, 126, 243, 196, 220, 265, 110, 146, 242, 248, 17, 181, 23, 77, 106, 296, 290, 243, 93]" - ] - }, - { - "cell_type": "code", - "execution_count": 122, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.13: print the following pattern of 10 rows and 19 columns" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```\n", - "*******************\n", - "---------*---------\n", - "********---********\n", - "-------*****-------\n", - "******-------******\n", - "-----*********-----\n", - "****-----------****\n", - "---*************---\n", - "**---------------**\n", - "-*****************-\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 123, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### List & dictionary comprehension" - ] - }, - { - "cell_type": "code", - "execution_count": 124, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[9, 25, 49, 81, 121, 169, 225, 289, 361, 441, 529, 625, 729, 841, 961, 1089, 1225, 1369]\n" - ] - } - ], - "source": [ - "a = [i**2 for i in range(3, 39, 2)]\n", - "print(a)" - ] - }, - { - "cell_type": "code", - "execution_count": 125, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{9: 0, 25: 1, 49: 2, 81: 3, 121: 4, 169: 5, 225: 6, 289: 7, 361: 8, 441: 9, 529: 10, 625: 11, 729: 12, 841: 13, 961: 14, 1089: 15, 1225: 16, 1369: 17}\n" - ] - } - ], - "source": [ - "b = {a[i]:i for i in range(len(a))}\n", - "print(b)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 4: Construct a geometric progression\n", - "print first 20 terms, use list comprehension" - ] - }, - { - "cell_type": "code", - "execution_count": 126, - "metadata": {}, - "outputs": [], - "source": [ - "first_term, ratio = 512, 1.5" - ] - }, - { - "cell_type": "code", - "execution_count": 127, - "metadata": {}, - "outputs": [], - "source": [ - "# Write your Python code" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 5: find the start time of Einstein’s presentation\n", - "\n", - "Suppose a presentation session at a conference starts at 8:20am, each speaker is given 20 minutes and they present in the ascending order of their surname, when does Einstein start to present? " - ] - }, - { - "cell_type": "code", - "execution_count": 128, - "metadata": {}, - "outputs": [], - "source": [ - "physicists = ['Erwin Schroedinger', 'Wolfgang Pauli', 'Max Born', 'Niels Bohr', 'Max Planck', 'Madame Curie', 'Hendrik Antoon Lorentz', 'Albert Einstein', 'Paul Langevin', 'Louis Victor de Broglie', 'Paul Dirac', 'Werner Heisenberg']" - ] - }, - { - "cell_type": "code", - "execution_count": 129, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Final exercise: list words that have appeared at least 3 times" - ] - }, - { - "cell_type": "code", - "execution_count": 130, - "metadata": {}, - "outputs": [], - "source": [ - "speech = ['the United States has conducted an operation that killed Osama bin Laden',\n", - " 'Abu Bakr al-Baghdadi is dead',\n", - " 'the United States launched a targeted operation against that compound',\n", - " 'they did a lot of shooting and they did a lot of blasting even not going through the front door You know you would think you go through the door If you are a normal person you say Knock knock May I come in',\n", - " 'After a firefight they killed Osama bin Laden and took custody of his body',\n", - " 'He died like a dog',\n", - " 'Yet his death does not mark the end of our effort',\n", - " 'a beautiful dog a talented dog',\n", - " 'We give thanks for the men who carried out this operation',\n", - " 'And I dont get any credit for this but thats okay I never do But here we are',\n", - " 'May God bless you And may God bless the United States of America',\n", - " 'And Im writing a book I think I wrote 12 books All did very well']" - ] - }, - { - "cell_type": "code", - "execution_count": 131, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - } - ], - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/W1_Python_Basics/class_exercise_1_submit.ipynb b/W1_Python_Basics/class_exercise_1_submit.ipynb deleted file mode 100644 index a4402ee..0000000 --- a/W1_Python_Basics/class_exercise_1_submit.ipynb +++ /dev/null @@ -1,788 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.11: count the frequence of each unique value in a given list" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [], - "source": [ - "long_list = [11, 230, 127, 183, 142, 186, 256, 182, 184, 50, 266, 179, 22, 30, 59, 236, 155, 57, 262, 279, 107, 98, 271, 240, 276, 23, 170, 207, 123, 228, 231, 205, 30, 161, 125, 212, 224, 34, 272, 106, 164, 26, 263, 3, 234, 244, 3, 260, 135, 29, 116, 44, 206, 131, 218, 201, 140, 208, 130, 247, 256, 272, 208, 262, 227, 242, 112, 138, 192, 7, 268, 184, 168, 5, 246, 199, 6, 26, 300, 54, 260, 69, 64, 61, 15, 288, 190, 78, 165, 7, 178, 71, 62, 131, 26, 75, 2, 52, 164, 195, 75, 80, 212, 127, 201, 184, 78, 106, 90, 256, 33, 241, 208, 39, 32, 240, 160, 172, 108, 144, 116, 251, 106, 278, 120, 99, 22, 148, 6, 185, 136, 235, 208, 114, 22, 229, 88, 225, 112, 236, 250, 32, 152, 195, 0, 160, 252, 15, 173, 283, 72, 94, 76, 226, 4, 44, 28, 120, 175, 56, 262, 178, 249, 246, 19, 203, 196, 207, 33, 94, 216, 280, 102, 250, 74, 277, 159, 23, 80, 63, 124, 240, 166, 137, 14, 255, 252, 112, 41, 90, 187, 108, 2, 60, 147, 114, 266, 173, 183, 84, 10, 173, 35, 248, 124, 207, 163, 44, 2, 171, 142, 174, 219, 114, 30, 290, 239, 63, 42, 103, 61, 58, 181, 18, 111, 119, 99, 171, 210, 59, 142, 278, 213, 35, 286, 285, 227, 91, 232, 196, 11, 91, 192, 241, 1, 275, 76, 210, 160, 32, 272, 120, 176, 33, 65, 26, 2, 248, 262, 286, 199, 12, 107, 253, 150, 138, 157, 31, 250, 30, 95, 96, 105, 261, 276, 146, 195, 190, 217, 62, 138, 268, 134, 39, 164, 8, 46, 152, 93, 263, 232, 264, 272, 53, 283, 286, 218, 293, 238, 5, 122, 241, 76, 106, 85, 103, 221, 77, 74, 236, 1, 13, 144, 235, 27, 50, 7, 17, 157, 296, 111, 1, 176, 297, 286, 115, 187, 272, 66, 185, 145, 254, 20, 232, 49, 289, 285, 222, 199, 103, 65, 33, 3, 88, 157, 276, 29, 88, 226, 194, 219, 98, 58, 193, 2, 255, 126, 41, 112, 83, 104, 296, 219, 148, 274, 34, 2, 15, 267, 286, 252, 275, 126, 173, 225, 223, 121, 136, 257, 214, 7, 291, 84, 60, 93, 284, 112, 195, 162, 296, 277, 204, 297, 120, 62, 218, 247, 150, 274, 108, 78, 146, 180, 168, 231, 39, 79, 45, 139, 75, 0, 83, 158, 273, 258, 242, 36, 268, 287, 106, 284, 184, 64, 235, 14, 159, 57, 168, 4, 3, 185, 180, 132, 132, 270, 148, 39, 18, 178, 121, 250, 29, 96, 190, 234, 34, 225, 187, 57, 57, 260, 219, 126, 158, 72, 248, 47, 180, 219, 253, 10, 84, 86, 5, 210, 147, 122, 61, 143, 84, 164, 250, 233, 225, 73, 133, 123, 148, 124, 214, 5, 48, 172, 102, 133, 100, 57, 253, 13, 0, 31, 272, 2, 87, 292, 243, 53, 298, 35, 116, 282, 187, 287, 30, 108, 298, 63, 285, 289, 132, 204, 30, 230, 95, 117, 254, 128, 203, 55, 36, 147, 2, 285, 168, 214, 239, 93, 171, 288, 265, 202, 168, 161, 217, 189, 36, 101, 46, 100, 101, 50, 266, 263, 170, 19, 126, 35, 67, 122, 147, 109, 76, 147, 177, 183, 51, 124, 220, 263, 265, 3, 41, 188, 234, 187, 157, 287, 21, 99, 46, 214, 68, 8, 230, 284, 234, 258, 296, 192, 6, 281, 31, 238, 297, 34, 120, 20, 6, 230, 127, 242, 248, 147, 294, 165, 266, 268, 258, 82, 121, 221, 9, 80, 240, 67, 271, 35, 78, 253, 207, 161, 257, 38, 128, 281, 281, 170, 167, 40, 113, 12, 93, 126, 41, 258, 233, 71, 242, 209, 82, 97, 150, 90, 276, 264, 51, 222, 6, 204, 118, 263, 102, 177, 113, 106, 288, 58, 94, 299, 131, 95, 183, 184, 108, 190, 273, 279, 99, 227, 10, 274, 81, 272, 50, 65, 114, 52, 52, 10, 181, 36, 281, 6, 97, 214, 279, 143, 203, 244, 250, 151, 180, 185, 169, 66, 51, 21, 201, 275, 250, 58, 108, 1, 87, 127, 95, 81, 212, 250, 222, 171, 83, 145, 149, 185, 67, 275, 206, 242, 67, 229, 118, 124, 117, 179, 141, 65, 40, 111, 81, 152, 79, 104, 67, 119, 27, 107, 295, 43, 97, 193, 148, 255, 247, 284, 69, 84, 268, 234, 251, 169, 99, 233, 126, 103, 233, 24, 196, 70, 181, 150, 181, 110, 257, 31, 299, 195, 25, 289, 36, 75, 152, 37, 115, 116, 171, 218, 278, 198, 200, 204, 260, 211, 97, 220, 167, 261, 168, 281, 67, 161, 297, 202, 56, 53, 230, 27, 64, 171, 299, 179, 66, 276, 209, 204, 282, 71, 132, 64, 299, 158, 163, 111, 252, 14, 180, 202, 286, 250, 142, 48, 271, 148, 151, 282, 116, 232, 188, 5, 150, 242, 292, 48, 119, 158, 10, 89, 124, 211, 253, 182, 295, 81, 199, 126, 139, 59, 154, 212, 101, 89, 45, 289, 69, 120, 264, 217, 279, 163, 103, 153, 159, 183, 81, 282, 77, 77, 4, 229, 10, 292, 222, 235, 205, 283, 194, 166, 63, 56, 92, 57, 184, 48, 285, 146, 184, 233, 76, 164, 83, 74, 178, 263, 137, 272, 4, 102, 111, 83, 229, 7, 268, 26, 274, 100, 231, 80, 223, 226, 151, 219, 5, 144, 169, 68, 175, 257, 48, 243, 185, 145, 115, 239, 259, 36, 192, 256, 19, 252, 95, 284, 62, 192, 281, 299, 34, 290, 70, 166, 9, 102, 279, 225, 147, 175, 269, 16, 115, 181, 150, 200, 89, 1, 298, 132, 93, 24, 209, 231, 225, 67, 239, 47, 280, 101, 210, 164, 241, 115, 259, 261, 157, 224, 296, 223, 127, 22, 280, 28, 170, 15, 201, 102, 245, 266, 161, 20, 210, 251, 249, 53, 282, 76, 126, 243, 196, 220, 265, 110, 146, 242, 248, 17, 181, 23, 77, 106, 296, 290, 243, 93]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[(0, 3),\n", - " (1, 5),\n", - " (2, 8),\n", - " (3, 5),\n", - " (4, 4),\n", - " (5, 6),\n", - " (6, 6),\n", - " (7, 5),\n", - " (8, 2),\n", - " (9, 2),\n", - " (10, 6),\n", - " (11, 2),\n", - " (12, 2),\n", - " (13, 2),\n", - " (14, 3),\n", - " (15, 4),\n", - " (16, 1),\n", - " (17, 2),\n", - " (18, 2),\n", - " (19, 3),\n", - " (20, 3),\n", - " (21, 2),\n", - " (22, 4),\n", - " (23, 3),\n", - " (24, 2),\n", - " (25, 1),\n", - " (26, 5),\n", - " (27, 3),\n", - " (28, 2),\n", - " (29, 3),\n", - " (30, 6),\n", - " (31, 4),\n", - " (32, 3),\n", - " (33, 4),\n", - " (34, 5),\n", - " (35, 5),\n", - " (36, 6),\n", - " (37, 1),\n", - " (38, 1),\n", - " (39, 4),\n", - " (40, 2),\n", - " (41, 4),\n", - " (42, 1),\n", - " (43, 1),\n", - " (44, 3),\n", - " (45, 2),\n", - " (46, 3),\n", - " (47, 2),\n", - " (48, 5),\n", - " (49, 1),\n", - " (50, 4),\n", - " (51, 3),\n", - " (52, 3),\n", - " (53, 4),\n", - " (54, 1),\n", - " (55, 1),\n", - " (56, 3),\n", - " (57, 6),\n", - " (58, 4),\n", - " (59, 3),\n", - " (60, 2),\n", - " (61, 3),\n", - " (62, 4),\n", - " (63, 4),\n", - " (64, 4),\n", - " (65, 4),\n", - " (66, 3),\n", - " (67, 7),\n", - " (68, 2),\n", - " (69, 3),\n", - " (70, 2),\n", - " (71, 3),\n", - " (72, 2),\n", - " (73, 1),\n", - " (74, 3),\n", - " (75, 4),\n", - " (76, 6),\n", - " (77, 4),\n", - " (78, 4),\n", - " (79, 2),\n", - " (80, 4),\n", - " (81, 5),\n", - " (82, 2),\n", - " (83, 5),\n", - " (84, 5),\n", - " (85, 1),\n", - " (86, 1),\n", - " (87, 2),\n", - " (88, 3),\n", - " (89, 3),\n", - " (90, 3),\n", - " (91, 2),\n", - " (92, 1),\n", - " (93, 6),\n", - " (94, 3),\n", - " (95, 5),\n", - " (96, 2),\n", - " (97, 4),\n", - " (98, 2),\n", - " (99, 5),\n", - " (100, 3),\n", - " (101, 4),\n", - " (102, 6),\n", - " (103, 5),\n", - " (104, 2),\n", - " (105, 1),\n", - " (106, 7),\n", - " (107, 3),\n", - " (108, 6),\n", - " (109, 1),\n", - " (110, 2),\n", - " (111, 5),\n", - " (112, 5),\n", - " (113, 2),\n", - " (114, 4),\n", - " (115, 5),\n", - " (116, 5),\n", - " (117, 2),\n", - " (118, 2),\n", - " (119, 3),\n", - " (120, 6),\n", - " (121, 3),\n", - " (122, 3),\n", - " (123, 2),\n", - " (124, 6),\n", - " (125, 1),\n", - " (126, 8),\n", - " (127, 5),\n", - " (128, 2),\n", - " (130, 1),\n", - " (131, 3),\n", - " (132, 5),\n", - " (133, 2),\n", - " (134, 1),\n", - " (135, 1),\n", - " (136, 2),\n", - " (137, 2),\n", - " (138, 3),\n", - " (139, 2),\n", - " (140, 1),\n", - " (141, 1),\n", - " (142, 4),\n", - " (143, 2),\n", - " (144, 3),\n", - " (145, 3),\n", - " (146, 4),\n", - " (147, 7),\n", - " (148, 6),\n", - " (149, 1),\n", - " (150, 6),\n", - " (151, 3),\n", - " (152, 4),\n", - " (153, 1),\n", - " (154, 1),\n", - " (155, 1),\n", - " (157, 5),\n", - " (158, 4),\n", - " (159, 3),\n", - " (160, 3),\n", - " (161, 5),\n", - " (162, 1),\n", - " (163, 3),\n", - " (164, 6),\n", - " (165, 2),\n", - " (166, 3),\n", - " (167, 2),\n", - " (168, 6),\n", - " (169, 3),\n", - " (170, 4),\n", - " (171, 6),\n", - " (172, 2),\n", - " (173, 4),\n", - " (174, 1),\n", - " (175, 3),\n", - " (176, 2),\n", - " (177, 2),\n", - " (178, 4),\n", - " (179, 3),\n", - " (180, 5),\n", - " (181, 6),\n", - " (182, 2),\n", - " (183, 5),\n", - " (184, 7),\n", - " (185, 6),\n", - " (186, 1),\n", - " (187, 5),\n", - " (188, 2),\n", - " (189, 1),\n", - " (190, 4),\n", - " (192, 5),\n", - " (193, 2),\n", - " (194, 2),\n", - " (195, 5),\n", - " (196, 4),\n", - " (198, 1),\n", - " (199, 4),\n", - " (200, 2),\n", - " (201, 4),\n", - " (202, 3),\n", - " (203, 3),\n", - " (204, 5),\n", - " (205, 2),\n", - " (206, 2),\n", - " (207, 4),\n", - " (208, 4),\n", - " (209, 3),\n", - " (210, 5),\n", - " (211, 2),\n", - " (212, 4),\n", - " (213, 1),\n", - " (214, 5),\n", - " (216, 1),\n", - " (217, 3),\n", - " (218, 4),\n", - " (219, 6),\n", - " (220, 3),\n", - " (221, 2),\n", - " (222, 4),\n", - " (223, 3),\n", - " (224, 2),\n", - " (225, 6),\n", - " (226, 3),\n", - " (227, 3),\n", - " (228, 1),\n", - " (229, 4),\n", - " (230, 5),\n", - " (231, 4),\n", - " (232, 4),\n", - " (233, 5),\n", - " (234, 5),\n", - " (235, 4),\n", - " (236, 3),\n", - " (238, 2),\n", - " (239, 4),\n", - " (240, 4),\n", - " (241, 4),\n", - " (242, 7),\n", - " (243, 4),\n", - " (244, 2),\n", - " (245, 1),\n", - " (246, 2),\n", - " (247, 3),\n", - " (248, 5),\n", - " (249, 2),\n", - " (250, 9),\n", - " (251, 3),\n", - " (252, 5),\n", - " (253, 5),\n", - " (254, 2),\n", - " (255, 3),\n", - " (256, 4),\n", - " (257, 4),\n", - " (258, 4),\n", - " (259, 2),\n", - " (260, 4),\n", - " (261, 3),\n", - " (262, 4),\n", - " (263, 6),\n", - " (264, 3),\n", - " (265, 3),\n", - " (266, 5),\n", - " (267, 1),\n", - " (268, 6),\n", - " (269, 1),\n", - " (270, 1),\n", - " (271, 3),\n", - " (272, 8),\n", - " (273, 2),\n", - " (274, 4),\n", - " (275, 4),\n", - " (276, 5),\n", - " (277, 2),\n", - " (278, 3),\n", - " (279, 5),\n", - " (280, 3),\n", - " (281, 6),\n", - " (282, 5),\n", - " (283, 3),\n", - " (284, 5),\n", - " (285, 5),\n", - " (286, 6),\n", - " (287, 3),\n", - " (288, 3),\n", - " (289, 4),\n", - " (290, 3),\n", - " (291, 1),\n", - " (292, 3),\n", - " (293, 1),\n", - " (294, 1),\n", - " (295, 2),\n", - " (296, 6),\n", - " (297, 4),\n", - " (298, 3),\n", - " (299, 5),\n", - " (300, 1)]" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "freq_count = {}\n", - "for key in long_list:\n", - " if key not in freq_count:\n", - " freq_count[key]=1\n", - " else:\n", - " freq_count[key]+=1\n", - "\n", - "list(sorted(freq_count.items(), key=lambda x: x[0]))" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [], - "source": [ - "value_freq = {}\n", - "for k in long_list:\n", - " if k in value_freq:\n", - " value_freq[k] += 1 #value_freq[k] + 1\n", - " else:\n", - " value_freq[k] = 1 # 0 + 1" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "dict_items([(11, 2), (230, 5), (127, 5), (183, 5), (142, 4), (186, 1), (256, 4), (182, 2), (184, 7), (50, 4), (266, 5), (179, 3), (22, 4), (30, 6), (59, 3), (236, 3), (155, 1), (57, 6), (262, 4), (279, 5), (107, 3), (98, 2), (271, 3), (240, 4), (276, 5), (23, 3), (170, 4), (207, 4), (123, 2), (228, 1), (231, 4), (205, 2), (161, 5), (125, 1), (212, 4), (224, 2), (34, 5), (272, 8), (106, 7), (164, 6), (26, 5), (263, 6), (3, 5), (234, 5), (244, 2), (260, 4), (135, 1), (29, 3), (116, 5), (44, 3), (206, 2), (131, 3), (218, 4), (201, 4), (140, 1), (208, 4), (130, 1), (247, 3), (227, 3), (242, 7), (112, 5), (138, 3), (192, 5), (7, 5), (268, 6), (168, 6), (5, 6), (246, 2), (199, 4), (6, 6), (300, 1), (54, 1), (69, 3), (64, 4), (61, 3), (15, 4), (288, 3), (190, 4), (78, 4), (165, 2), (178, 4), (71, 3), (62, 4), (75, 4), (2, 8), (52, 3), (195, 5), (80, 4), (90, 3), (33, 4), (241, 4), (39, 4), (32, 3), (160, 3), (172, 2), (108, 6), (144, 3), (251, 3), (278, 3), (120, 6), (99, 5), (148, 6), (185, 6), (136, 2), (235, 4), (114, 4), (229, 4), (88, 3), (225, 6), (250, 9), (152, 4), (0, 3), (252, 5), (173, 4), (283, 3), (72, 2), (94, 3), (76, 6), (226, 3), (4, 4), (28, 2), (175, 3), (56, 3), (249, 2), (19, 3), (203, 3), (196, 4), (216, 1), (280, 3), (102, 6), (74, 3), (277, 2), (159, 3), (63, 4), (124, 6), (166, 3), (137, 2), (14, 3), (255, 3), (41, 4), (187, 5), (60, 2), (147, 7), (84, 5), (10, 6), (35, 5), (248, 5), (163, 3), (171, 6), (174, 1), (219, 6), (290, 3), (239, 4), (42, 1), (103, 5), (58, 4), (181, 6), (18, 2), (111, 5), (119, 3), (210, 5), (213, 1), (286, 6), (285, 5), (91, 2), (232, 4), (1, 5), (275, 4), (176, 2), (65, 4), (12, 2), (253, 5), (150, 6), (157, 5), (31, 4), (95, 5), (96, 2), (105, 1), (261, 3), (146, 4), (217, 3), (134, 1), (8, 2), (46, 3), (93, 6), (264, 3), (53, 4), (293, 1), (238, 2), (122, 3), (85, 1), (221, 2), (77, 4), (13, 2), (27, 3), (17, 2), (296, 6), (297, 4), (115, 5), (66, 3), (145, 3), (254, 2), (20, 3), (49, 1), (289, 4), (222, 4), (194, 2), (193, 2), (126, 8), (83, 5), (104, 2), (274, 4), (267, 1), (223, 3), (121, 3), (257, 4), (214, 5), (291, 1), (284, 5), (162, 1), (204, 5), (180, 5), (79, 2), (45, 2), (139, 2), (158, 4), (273, 2), (258, 4), (36, 6), (287, 3), (132, 5), (270, 1), (47, 2), (86, 1), (143, 2), (233, 5), (73, 1), (133, 2), (48, 5), (100, 3), (87, 2), (292, 3), (243, 4), (298, 3), (282, 5), (117, 2), (128, 2), (55, 1), (265, 3), (202, 3), (189, 1), (101, 4), (67, 7), (109, 1), (177, 2), (51, 3), (220, 3), (188, 2), (21, 2), (68, 2), (281, 6), (294, 1), (82, 2), (9, 2), (38, 1), (167, 2), (40, 2), (113, 2), (209, 3), (97, 4), (118, 2), (299, 5), (81, 5), (151, 3), (169, 3), (149, 1), (141, 1), (295, 2), (43, 1), (24, 2), (70, 2), (110, 2), (25, 1), (37, 1), (198, 1), (200, 2), (211, 2), (89, 3), (154, 1), (153, 1), (92, 1), (259, 2), (269, 1), (16, 1), (245, 1)])\n" - ] - } - ], - "source": [ - "print(value_freq.items())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.12: find the first value appears 3 times in a list" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "26\n" - ] - } - ], - "source": [ - "freq_count = {}\n", - "for key in long_list:\n", - " if key not in freq_count:\n", - " freq_count[key]=1\n", - " else: \n", - " freq_count[key]+=1\n", - " if freq_count[key] == 3:\n", - " print(key)\n", - " break" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.13: print the following pattern of 10 rows and 19 columns" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "```\n", - "*******************\n", - "---------*---------\n", - "********---********\n", - "-------*****-------\n", - "******-------******\n", - "-----*********-----\n", - "****-----------****\n", - "---*************---\n", - "**---------------**\n", - "-*****************-\n", - "```" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "*******************\n", - "---------*---------\n", - "********---********\n", - "-------*****-------\n", - "******-------******\n", - "-----*********-----\n", - "****-----------****\n", - "---*************---\n", - "**---------------**\n", - "-*****************-\n" - ] - } - ], - "source": [ - "n_rows = 10\n", - "n_cols = 19\n", - "\n", - "for i in range(10):\n", - " if i == 0:\n", - " print(\"*\"*n_cols)\n", - " else:\n", - " if i % 2 == 1:\n", - " side, mid = \"-\", \"*\"\n", - " else:\n", - " side, mid = \"*\", \"-\"\n", - " print(side*(n_rows-i) + mid*(2*i -1) + side*(n_rows-i))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.14: Construct a geometric progression\n", - "- Xn = a* r^(n-1)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], - "source": [ - "first_term, ratio = 512, 1.5\n", - "length = 20" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[512.0, 768.0, 1152.0, 1728.0, 2592.0, 3888.0, 5832.0, 8748.0, 13122.0, 19683.0, 29524.5, 44286.75, 66430.125, 99645.1875, 149467.7812, 224201.6719, 336302.5078, 504453.7617, 756680.6426, 1135020.9639]\n" - ] - } - ], - "source": [ - "gp_list = [round(first_term*(ratio**(n-1)), 4) for n in range(1,length+1)]\n", - "print(gp_list)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.15: find the start time of Einstein’s presentation\n", - "Suppose a presentation session at a conference starts at 8:05am, each speaker is given 25 minutes and they present in the ascending order of their surname, when does Einstein start to present?" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['Erwin Schroedinger', 'Wolfgang Pauli', 'Max Born', 'Niels Bohr', 'Max Planck', 'Madame Curie', 'Hendrik Antoon Lorentz', 'Albert Einstein', 'Paul Langevin', 'Louis Victor de Broglie', 'Paul Dirac', 'Werner Heisenberg']\n" - ] - } - ], - "source": [ - "physicists = ['Erwin Schroedinger', 'Wolfgang Pauli', 'Max Born', 'Niels Bohr', 'Max Planck', 'Madame Curie', 'Hendrik Antoon Lorentz', 'Albert Einstein', 'Paul Langevin', 'Louis Victor de Broglie', 'Paul Dirac', 'Werner Heisenberg']\n", - "print(physicists)" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['Niels Bohr',\n", - " 'Max Born',\n", - " 'Louis Victor de Broglie',\n", - " 'Madame Curie',\n", - " 'Paul Dirac',\n", - " 'Albert Einstein',\n", - " 'Werner Heisenberg',\n", - " 'Paul Langevin',\n", - " 'Hendrik Antoon Lorentz',\n", - " 'Wolfgang Pauli',\n", - " 'Max Planck',\n", - " 'Erwin Schroedinger']" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted_physicists = sorted(physicists, key=lambda x: x.split()[-1])\n", - "sorted_physicists" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "125" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "present_time = {physicist: index*25 for index, physicist in enumerate(sorted_physicists)}\n", - "present_time['Albert Einstein']" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "scrolled": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Einstein 's presentation time: 10:10 \n" - ] - } - ], - "source": [ - "from datetime import datetime, timedelta\n", - "time_str = '8:05'\n", - "time_format = '%H:%M'\n", - "# create datetime object from timestamp string\n", - "start_time = datetime.strptime(time_str, time_format)\n", - "#Add 125 mins to start_time, which will be Einstein's start time\n", - "final_time = start_time + timedelta(minutes=present_time['Albert Einstein'])\n", - "\n", - "# Convert datetime object to string in specific format \n", - "final_time_str = final_time.strftime(time_format)\n", - "print(f\"Einstein 's presentation time: {final_time_str} \")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Solution" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "10:10\n" - ] - } - ], - "source": [ - "surname = [i.split()[-1] for i in physicists] #Assume surname is the last word of each name\n", - "surname.sort()\n", - "start_time = (8*60 + 5) #start time convert to minutes\n", - "v = start_time + 25*surname.index(\"Einstein\")\n", - "print(f'{v//60:02d}:{v%60:02d}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 1.16: list words that have appeared at least 3 times" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "speech = ['the United States has conducted an operation that killed Osama bin Laden',\n", - " 'Abu Bakr al-Baghdadi is dead',\n", - " 'the United States launched a targeted operation against that compound',\n", - " 'they did a lot of shooting and they did a lot of blasting even not going through the front door You know you would think you go through the door If you are a normal person you say Knock knock May I come in',\n", - " 'After a firefight they killed Osama bin Laden and took custody of his body',\n", - " 'He died like a dog',\n", - " 'Yet his death does not mark the end of our effort',\n", - " 'a beautiful dog a talented dog',\n", - " 'We give thanks for the men who carried out this operation',\n", - " 'And I dont get any credit for this but thats okay I never do But here we are',\n", - " 'May God bless you And may God bless the United States of America',\n", - " 'And Im writing a book I think I wrote 12 books All did very well']" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "word_count = dict()\n", - "for sentence in speech:\n", - " for word in sentence.split():\n", - " word = word.lower()\n", - " if word not in word_count:\n", - " word_count[word] = 1\n", - " else:\n", - " word_count[word] += 1" - ] - }, - { - "cell_type": "code", - "execution_count": 36, - "metadata": {}, - "outputs": [], - "source": [ - "freq_3 = [k for k,v in word_count.items() if v >= 3]" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "data": { - "text/plain": [ - "['the',\n", - " 'united',\n", - " 'states',\n", - " 'operation',\n", - " 'a',\n", - " 'they',\n", - " 'did',\n", - " 'of',\n", - " 'and',\n", - " 'you',\n", - " 'may',\n", - " 'i',\n", - " 'dog']" - ] - }, - "execution_count": 37, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "freq_3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Solution" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [], - "source": [ - "words = [word.lower() for sentence in speech for word in sentence.split()]" - ] - }, - { - "cell_type": "code", - "execution_count": 38, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "the united states operation a they did of and you may i dog\n" - ] - } - ], - "source": [ - "word_count = {}\n", - "for w in words:\n", - " word_count[w] = word_count.get(w, 0) + 1\n", - "print(\" \".join([w for w,c in word_count.items() if c >= 3]))" - ] - }, - { - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/W1_Python_Basics/tutorial_1.ipynb b/W1_Python_Basics/tutorial_1.ipynb deleted file mode 100644 index 9e79161..0000000 --- a/W1_Python_Basics/tutorial_1.ipynb +++ /dev/null @@ -1,725 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 1.21: Find the pair of nearest points in Euclidean distance\n", - "\n", - "Give a list of 200 2-dimensional points" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [], - "source": [ - "points = [[1.6917766692855842, -5.755629277630385], [7.675827069862372, 7.301699114949773], [-3.2909129520196334, 9.613848011649935], [-9.085072103632527, -1.494685042518995], [-1.4697584875414886, -2.7246611030972367], [-2.976539234942413, -4.837062248394437], [-5.764304539098299, 2.993570134491293], [-7.315877529023922, -9.705105482173941], [1.707258575977411, 8.485934115270496], [-8.351619858350414, -5.223846451971372], [-5.828795444668502, 3.976366472397393], [8.720271552698694, -3.2124379846092825], [-0.4054482808742037, 9.317930145526955], [6.510986951874475, -2.1819354371980904], [-2.9962592160097756, -7.31509680893523], [9.083360339101048, 7.829967068419251], [-1.3331436878552552, 3.1603946549411432], [6.458132015006093, 8.822434340960669], [7.16827365354672, -3.4508012637846512], [-5.326845746838891, 9.040483027647156], [4.876441225663108, 5.232449738531539], [8.712743288792506, -3.7280349050848205], [7.466241207765329, 2.379265289757564], [-0.9978936202890551, 1.6449368506129112], [-2.6773431893653266, -0.40694827311359916], [-1.8106293810449987, 2.213838668872807], [4.947071131296752, 3.8097106485733008], [5.950466307087394, -7.2512068192895125], [-1.1945786627066717, -5.044692372482798], [2.8811835000735186, 8.851997733796221], [-0.2955365925438471, -9.53917142360364], [-2.011593976593165, -3.542159913868959], [-5.769156935219925, -5.5530087458111606], [9.295871879150603, -3.1240063531616125], [9.756200956431801, 6.479447636789221], [0.8652659943599339, 7.223803402253235], [-3.0332492431783713, -2.1682838845029355], [-0.46657573289961896, 6.8578688639078464], [-2.8117123795590304, -9.572150259865635], [7.203169784969749, 8.753192289873127], [5.224452974702636, 6.857696807277627], [-0.049900556065052726, -1.6942071762016973], [3.5917999402331073, 5.805997834258715], [-5.726479558318768, -7.825976148522635], [4.4719508762928974, -0.47119270370785493], [-8.51658927302788, 9.019684845294073], [9.998303580126834, 1.0909413091749443], [-7.490707783997972, -4.918960983306291], [-2.3814557996463215, 0.4179856971303444], [-4.74392775076129, -4.954224114510013], [-3.3798603785546284, 7.4349511827236405], [3.348941636633935, -4.119066801277675], [3.069597715313229, 8.095932206766918], [-9.977767715384749, 6.31860517880245], [-7.694480444296634, -2.2312884198209426], [7.009378799427232, -9.813278209833005], [-6.892764172568169, 0.4037318298032808], [1.934551861184664, 9.647259153474256], [-1.684970151131278, 6.715523798836713], [4.778791910872442, -6.302597588632741], [7.880213948051896, -6.87757837319777], [3.018764954167871, 9.55577737941606], [9.442098648513728, -1.7971299117298027], [4.294009056182848, 2.9257922144291086], [-7.488141519192402, 3.194146869954558], [4.4044943363257865, 3.47156887284239], [-5.265210866237737, 0.935707859404797], [1.0874401120301478, 4.769687266008177], [3.6677610968015735, 2.329559760946882], [1.3264496075559418, 6.8853295396453476], [2.5218992542292025, -5.3065171699363445], [-6.891179995601471, 1.4638922450737049], [-4.104604058398198, -0.3519967592988227], [-6.387767854843327, -4.577263623649737], [5.677380281111347, -7.529320047947541], [6.8499814135785435, 2.7651117469683975], [4.524713991980372, 7.031248939975825], [-6.219936466401483, 6.892438002621454], [7.118149238188241, -9.529551925292782], [4.114057119430395, -2.8804850370519564], [1.1264331754207308, 9.342444010097452], [-3.3387597997519496, -1.030669371597714], [2.754752556298641, -3.8303761593096564], [2.909388807772359, -5.627376431102753], [4.069630695597288, 4.094098821729082], [-0.22956514974007902, -4.58853096311544], [7.534625539128605, -4.639398935950235], [4.0975226435368235, 1.7820187555361073], [4.523097584062741, 1.049588730388077], [8.417023917682236, 0.1800789755507548], [0.7221429129456567, 6.043776101932181], [7.951069747757323, 3.5232376580146934], [4.436388479108524, 1.9518412860140444], [0.8948126626225257, 1.6870313023848187], [-8.572283501649252, 7.636418415404268], [-7.598099763010668, 9.74677805351963], [-5.474665381459111, -0.09997403697378004], [-9.62348607265123, 8.1817556106746], [4.832941301248653, -7.471586076153429], [0.05489249120935469, 4.427018862646381], [-0.7623078015360356, -4.907223326092369], [5.034440191453175, -7.262422368215999], [0.6749115867488484, 1.0617316506040897], [-5.1257522163309694, 3.0558877666004243], [7.989879083992175, 6.113310630467961], [-6.717271141351702, 6.257733867841495], [2.983926361240556, 3.042070100993019], [5.110723815722771, 9.969387392449438], [7.979605659313002, -3.119594793941558], [2.8722736848244175, -8.92267951192901], [1.4725245815339516, 7.7370401415203425], [5.418909068505318, -9.899664895856628], [-0.3293559589320534, -9.437455767069785], [-5.34092368773914, 0.9864061312783186], [-5.154479072122699, 6.40140805792705], [-0.9157534309671682, -3.9493086221799834], [6.995617487705161, 4.338249584691781], [-4.621252431635439, -5.671606152930753], [-7.925718226173945, 5.084347460461391], [-9.208656699649092, 2.2542831481077954], [2.677446578667597, -2.815260402542414], [1.5725772741199417, 5.984661070798369], [-8.214349445840588, 2.8719923126330187], [-5.250694847383057, 8.186106947277043], [-9.602658269493816, 9.444386484846465], [9.115835186422256, 5.871935528361178], [-2.5287196350232737, 2.887246469932851], [-2.1372641737135734, -1.8391371234033809], [-1.1082552861090988, -4.2077726793698496], [4.629226584152599, -1.8924358944589734], [-5.2525786527691665, -9.369867782433111], [9.689666432703984, 8.631856666441546], [-3.1058640538038906, -7.112691119818997], [3.8351850067247675, -7.816140083215879], [8.059420357182002, -3.9918994148213045], [8.987126313071869, 9.670169215984295], [-8.004125422134386, -7.1932295635881065], [-0.06738368787870286, 4.151225812072738], [-6.321804627995416, 6.465945820534664], [-6.272914208292708, -6.651387059839684], [-0.650918077356728, 1.1571804929060008], [9.900367553654284, -9.549655307552209], [-5.356214337566534, -1.5157332931067398], [-5.493398811827042, -5.103215154502985], [4.394427744530926, -6.258852539216266], [0.651214329260787, 8.205110848341754], [-2.887747978726665, 0.45437176710394667], [7.2358298248090875, -0.7626602653399406], [-1.6802984837606445, -1.521300620569285], [6.2871381561148745, 7.550379731999151], [8.828265968582258, -5.450358190359445], [-2.771419010097665, 4.965733736649366], [7.283791183364258, -9.330647069466309], [1.1503066518591716, -1.494280922589116], [5.430985505849231, 3.6506997889161177], [6.368883543730131, 2.5665925873045214], [8.27268807049646, -2.8108071086508613], [-8.761049538238906, -1.6668399813187218], [6.969563475322449, 4.870653532707438], [-3.8088639686044923, -8.04770050129066], [-6.588753626385426, -5.479445503860109], [0.3628758153674525, -7.375003116652234], [4.2110293083088735, -8.173588108962464], [9.109404060819152, 5.0945898294577425], [1.202164552896999, -6.704377860207917], [3.678524338607412, -6.480872921026548], [-9.2398934138698, 9.76162162677548], [5.014304634637492, -2.4366142669971076], [-0.7032174537587714, -8.412492474901585], [-7.914280615312719, -9.611747935706859], [8.375659961940777, 8.983443372571148], [-3.3398204611856848, -4.1187025796210825], [7.776476441020563, -2.147519947412942], [6.021515870950164, 9.586902937160275], [5.399893902345628, -4.2287458010492145], [1.1876175402532994, -1.6866656645274158], [9.74486427533984, 4.557794093707109], [-9.224676163399579, -2.700399005920211], [0.8443253817877387, 5.148506043849885], [3.8089155234248278, -0.08432848625492895], [8.657341530126452, 9.731798284743121], [5.54498708607046, -9.173588536034211], [-3.324039445073714, 9.816471573057132], [3.4925222371530076, -4.5624259495605095], [-9.58522266877101, -2.958387712219963], [-6.1029158407825275, 0.3190439014138118], [2.9081452608597242, 0.15094304627423938], [8.14261912316013, 0.14005581572142312], [-9.86297822478999, 9.9630163124958], [2.8257928317496344, -2.7283387054290165], [3.7547434905675114, -1.7952181505798883], [-5.749168201073395, 6.1766418276003705], [-4.680119791390682, 8.930237286122129], [-3.953594775616896, 6.842726263223426], [8.502438568323704, -0.7444855789600986], [-2.9955321537705615, 3.3497140964060073], [-2.1949766474129113, 2.0897368044250157], [8.72756539060871, 4.6607545572283104], [-4.153754350587191, 2.3678095388120113], [4.862091715463841, 2.1254725176755827]]" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "200" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import math\n", - "len(points)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Min = 0.0911 where points are [-5.265210866237737, 0.935707859404797], and [-5.34092368773914, 0.9864061312783186] \n" - ] - } - ], - "source": [ - "\n", - "dist_dict = dict()\n", - "for i in range(len(points)):\n", - " for j in range(i+1, len(points)):\n", - " dist_dict[(i,j)] = math.sqrt((points[i][0] - points[j][0])**2 + (points[i][1] - points[j][1])**2)\n", - "\n", - "pair, min_dist = min(dist_dict.items(), key=lambda x: x[1]) \n", - "print(f\"Min = {min_dist:.4f} where points are {points[pair[0]]}, and {points[pair[1]]} \")" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0.09111940578529276 [-5.265210866237737, 0.935707859404797] [-5.34092368773914, 0.9864061312783186]\n" - ] - } - ], - "source": [ - "n = len(points)\n", - "min_dist = float(\"inf\") \n", - "min_i, min_j = 0,0\n", - "for i in range(n):\n", - " for j in range(i+1, n):\n", - " d = math.sqrt((points[i][0] - points[j][0])**2 + (points[i][1] - points[j][1])**2)\n", - " if d < min_dist:\n", - " min_dist, min_i, min_j = d, i, j\n", - " \n", - "print(min_dist, points[min_i],points[min_j]) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 1.22: Find longest palindrome\n", - "\n", - "if two palindromes are of same length, return the one appears first
\n", - "optional part: if two palindromes are of same length, return the one appears first in alphabetical order" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "e.g. s = 'abbabcdefghijihgfedcbaaabbbbaaaabbaaaabbbbaaabc' => return 'cbaaabbbbaaaabbaaaabbbbaaabc'" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [], - "source": [ - "s = 'abbabcdefghijihgfedcbaaabbbbaaaabbaaaabbbbaaabc'" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'abcdefghijihgfedcba'" - ] - }, - "execution_count": 24, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "s[3:22]" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": { - "scrolled": true - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "28 cbaaabbbbaaaabbaaaabbbbaaabc\n" - ] - } - ], - "source": [ - "max_value = float(\"-inf\")\n", - "palindrome = \"\"\n", - "\n", - "for i in range(len(s)):\n", - " for j in range(i+1, len(s)):\n", - " if s[i:j+1] == s[i:j+1][::-1]: #j + 1 as s[i:j+1] as not including j+1\n", - " pal_len = len(s[i:j+1]) \n", - " if pal_len > max_value:\n", - " max_value = pal_len\n", - " palindrome = s[i:j+1]\n", - "\n", - "print(max_value, palindrome)" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "{1: 'a', 3: 'aaa', 19: 'abcdefghijihgfedcba', 5: 'baaab', 4: 'abba', 2: 'aa', 10: 'aaabbbbaaa', 8: 'bbaaaabb', 28: 'cbaaabbbbaaaabbaaaabbbbaaabc'}\n" - ] - } - ], - "source": [ - "n = len(s)\n", - "palindrome = {}\n", - "\n", - "#Case 1 - Pal is Odd: aba - i is in the center\n", - "for i in range(n):\n", - " j = 1\n", - " while( j <= i and j < n - i): #i - j >=0 => i >= j; i+j < n => j < n - i\n", - " if s[i-j] != s[i+j]:\n", - " break\n", - " j+=1\n", - " #len_pal = 2*j - 1 as we double counts (2*j) the center, so need to minus 1 center\n", - " #s[i-j+1:i+j] < palindrome[2*j -1] to take care \"return the one appears first in alphabetical order\" \n", - " if 2*j -1 not in palindrome or s[i-j+1:i+j] < palindrome[2*j -1]: \n", - " palindrome[2*j -1] = s[i-j+1:i+j]\n", - "\n", - "#Case 2 - Pal is Even: abba i and i+1 in the center\n", - "for i in range(n-1):\n", - " if s[i] == s[i+1]:\n", - " j = 1\n", - " while( j <= i and j < n - i - 1): #i - j >=0 => i >= j; i+j < n-1 => j < n - i -1\n", - " if s[i-j] != s[i+1+j]:\n", - " break\n", - " j+=1\n", - " if 2*j not in palindrome or s[i-j+1:i+1+j] < palindrome[2*j]: \n", - " palindrome[2*j] = s[i-j+1:i+1+j]\n", - "\n", - "print(palindrome)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 1.23 : Largest number in a string matching -- in single scan\n", - "\n", - "e.g. string = 'abc123def789.456' => return 789.456" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], - "source": [ - "s = 'abc123def789.456' " - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "['123', '789.456']\n", - "789.456\n" - ] - } - ], - "source": [ - "import re\n", - "\n", - "x = re.findall(r\"\\d+.\\d+\", string)\n", - "print(x)\n", - "print(max(x, key=lambda x: len(x)))" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "789.456\n" - ] - } - ], - "source": [ - "n = len(s)\n", - "max_float = 0.0\n", - "first, second = '0','0' #2 container\n", - "for i in range(n):\n", - " if s[i].isdigit():\n", - " first += s[i]\n", - " second += s[i]\n", - " elif s[i] == '.':\n", - " max_float = max(max_float, float(second))\n", - " second = first+'.' #use second container to continue after '.'\n", - " first = '0' #reset first container to zero\n", - " elif len(first) > 1 or len(second) > 1: #If we found a char not '.', we need to store the current value\n", - " max_float = max(max_float, max(float(first), float(second)))\n", - " first, second = '0', '0'\n", - " else:\n", - " pass\n", - "\n", - " #In case, it breaks the loop, but yet to compare the final first and second with max_float\n", - "max_float = max(max_float, max(float(first), float(second))) \n", - "print(max_float)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 1.24: Write the naive primality test algorithm" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Basic method : check one by one (the most naive version: check number by number, factor by factor)
\n", - "Example:\n", - "- check if 13 is a prime
\n", - "-- check from all numbers between 2 and 12 inclusive, none of them is a factor of 13
\n", - "-- then we know 13 is a prime
\n", - "- proceed to 14 to check if it is a prime" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Improvement 1: primality can be determined as long as one non-trivial factor is found
\n", - "Improvement 2: do you need to check even numbers? Can an odd number be divided by an even number?
\n", - "Improvement 3: can checking on non-trivial factors be terminated earlier?" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 23, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "num = 13\n", - "def check_primality(num):\n", - " if num % 2 == 0 and num != 2:\n", - " return False\n", - " else:\n", - " for i in range(3, num, 2):\n", - " if num%i == 0:\n", - " return False\n", - " else:\n", - " return True\n", - "\n", - "check_primality(2)" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[2, 3, 5, 7, 9, 11, 13, 15, 17, 19, 23, 25, 29, 31, 35, 37, 41, 43, 47, 49, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 121, 127, 131, 137, 139, 143, 149, 151, 157, 163, 167, 169, 173, 179, 181, 191, 193, 197, 199]\n" - ] - } - ], - "source": [ - "prime = [2]\n", - "for i in range(3, 200, 2):\n", - " is_prime = True\n", - " for f in range(3, int(math.sqrt(i)), 2):\n", - " if i % f == 0:\n", - " is_prime = False\n", - " break\n", - " if is_prime:\n", - " prime.append(i)\n", - "print(prime)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199]\n" - ] - } - ], - "source": [ - "prime = [2]\n", - "for i in range(3,200,2):\n", - " f = 3\n", - " while f*f <=i:\n", - " if i % f == 0:\n", - " break\n", - " f+=2 #Since we dont need to divide by even number\n", - " else:\n", - " prime.append(i)\n", - "print(prime)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 1.25: Sudoku checker (I) -- return the list of possible values for each cell" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "| | | | | | | | | |\n", - "|---|---|---|---|---|---|---|---|---|\n", - "| | |7| | | |1|?|&|\n", - "| |5|9| | | |2|3|%|\n", - "|8|2|3| | | |4|5|6|\n", - "|5|1| | | | | |7|8|\n", - "|9| | |1| |3| | |4|\n", - "| | |4|2| |8|9| | |\n", - "| |7|5|3| |6|8|9| |\n", - "| |8|6| | | |7|1| |\n", - "| |9| | | | | |4| |" - ] - }, - { - "cell_type": "code", - "execution_count": 35, - "metadata": {}, - "outputs": [], - "source": [ - "sudoku1 = [' 7 1 ', ' 59 23 ', '823 456', '51 78', '9 1 3 4', ' 42 89 ', ' 753 689 ', ' 86 71 ', ' 9 4 ']\n", - "sudoku2 = [' ', ' 528 614 ', ' 98 27 ', ' 12 39 ', '735 682', ' 695 741 ', ' 1 3 8 9 ', '42 7 1 65', ' ']\n", - "sudoku3 = [' 76 3 ', ' 13 8 92', ' 4 2 31 ', ' 86 5 9', '26 78', '4 9 82 ', ' 17 5 2 ', '95 3 41 ', ' 2 96 ']" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Example:\n", - "Take the 3x3 square at the upper right corner for example, 1, 2, 3, 4, 5, 6 are already filled. We use '?', '&' and '%' to represent the remaining three positions.
\n", - "7 cannot be in the first row, as there is a 7 in the first row in the 3x3 square upper left corner. So 7 must be at the position '%', so 7 is the only possible value at the cell (row = 2, col = 9), and we write '(2, 9): 7' in one line.
\n", - "Likewise, 8 cannot be in the last column, as there is already a 8 in the last column. So 8 must be at the position '?', we write '(1, 8): 8' to state the only possible value at cell (row = 1, col = 8) is 8.
\n", - "After that, the only missing value in the 3x3 square upper right corner is 9, and it must be at the position '&'. Therefore, we write '(1, 9): 9'.
\n", - "In this exercise, your goal is to list possible values for each cell. When there is uncertainty, you are allowed to list multiple values for one cell, but try your best to keep this list as short as possible, i.e., remove as many impossible values as possible for each cell." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "#### Hint:\n", - "1. Build the initial sudoku board with -1 being unfilled ==> the board is a 2-dimensional array\n", - "2. Build a list of possible values for each cell ==> this should be a 3-dimensional array\n", - "3. If a cell is marked with a value v
\n", - "3a) other cells in the same row should mark v as impossible
\n", - "3b) other cells in the same column should mark v as impossible
\n", - "3c) the 3x3 square where this cell is in should mark v as impossible
\n", - "4. Output the list of possible values for each empty cell" - ] - }, - { - "cell_type": "raw", - "metadata": {}, - "source": [ - "# for sudoku1, as shown above, the result should look like this:\n", - "(1, 1): 4 6\n", - "(1, 2): 4 6\n", - "(1, 4): 4 5 6 8 9\n", - "(1, 5): 2 3 4 5 6 8 9\n", - "(1, 6): 2 4 5 9\n", - "(1, 8): 8\n", - "(1, 9): 9\n", - "(2, 1): 1 4 6\n", - "(2, 4): 4 6 7 8\n", - "(2, 5): 1 4 6 7 8\n", - "(2, 6): 1 4 7\n", - "(2, 9): 7\n", - "(3, 4): 7 9\n", - "(3, 5): 1 7 9\n", - "(3, 6): 1 7 9\n", - "(4, 3): 2\n", - "(4, 4): 4 6 9\n", - "(4, 5): 4 6 9\n", - "(4, 6): 4 9\n", - "(4, 7): 3 6\n", - "(5, 2): 6\n", - "(5, 3): 2 8\n", - "(5, 5): 5 6 7\n", - "(5, 7): 5 6\n", - "(5, 8): 2 6\n", - "(6, 1): 3 6 7\n", - "(6, 2): 3 6\n", - "(6, 5): 5 6 7\n", - "(6, 8): 6\n", - "(6, 9): 1 3 5\n", - "(7, 1): 1 2 4\n", - "(7, 5): 1 2 4\n", - "(7, 9): 2\n", - "(8, 1): 2 3 4\n", - "(8, 4): 4 5 9\n", - "(8, 5): 2 4 5 9\n", - "(8, 6): 2 4 5 9\n", - "(8, 9): 2 3 5\n", - "(9, 1): 1 2 3\n", - "(9, 3): 1 2\n", - "(9, 4): 5 7 8\n", - "(9, 5): 1 2 5 7 8\n", - "(9, 6): 1 2 5 7\n", - "(9, 7): 3 5 6\n", - "(9, 9): 2 3 5" - ] - }, - { - "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], - "source": [ - "def build_sudoku_board(board):\n", - " return [[int(item) if not item.isspace() else -1 for item in row] for row in board]\n", - "\n", - "board = build_sudoku_board(sudoku1)" - ] - }, - { - "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], - "source": [ - "def find_next_empty(puzzle):\n", - " for r in range(9):\n", - " for c in range(9):\n", - " if puzzle[r][c] == -1:\n", - " return (r, c)\n", - " return None, None #if no spaces in the puzzle to make a guess\n", - "\n", - "def is_valid(puzzle, guess, row, col):\n", - " # figures out whether the guess at the row/col of the puzzle is a valid guess\n", - " # returns True or False\n", - " # Let s start with the row:\n", - " row_vals = puzzle[row]\n", - " #Column:\n", - " col_vals = [r[col] for r in puzzle]\n", - " if guess in row_vals:\n", - " return False\n", - " if guess in col_vals:\n", - " return False\n", - " #And then the square 3x3 matrix\n", - " #Find the start index of 3x3 matrix\n", - " row_start = (row//3)*3 #row//3 to identify if first, second or third matrix\n", - " col_start = (col//3)*3\n", - " for r in range(row_start, row_start+3):\n", - " for c in range(col_start, col_start+3):\n", - " if puzzle[r][c] == guess:\n", - " return False\n", - " return True\n", - " \n", - "def solve_sudoku(puzzle):\n", - " # Step 1: Choose somewhere on the puzzle to make a guess\n", - " row, col = find_next_empty(puzzle)\n", - " # Step 1.1: if row, col = None, we finished\n", - " if row is None:\n", - " return True\n", - " # step 2: if there is a place to put a number, then make a guess between 1 and 9\n", - " for guess in range(1,10):\n", - " # step 3: check if this is a valid guess\n", - " if is_valid(puzzle, guess, row, col):\n", - " # Step 3.1: \n", - " puzzle[row][col] = guess\n", - " if solve_sudoku(puzzle):\n", - " return True\n", - " # step 5: it not valid or if nothing gets returned true, then we need to backtrack and try a new number\n", - " puzzle[row][col] = -1\n", - " return False" - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "True" - ] - }, - "execution_count": 30, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "solve_sudoku(board)" - ] - }, - { - "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[[6, 4, 7, 5, 3, 2, 1, 8, 9],\n", - " [1, 5, 9, 6, 8, 4, 2, 3, 7],\n", - " [8, 2, 3, 7, 9, 1, 4, 5, 6],\n", - " [5, 1, 2, 4, 6, 9, 3, 7, 8],\n", - " [9, 6, 8, 1, 7, 3, 5, 2, 4],\n", - " [7, 3, 4, 2, 5, 8, 9, 6, 1],\n", - " [4, 7, 5, 3, 1, 6, 8, 9, 2],\n", - " [2, 8, 6, 9, 4, 5, 7, 1, 3],\n", - " [3, 9, 1, 8, 2, 7, 6, 4, 5]]" - ] - }, - "execution_count": 31, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "board" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, - "outputs": [], - "source": [ - "value = [[-1]*9 for _ in range(9)]\n", - "possible = [[[True]*10 for _ in range(9)] for _ in range(9)] #10 we need to map possible[1] to possible[9], will ignore possible[0]" - ] - }, - { - "cell_type": "code", - "execution_count": 33, - "metadata": {}, - "outputs": [], - "source": [ - "value = []\n", - "for _ in range(9):\n", - " value.append([-1]*9)\n", - "possible = []\n", - "for _ in range(9):\n", - " for _ in range(9):\n", - " possible.append([True]*10)" - ] - }, - { - "cell_type": "code", - "execution_count": 37, - "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "'bool' 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 9\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mvv\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m1\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0;36m10\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mvv\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mv\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m---> 11\u001b[0;31m \u001b[0mpossible\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mi\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mj\u001b[0m\u001b[0;34m]\u001b[0m\u001b[0;34m[\u001b[0m\u001b[0mvv\u001b[0m\u001b[0;34m]\u001b[0m \u001b[0;34m=\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 12\u001b[0m \u001b[0;32mfor\u001b[0m \u001b[0mjj\u001b[0m \u001b[0;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;36m9\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 13\u001b[0m \u001b[0;32mif\u001b[0m \u001b[0mjj\u001b[0m \u001b[0;34m!=\u001b[0m \u001b[0mj\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", - "\u001b[0;31mTypeError\u001b[0m: 'bool' object does not support item assignment" - ] - } - ], - "source": [ - "i = 0\n", - "for s in sudoku1:\n", - " if len(s) != 9:\n", - " print('Length sould be 9', s)\n", - " for j in range(9):\n", - " if s[j] != ' ':\n", - " v = int(s[j])\n", - " value[i][j] = v\n", - " for vv in range(1, 10):\n", - " if vv != v:\n", - " possible[i][j][vv] = False\n", - " for jj in range(9):\n", - " if jj != j:\n", - " possible[i][jj][v] = False\n", - " for ii in range(9):\n", - " if ii != i:\n", - " possible[ii][j][v] = False\n", - " gi, gj = (i // 3)*3, (j//3)*3\n", - " for ii in range(3):\n", - " for jj in range(3):\n", - " if gi + ii != i or gj + jj != j: #to ensure not the same row and col\n", - " possible[gi+ii][gj+jj][v] = False\n", - " i +=1\n", - "for i in range(9):\n", - " for j in range(9):\n", - " if value[i][j] == -1:\n", - " print(f\"({i+1, j+1}): {''.join([str(v) for v in range(1,10) if possible[i][j][v]])}\")" - ] - }, - { - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/W1_Python_Basics/tutorial_1_answer.pdf b/W1_Python_Basics/tutorial_1_answer.pdf deleted file mode 100644 index 168b05da876c30bf029d536240f8540102840d20..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 130604 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\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m40\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m: info() missing 1 required positional argument: 'age'" - ] - } - ], - "source": [ - "info(40)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike is 40 years old.\n", - "Mike is 40 years old.\n" - ] - } - ], - "source": [ - "def info(name, age):\n", - " print(name, 'is', age, 'years old.')\n", - "\n", - "info(name = 'Mike', age = 40)\n", - "info(age = 40, name = 'Mike') " - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike is 40 years old.\n", - "Mike is 35 years old.\n" - ] - } - ], - "source": [ - "def info(name, age = 35):\n", - " print(name, 'is', age, 'years old.')\n", - "\n", - "info('Mike', 40)\n", - "info('Mike')" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike's hobbies: \n", - "Mike's hobbies: hiking, reading\n" - ] - } - ], - "source": [ - "def info(name, *args):\n", - " hobby = []\n", - " for a in args:\n", - " hobby.append(a)\n", - " print(name +\"'s hobbies: \" + ', '.join(hobby))\n", - "\n", - "info('Mike')\n", - "info('Mike', 'hiking', 'reading') " - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike's hobbies: first-hiking, second-reading\n" - ] - } - ], - "source": [ - "def info(name, **kwargs):\n", - " hobby = []\n", - " for k, v in kwargs.items():\n", - " hobby.append(k+'-'+v)\n", - " print(name +\"'s hobbies: \" + ', '.join(hobby))\n", - "\n", - "info('Mike', first='hiking', second='reading')" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Python Data Analysis\n", - "Python Data Analysis\n" - ] - } - ], - "source": [ - "def func(a1, a2, a3):\n", - " print(a1,a2,a3)\n", - " \n", - "args = ('Python', 'Data', 'Analysis')\n", - "func(*args)\n", - "\n", - "kwargs = {'a1' : 'Python', 'a2' : 'Data', 'a3' : 'Analysis'}\n", - "func(**kwargs)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "args: ('I', 'love')\n", - "kwargs: {'first': 'Python programming', 'mid': 'and', 'last': 'Data Analysis'}\n", - "I love Python programming and Data Analysis\n" - ] - } - ], - "source": [ - "def func(*args,**kwargs):\n", - " print('args: ', args)\n", - " print('kwargs: ', kwargs)\n", - " print(' '.join(args), ' '.join(kwargs.values()))\n", - " \n", - "func('I', 'love', first='Python programming', mid='and', last='Data Analysis')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Return" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "(1, 3)\n" - ] - } - ], - "source": [ - "def func1(a,b):\n", - " return a\n", - "\n", - "def func2(a,b):\n", - " return a,b\n", - "\n", - "print(func1(1,3))\n", - "print(func2(1,3))" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1, 3]\n", - "{'a': 1, 'b': 3}\n" - ] - } - ], - "source": [ - "def func3(a,b):\n", - " return [a,b]\n", - "\n", - "def func4(a,b):\n", - " return {'a': a, 'b': b}\n", - "\n", - "print(func3(1,3))\n", - "print(func4(1,3))" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4\n", - "6\n" - ] - } - ], - "source": [ - "def by_factor(factor):\n", - " def multiply(number):\n", - " return factor * number\n", - " return multiply\n", - "\n", - "double = by_factor(2)\n", - "print(double(2))\n", - "print(double(3))" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5\n" - ] - } - ], - "source": [ - "def add(a, b):\n", - " c = a + b\n", - " return c\n", - "\n", - "result = add(2, 3)\n", - "print(result)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5\n", - "None\n" - ] - } - ], - "source": [ - "def add2(a, b):\n", - " c = a + b\n", - " print(c)\n", - "\n", - "result2 = add2(2, 3)\n", - "print(result2)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3.7200759760208356e-44\n", - "0.5\n", - "1.0\n" - ] - } - ], - "source": [ - "def logistic(x):\n", - " return 1/(1+math.exp(-x))\n", - "\n", - "print(logistic(-100))\n", - "print(logistic(0))\n", - "print(logistic(100))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Variable Scope" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "local\n" - ] - }, - { - "ename": "NameError", - "evalue": "name 'y' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mtest\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mNameError\u001b[0m: name 'y' is not defined" - ] - } - ], - "source": [ - "def test():\n", - " y = 'local'\n", - " print(y)\n", - "\n", - "test()\n", - "print(y) " - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "global\n", - "global\n" - ] - } - ], - "source": [ - "y = 'global'\n", - "def test():\n", - " global y\n", - " print(y)\n", - "\n", - "test()\n", - "print(y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.11: find out all the prime numbers in a given list" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "num_list = [649, 778, 652, 653, 912, 402, 917, 536, 664, 922, 284, 158, 415, 672, 673, 33, 419, 414, 421, 811, 683, 48, 818, 566, 567, 310, 580, 838, 199, 586, 458, 460, 337, 728, 604, 94, 607, 865, 354, 230, 367, 752, 625, 371, 505, 635, 893, 382, 767]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Lambda Expressions" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "add=lambda x, y: x+y\n", - "add(1, 2) " - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum = lambda x: 1\n", - "sum([2,3])" - ] - }, - { - "cell_type": "code", - "execution_count": 48, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[3, 2, 4, 1, 5]" - ] - }, - "execution_count": 48, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted([1, 2, 3, 4, 5], key = lambda x: abs(3 - x))" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 3, 5]" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(filter(lambda n: n % 2 == 1, [1, 2, 3, 4, 5]))" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[2, 3, 4]" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(map(lambda x: x + 1, [1, 2, 3]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.12: use the prime function you created in exercise 1 and lambda to find out all the prime numbers in a given list in one line" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Modules" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3.141592653589793\n", - "3.141592653589793\n", - "3.141592653589793\n" - ] - } - ], - "source": [ - "import math\n", - "print(math.pi)\n", - "\n", - "import math as mt\n", - "print(mt.pi)\n", - "\n", - "from math import pi\n", - "print(pi)\n", - "\n", - "from math import * " - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7\n", - "0.187558625103874\n", - "3\n", - "b\n" - ] - } - ], - "source": [ - "import random as rnd\n", - "print(rnd.randint(0, 10))\n", - "print(rnd.random())\n", - "lst = list(range(10))\n", - "print(rnd.choice(lst))\n", - "print(random.choice('abc'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Classes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Class and Instance" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1469952256\n", - "\n" - ] - } - ], - "source": [ - "a = 2\n", - "print(id(a))\n", - "print(type(a)) " - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1469952256\n", - "\n" - ] - } - ], - "source": [ - "b = 2\n", - "print(id(b))\n", - "print(type(b)) " - ] - }, - { - "cell_type": "code", - "execution_count": 91, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1469952288\n", - "\n" - ] - } - ], - "source": [ - "c = 3\n", - "print(id(c))\n", - "print(type(c)) " - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023259656\n", - "1531023259656\n", - "[1, 2, 3]\n", - "[1, 2, 3]\n", - "1531023259656\n", - "1531023259656\n" - ] - } - ], - "source": [ - "a = [1,2]\n", - "b = a\n", - "print(id(a))\n", - "print(id(b))\n", - "\n", - "b.append(3)\n", - "print(a)\n", - "print(b)\n", - "print(id(a)) \n", - "print(id(b)) " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4426390664\n", - "4426391176\n", - "True\n", - "False\n" - ] - } - ], - "source": [ - "a = [1,2]\n", - "b = [1,2]\n", - "print(id(a))\n", - "print(id(b))\n", - "\n", - "print(a == b)\n", - "print(a is b) " - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4389863968\n", - "4389863968\n", - "True\n", - "True\n" - ] - } - ], - "source": [ - "a = 101\n", - "b = 101\n", - "print(id(a))\n", - "print(id(b))\n", - "\n", - "print(a == b)\n", - "print(a is b) " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4426665552\n", - "4426665104\n", - "True\n", - "False\n" - ] - } - ], - "source": [ - "c = 1001\n", - "d = 1001\n", - "print(id(c)) \n", - "print(id(d)) \n", - "\n", - "print(c == d)\n", - "print(c is d) " - ] - }, - { - "cell_type": "code", - "execution_count": 96, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023200840\n", - "1531023200840\n", - "[[9, 1], 2, 3, 4]\n", - "[[9, 1], 2, 3, 4]\n", - "1531023200840\n", - "1531023200840\n" - ] - } - ], - "source": [ - "a = [[0, 1], 2, 3]\n", - "b = a\n", - "print(id(a))\n", - "print(id(b))\n", - "\n", - "b.append(4)\n", - "b[0][0] = 9\n", - "print(a)\n", - "print(b)\n", - "print(id(a))\n", - "print(id(b))" - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023204040\n", - "1531023260168\n", - "1531023201608\n", - "1531023201608\n", - "[[9, 1], 2, 3]\n", - "[[9, 1], 2, 3, 4]\n" - ] - } - ], - "source": [ - "import copy\n", - "a = [[0, 1], 2, 3]\n", - "b = copy.copy(a)\n", - "print(id(a))\n", - "print(id(b))\n", - "print(id(a[0]))\n", - "print(id(b[0]))\n", - "\n", - "b.append(4)\n", - "b[0][0] = 9\n", - "print(a)\n", - "print(b) " - ] - }, - { - "cell_type": "code", - "execution_count": 98, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023203336\n", - "1531023203784\n", - "1531023200840\n", - "1531022909128\n", - "[[0, 1], 2, 3]\n", - "[[9, 1], 2, 3, 4]\n" - ] - } - ], - "source": [ - "import copy\n", - "a = [[0, 1], 2, 3]\n", - "b = copy.deepcopy(a)\n", - "print(id(a)) \n", - "print(id(b))\n", - "print(id(a[0]))\n", - "print(id(b[0]))\n", - "\n", - "b.append(4)\n", - "b[0][0] = 9\n", - "print(a)\n", - "print(b) " - ] - }, - { - "cell_type": "code", - "execution_count": 99, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023380864\n", - "Hello!\n", - "1531023382824\n" - ] - } - ], - "source": [ - "string = 'Hello'\n", - "print(id(string))\n", - "string += '!'\n", - "print(string)\n", - "print(id(string)) " - ] - }, - { - "cell_type": "code", - "execution_count": 100, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023201032\n", - "[1, 2, 3]\n", - "1531023201032\n" - ] - } - ], - "source": [ - "list1 = [1,2]\n", - "print(id(list1))\n", - "list1 += [3]\n", - "print(list1)\n", - "print(id(list1))" - ] - }, - { - "cell_type": "code", - "execution_count": 101, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean.Chen@smu.edu.sg\n" - ] - } - ], - "source": [ - "class Student:\n", - " pass #skip this part for now\n", - "\n", - "stu_1 = Student()\n", - "stu_1.first = 'Jean'\n", - "stu_1.last = 'Chen'\n", - "stu_1.email = 'Jean.Chen@smu.edu.sg'\n", - "print(stu_1.email) " - ] - }, - { - "cell_type": "code", - "execution_count": 102, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean.Chen@smu.edu.sg\n", - "Zian.Gong@smu.edu.sg\n" - ] - } - ], - "source": [ - "class Student:\n", - " def __init__(self, first, last):\n", - " self.first = first\n", - " self.last = last\n", - " self.email = first + '.' + last + '@smu.edu.sg'\n", - "\n", - "stu_1 = Student('Jean', 'Chen')\n", - "stu_2 = Student('Zian', 'Gong')\n", - "print(stu_1.email) \n", - "print(stu_2.email) " - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean Chen\n", - "Jean Chen\n" - ] - } - ], - "source": [ - "class Student:\n", - " def __init__(self, first, last):\n", - " self.first = first\n", - " self.last = last\n", - " self.email = first + '.' + last + '@smu.edu.sg'\n", - " \n", - " def fullname(self):\n", - " return self.first + ' ' + self.last\n", - "\n", - "stu_1 = Student('Jean', 'Chen')\n", - "print(stu_1.fullname())\n", - "print(Student.fullname(stu_1)) " - ] - }, - { - "cell_type": "code", - "execution_count": 103, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "1\n" - ] - } - ], - "source": [ - "class Student:\n", - " num_of_stu = 0\n", - " def __init__(self, first, last):\n", - " self.first = first\n", - " self.last = last\n", - " self.email = first + '.' + last + '@smu.edu.sg'\n", - " Student.num_of_stu += 1\n", - "\n", - "print(Student.num_of_stu) \n", - "stu_1 = Student('Jean', 'Chen')\n", - "print(Student.num_of_stu) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inheritance" - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "metadata": {}, - "outputs": [], - "source": [ - "class Student:\n", - " def __init__(self, first, last):\n", - " self.first = first\n", - " self.last = last\n", - " self.email = first + '.' + last + '@smu.edu.sg'\n", - " \n", - " def fullname(self):\n", - " return self.first + ' ' + self.last" - ] - }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": {}, - "outputs": [], - "source": [ - "class Rep(Student):\n", - " pass" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean.Chen@smu.edu.sg\n", - "Jean Chen\n" - ] - } - ], - "source": [ - "rep_1 = Rep('Jean', 'Chen') \n", - "print(rep_1.email)\n", - "print(rep_1.fullname())" - ] - }, - { - "cell_type": "code", - "execution_count": 87, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean.Chen@smu.edu.sg\n", - "Jean Chen\n", - "academic\n" - ] - } - ], - "source": [ - "class Rep(Student):\n", - " def __init__(self, first, last, cat):\n", - " super().__init__(first, last)\n", - " self.cat = cat\n", - "\n", - "rep_1 = Rep('Jean', 'Chen', 'academic')\n", - "print(rep_1.email) \n", - "print(rep_1.fullname())\n", - "print(rep_1.cat) " - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'academic representative: Jean Chen'" - ] - }, - "execution_count": 88, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "class Rep(Student):\n", - " def __init__(self, first, last, cat):\n", - " super().__init__(first, last) \n", - " self.cat = cat\n", - "\n", - " def fullname(self):\n", - " return self.cat + ' representative: ' + self.first + ' ' + self.last\n", - " \n", - "rep_1 = Rep('Jean', 'Chen', 'academic')\n", - "rep_1.fullname()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Magic Method" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['__abs__',\n", - " '__add__',\n", - " '__and__',\n", - " '__bool__',\n", - " '__ceil__',\n", - " '__class__',\n", - " '__delattr__',\n", - " '__dir__',\n", - " '__divmod__',\n", - " '__doc__',\n", - " '__eq__',\n", - " '__float__',\n", - " '__floor__',\n", - " '__floordiv__',\n", - " '__format__',\n", - " '__ge__',\n", - " '__getattribute__',\n", - " '__getnewargs__',\n", - " '__gt__',\n", - " '__hash__',\n", - " '__index__',\n", - " '__init__',\n", - " '__init_subclass__',\n", - " '__int__',\n", - " '__invert__',\n", - " '__le__',\n", - " '__lshift__',\n", - " '__lt__',\n", - " '__mod__',\n", - " '__mul__',\n", - " '__ne__',\n", - " '__neg__',\n", - " '__new__',\n", - " '__or__',\n", - " '__pos__',\n", - " '__pow__',\n", - " '__radd__',\n", - " '__rand__',\n", - " '__rdivmod__',\n", - " '__reduce__',\n", - " '__reduce_ex__',\n", - " '__repr__',\n", - " '__rfloordiv__',\n", - " '__rlshift__',\n", - " '__rmod__',\n", - " '__rmul__',\n", - " '__ror__',\n", - " '__round__',\n", - " '__rpow__',\n", - " '__rrshift__',\n", - " '__rshift__',\n", - " '__rsub__',\n", - " '__rtruediv__',\n", - " '__rxor__',\n", - " '__setattr__',\n", - " '__sizeof__',\n", - " '__str__',\n", - " '__sub__',\n", - " '__subclasshook__',\n", - " '__truediv__',\n", - " '__trunc__',\n", - " '__xor__',\n", - " 'bit_length',\n", - " 'conjugate',\n", - " 'denominator',\n", - " 'from_bytes',\n", - " 'imag',\n", - " 'numerator',\n", - " 'real',\n", - " 'to_bytes']" - ] - }, - "execution_count": 81, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dir(int)" - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n", - "3\n" - ] - } - ], - "source": [ - "num = 1\n", - "print(num + 2)\n", - "print(num.__add__(2))" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "class iter_example(): \n", - " def __init__(self, data=1): \n", - " self.data = data \n", - "\n", - " def __iter__(self): \n", - " return self \n", - "\n", - " def __next__(self): \n", - " if self.data > 3:\n", - " raise StopIteration \n", - " else:\n", - " self.data += 1 \n", - " return self.data" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2\n", - "3\n", - "4\n" - ] - } - ], - "source": [ - "for i in iter_example():\n", - " print(i)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Final exercises 2.13, 2.14 and 2.15: class inheritance" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.13: Write a parallelogram class that takes length, width and angle between sides as arguments:\n", - "- it has two functions: perimeter and area\n", - "- create an instant paral with length 5, width 6 and angle 60, print out its perimeter and area\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Write your python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.14: Write a rhombus class that inherits from parallelogram class:\n", - "- create an instant rh with length 5 and angle 60, print out its perimeter and area" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Write your python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.15: Write a square class that inherits from rhombus class:\n", - "- create an instant sq with length 5, print out its perimeter and area\n", - "- write a new function area that will return \"The area of a square with length xxx is xxx\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Write your python code here" - ] - } - ], - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/W2_Function_Lambda/.ipynb_checkpoints/class_exercise_2_submit-checkpoint.ipynb b/W2_Function_Lambda/.ipynb_checkpoints/class_exercise_2_submit-checkpoint.ipynb deleted file mode 100644 index 790c3dd..0000000 --- a/W2_Function_Lambda/.ipynb_checkpoints/class_exercise_2_submit-checkpoint.ipynb +++ /dev/null @@ -1,244 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Python programming and Data Analysis\n", - "\n", - "## Class Exercise 2 -- Python Intermediate" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.11: find out all the prime numbers in a given list" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "num_list = [649, 778, 652, 653, 912, 402, 917, 536, 664, 922, 284, 158, 415, 672, 673, 33, 419, 414, 421, 811, 683, 48, 818, 566, 567, 310, 580, 838, 199, 586, 458, 460, 337, 728, 604, 94, 607, 865, 354, 230, 367, 752, 625, 371, 505, 635, 893, 382, 767]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[649, 653, 917, 415, 673, 33, 419, 421, 811, 683, 567, 199, 337, 607, 865, 367, 625, 371, 505, 635, 893, 767]\n" - ] - } - ], - "source": [ - "import math\n", - "# write your Python code here\n", - "def is_prime(num):\n", - " for i in range(2, math.floor(math.sqrt(num))+1, 2):\n", - " if num%i == 0:\n", - " return False\n", - " return True\n", - "prime_list = [num for num in num_list if is_prime(num)]\n", - "print(prime_list)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.12: use the prime function you created in exercise 1 and lambda to find out all the prime numbers in a given list in one line" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[649, 653, 917, 415, 673, 33, 419, 421, 811, 683, 567, 199, 337, 607, 865, 367, 625, 371, 505, 635, 893, 767]\n" - ] - } - ], - "source": [ - "# write your Python code here\n", - "\n", - "print(list(filter(lambda num: is_prime(num), num_list)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.13: Write a parallelogram class that takes length, width and angle between sides as arguments:\n", - "- it has two functions: perimeter and area\n", - "- create an instant paral with length 5, width 6 and angle 60, print out its perimeter and area\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "import math\n", - "class parallel:\n", - " def __init__(self, length, width, angle):\n", - " self.length = length\n", - " self.width = width\n", - " self.angle = angle\n", - " def perimeter(self):\n", - " return (self.length + self.width)*2\n", - " def area(self):\n", - " return f\"{self.length*self.width*math.sin(math.radians(self.angle)):.2f}\"" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "22\n", - "25.98\n" - ] - } - ], - "source": [ - "paral = parallel(5, 6, 60)\n", - "print(paral.perimeter())\n", - "print(paral.area())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.14: Write a rhombus class that inherits from parallelogram class:\n", - "- create an instant rh with length 5 and angle 60, print out its perimeter and area" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here\n", - "class rhombus(parallel):\n", - " def __init__(self, length, angle):\n", - " self.length = length\n", - " self.angle = angle\n", - " def perimeter(self):\n", - " return 4*self.length\n", - " def area(self):\n", - " return f\"{pow(self.length,2)*math.sin(math.radians(self.angle)):.2f}\"\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "20\n", - "21.65\n" - ] - } - ], - "source": [ - "rh = rhombus(5, 60)\n", - "print(rh.perimeter())\n", - "print(rh.area())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.15: Write a square class that inherits from rhombus class:\n", - "- create an instant sq with length 5, print out its perimeter and area\n", - "- write a new function area that will return \"The area of a square with length xxx is xxx\"" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here\n", - "class square(rhombus):\n", - " def __init__(self, length):\n", - " self.length = length\n", - " def area(self):\n", - " return f\"The area of a square with length {self.length} is {self.length*self.length}\"" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "20\n", - "The area of a square with length 5 is 25\n" - ] - } - ], - "source": [ - "sq = square(5)\n", - "print(sq.perimeter())\n", - "print(sq.area())" - ] - }, - { - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/W2_Function_Lambda/class_exercise_2.ipynb b/W2_Function_Lambda/class_exercise_2.ipynb deleted file mode 100644 index 5efb696..0000000 --- a/W2_Function_Lambda/class_exercise_2.ipynb +++ /dev/null @@ -1,1545 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Python programming and Data Analysis\n", - "\n", - "## Class Exercise 2 -- Python Intermediate" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Before function – Operators " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n", - "False\n", - "False\n", - "True\n" - ] - } - ], - "source": [ - "str1 = 'abc'\n", - "str2 = 'def'\n", - "print('a' in str1)\n", - "print('a' in str2)\n", - "print('a' not in str1)\n", - "print('a' not in str2)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "True\n", - "False\n", - "False\n", - "True\n" - ] - } - ], - "source": [ - "x = 5\n", - "print(type(x) is int)\n", - "print(type(x) is str)\n", - "\n", - "print(type(x) is not int)\n", - "print(type(x) is not str)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Functions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Define & Call" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5\n" - ] - } - ], - "source": [ - "def add(a, b):\n", - " c = a + b\n", - " print(c)\n", - "\n", - "add(2, 3)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Arguments" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike is 40 years old.\n" - ] - } - ], - "source": [ - "def info(name, age):\n", - " print(name, 'is', age, 'years old.')\n", - "\n", - "info('Mike', 40) " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "40 is Mike years old.\n" - ] - } - ], - "source": [ - "info(40, 'Mike')" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "ename": "TypeError", - "evalue": "info() missing 1 required positional argument: 'age'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0minfo\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m40\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m: info() missing 1 required positional argument: 'age'" - ] - } - ], - "source": [ - "info(40)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike is 40 years old.\n", - "Mike is 40 years old.\n" - ] - } - ], - "source": [ - "def info(name, age):\n", - " print(name, 'is', age, 'years old.')\n", - "\n", - "info(name = 'Mike', age = 40)\n", - "info(age = 40, name = 'Mike') " - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike is 40 years old.\n", - "Mike is 35 years old.\n" - ] - } - ], - "source": [ - "def info(name, age = 35):\n", - " print(name, 'is', age, 'years old.')\n", - "\n", - "info('Mike', 40)\n", - "info('Mike')" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike's hobbies: \n", - "Mike's hobbies: hiking, reading\n" - ] - } - ], - "source": [ - "def info(name, *args):\n", - " hobby = []\n", - " for a in args:\n", - " hobby.append(a)\n", - " print(name +\"'s hobbies: \" + ', '.join(hobby))\n", - "\n", - "info('Mike')\n", - "info('Mike', 'hiking', 'reading') " - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Mike's hobbies: first-hiking, second-reading\n" - ] - } - ], - "source": [ - "def info(name, **kwargs):\n", - " hobby = []\n", - " for k, v in kwargs.items():\n", - " hobby.append(k+'-'+v)\n", - " print(name +\"'s hobbies: \" + ', '.join(hobby))\n", - "\n", - "info('Mike', first='hiking', second='reading')" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Python Data Analysis\n", - "Python Data Analysis\n" - ] - } - ], - "source": [ - "def func(a1, a2, a3):\n", - " print(a1,a2,a3)\n", - " \n", - "args = ('Python', 'Data', 'Analysis')\n", - "func(*args)\n", - "\n", - "kwargs = {'a1' : 'Python', 'a2' : 'Data', 'a3' : 'Analysis'}\n", - "func(**kwargs)" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "args: ('I', 'love')\n", - "kwargs: {'first': 'Python programming', 'mid': 'and', 'last': 'Data Analysis'}\n", - "I love Python programming and Data Analysis\n" - ] - } - ], - "source": [ - "def func(*args,**kwargs):\n", - " print('args: ', args)\n", - " print('kwargs: ', kwargs)\n", - " print(' '.join(args), ' '.join(kwargs.values()))\n", - " \n", - "func('I', 'love', first='Python programming', mid='and', last='Data Analysis')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Return" - ] - }, - { - "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1\n", - "(1, 3)\n" - ] - } - ], - "source": [ - "def func1(a,b):\n", - " return a\n", - "\n", - "def func2(a,b):\n", - " return a,b\n", - "\n", - "print(func1(1,3))\n", - "print(func2(1,3))" - ] - }, - { - "cell_type": "code", - "execution_count": 23, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[1, 3]\n", - "{'a': 1, 'b': 3}\n" - ] - } - ], - "source": [ - "def func3(a,b):\n", - " return [a,b]\n", - "\n", - "def func4(a,b):\n", - " return {'a': a, 'b': b}\n", - "\n", - "print(func3(1,3))\n", - "print(func4(1,3))" - ] - }, - { - "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4\n", - "6\n" - ] - } - ], - "source": [ - "def by_factor(factor):\n", - " def multiply(number):\n", - " return factor * number\n", - " return multiply\n", - "\n", - "double = by_factor(2)\n", - "print(double(2))\n", - "print(double(3))" - ] - }, - { - "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5\n" - ] - } - ], - "source": [ - "def add(a, b):\n", - " c = a + b\n", - " return c\n", - "\n", - "result = add(2, 3)\n", - "print(result)" - ] - }, - { - "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "5\n", - "None\n" - ] - } - ], - "source": [ - "def add2(a, b):\n", - " c = a + b\n", - " print(c)\n", - "\n", - "result2 = add2(2, 3)\n", - "print(result2)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3.7200759760208356e-44\n", - "0.5\n", - "1.0\n" - ] - } - ], - "source": [ - "def logistic(x):\n", - " return 1/(1+math.exp(-x))\n", - "\n", - "print(logistic(-100))\n", - "print(logistic(0))\n", - "print(logistic(100))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Variable Scope" - ] - }, - { - "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "local\n" - ] - }, - { - "ename": "NameError", - "evalue": "name 'y' is not defined", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mNameError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[0mtest\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 6\u001b[1;33m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0my\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", - "\u001b[1;31mNameError\u001b[0m: name 'y' is not defined" - ] - } - ], - "source": [ - "def test():\n", - " y = 'local'\n", - " print(y)\n", - "\n", - "test()\n", - "print(y) " - ] - }, - { - "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "global\n", - "global\n" - ] - } - ], - "source": [ - "y = 'global'\n", - "def test():\n", - " global y\n", - " print(y)\n", - "\n", - "test()\n", - "print(y)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.11: find out all the prime numbers in a given list" - ] - }, - { - "cell_type": "code", - "execution_count": 34, - "metadata": {}, - "outputs": [], - "source": [ - "num_list = [649, 778, 652, 653, 912, 402, 917, 536, 664, 922, 284, 158, 415, 672, 673, 33, 419, 414, 421, 811, 683, 48, 818, 566, 567, 310, 580, 838, 199, 586, 458, 460, 337, 728, 604, 94, 607, 865, 354, 230, 367, 752, 625, 371, 505, 635, 893, 382, 767]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Lambda Expressions" - ] - }, - { - "cell_type": "code", - "execution_count": 46, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "3" - ] - }, - "execution_count": 46, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "add=lambda x, y: x+y\n", - "add(1, 2) " - ] - }, - { - "cell_type": "code", - "execution_count": 47, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "1" - ] - }, - "execution_count": 47, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sum = lambda x: 1\n", - "sum([2,3])" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[3, 2, 4, 1, 5]" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "sorted([1, 2, 3, 4, 5], key = lambda x: abs(3 - x))" - ] - }, - { - "cell_type": "code", - "execution_count": 49, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[1, 3, 5]" - ] - }, - "execution_count": 49, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(filter(lambda n: n % 2 == 1, [1, 2, 3, 4, 5]))" - ] - }, - { - "cell_type": "code", - "execution_count": 50, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "[2, 3, 4]" - ] - }, - "execution_count": 50, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "list(map(lambda x: x + 1, [1, 2, 3]))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.12: use the prime function you created in exercise 1 and lambda to find out all the prime numbers in a given list in one line" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Modules" - ] - }, - { - "cell_type": "code", - "execution_count": 62, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3.141592653589793\n", - "3.141592653589793\n", - "3.141592653589793\n" - ] - } - ], - "source": [ - "import math\n", - "print(math.pi)\n", - "\n", - "import math as mt\n", - "print(mt.pi)\n", - "\n", - "from math import pi\n", - "print(pi)\n", - "\n", - "from math import * " - ] - }, - { - "cell_type": "code", - "execution_count": 63, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "7\n", - "0.187558625103874\n", - "3\n", - "b\n" - ] - } - ], - "source": [ - "import random as rnd\n", - "print(rnd.randint(0, 10))\n", - "print(rnd.random())\n", - "lst = list(range(10))\n", - "print(rnd.choice(lst))\n", - "print(random.choice('abc'))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Classes" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Class and Instance" - ] - }, - { - "cell_type": "code", - "execution_count": 89, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1469952256\n", - "\n" - ] - } - ], - "source": [ - "a = 2\n", - "print(id(a))\n", - "print(type(a)) " - ] - }, - { - "cell_type": "code", - "execution_count": 90, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1469952256\n", - "\n" - ] - } - ], - "source": [ - "b = 2\n", - "print(id(b))\n", - "print(type(b)) " - ] - }, - { - "cell_type": "code", - "execution_count": 91, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1469952288\n", - "\n" - ] - } - ], - "source": [ - "c = 3\n", - "print(id(c))\n", - "print(type(c)) " - ] - }, - { - "cell_type": "code", - "execution_count": 92, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023259656\n", - "1531023259656\n", - "[1, 2, 3]\n", - "[1, 2, 3]\n", - "1531023259656\n", - "1531023259656\n" - ] - } - ], - "source": [ - "a = [1,2]\n", - "b = a\n", - "print(id(a))\n", - "print(id(b))\n", - "\n", - "b.append(3)\n", - "print(a)\n", - "print(b)\n", - "print(id(a)) \n", - "print(id(b)) " - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4426390664\n", - "4426391176\n", - "True\n", - "False\n" - ] - } - ], - "source": [ - "a = [1,2]\n", - "b = [1,2]\n", - "print(id(a))\n", - "print(id(b))\n", - "\n", - "print(a == b)\n", - "print(a is b) " - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4389863968\n", - "4389863968\n", - "True\n", - "True\n" - ] - } - ], - "source": [ - "a = 101\n", - "b = 101\n", - "print(id(a))\n", - "print(id(b))\n", - "\n", - "print(a == b)\n", - "print(a is b) " - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "4426665552\n", - "4426665104\n", - "True\n", - "False\n" - ] - } - ], - "source": [ - "c = 1001\n", - "d = 1001\n", - "print(id(c)) \n", - "print(id(d)) \n", - "\n", - "print(c == d)\n", - "print(c is d) " - ] - }, - { - "cell_type": "code", - "execution_count": 96, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023200840\n", - "1531023200840\n", - "[[9, 1], 2, 3, 4]\n", - "[[9, 1], 2, 3, 4]\n", - "1531023200840\n", - "1531023200840\n" - ] - } - ], - "source": [ - "a = [[0, 1], 2, 3]\n", - "b = a\n", - "print(id(a))\n", - "print(id(b))\n", - "\n", - "b.append(4)\n", - "b[0][0] = 9\n", - "print(a)\n", - "print(b)\n", - "print(id(a))\n", - "print(id(b))" - ] - }, - { - "cell_type": "code", - "execution_count": 97, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023204040\n", - "1531023260168\n", - "1531023201608\n", - "1531023201608\n", - "[[9, 1], 2, 3]\n", - "[[9, 1], 2, 3, 4]\n" - ] - } - ], - "source": [ - "import copy\n", - "a = [[0, 1], 2, 3]\n", - "b = copy.copy(a)\n", - "print(id(a))\n", - "print(id(b))\n", - "print(id(a[0]))\n", - "print(id(b[0]))\n", - "\n", - "b.append(4)\n", - "b[0][0] = 9\n", - "print(a)\n", - "print(b) " - ] - }, - { - "cell_type": "code", - "execution_count": 98, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023203336\n", - "1531023203784\n", - "1531023200840\n", - "1531022909128\n", - "[[0, 1], 2, 3]\n", - "[[9, 1], 2, 3, 4]\n" - ] - } - ], - "source": [ - "import copy\n", - "a = [[0, 1], 2, 3]\n", - "b = copy.deepcopy(a)\n", - "print(id(a)) \n", - "print(id(b))\n", - "print(id(a[0]))\n", - "print(id(b[0]))\n", - "\n", - "b.append(4)\n", - "b[0][0] = 9\n", - "print(a)\n", - "print(b) " - ] - }, - { - "cell_type": "code", - "execution_count": 99, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023380864\n", - "Hello!\n", - "1531023382824\n" - ] - } - ], - "source": [ - "string = 'Hello'\n", - "print(id(string))\n", - "string += '!'\n", - "print(string)\n", - "print(id(string)) " - ] - }, - { - "cell_type": "code", - "execution_count": 100, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "1531023201032\n", - "[1, 2, 3]\n", - "1531023201032\n" - ] - } - ], - "source": [ - "list1 = [1,2]\n", - "print(id(list1))\n", - "list1 += [3]\n", - "print(list1)\n", - "print(id(list1))" - ] - }, - { - "cell_type": "code", - "execution_count": 101, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean.Chen@smu.edu.sg\n" - ] - } - ], - "source": [ - "class Student:\n", - " pass #skip this part for now\n", - "\n", - "stu_1 = Student()\n", - "stu_1.first = 'Jean'\n", - "stu_1.last = 'Chen'\n", - "stu_1.email = 'Jean.Chen@smu.edu.sg'\n", - "print(stu_1.email) " - ] - }, - { - "cell_type": "code", - "execution_count": 102, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean.Chen@smu.edu.sg\n", - "Zian.Gong@smu.edu.sg\n" - ] - } - ], - "source": [ - "class Student:\n", - " def __init__(self, first, last):\n", - " self.first = first\n", - " self.last = last\n", - " self.email = first + '.' + last + '@smu.edu.sg'\n", - "\n", - "stu_1 = Student('Jean', 'Chen')\n", - "stu_2 = Student('Zian', 'Gong')\n", - "print(stu_1.email) \n", - "print(stu_2.email) " - ] - }, - { - "cell_type": "code", - "execution_count": 104, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean Chen\n", - "Jean Chen\n" - ] - } - ], - "source": [ - "class Student:\n", - " def __init__(self, first, last):\n", - " self.first = first\n", - " self.last = last\n", - " self.email = first + '.' + last + '@smu.edu.sg'\n", - " \n", - " def fullname(self):\n", - " return self.first + ' ' + self.last\n", - "\n", - "stu_1 = Student('Jean', 'Chen')\n", - "print(stu_1.fullname())\n", - "print(Student.fullname(stu_1)) " - ] - }, - { - "cell_type": "code", - "execution_count": 103, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "0\n", - "1\n" - ] - } - ], - "source": [ - "class Student:\n", - " num_of_stu = 0\n", - " def __init__(self, first, last):\n", - " self.first = first\n", - " self.last = last\n", - " self.email = first + '.' + last + '@smu.edu.sg'\n", - " Student.num_of_stu += 1\n", - "\n", - "print(Student.num_of_stu) \n", - "stu_1 = Student('Jean', 'Chen')\n", - "print(Student.num_of_stu) " - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Inheritance" - ] - }, - { - "cell_type": "code", - "execution_count": 84, - "metadata": {}, - "outputs": [], - "source": [ - "class Student:\n", - " def __init__(self, first, last):\n", - " self.first = first\n", - " self.last = last\n", - " self.email = first + '.' + last + '@smu.edu.sg'\n", - " \n", - " def fullname(self):\n", - " return self.first + ' ' + self.last" - ] - }, - { - "cell_type": "code", - "execution_count": 85, - "metadata": {}, - "outputs": [], - "source": [ - "class Rep(Student):\n", - " pass" - ] - }, - { - "cell_type": "code", - "execution_count": 86, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean.Chen@smu.edu.sg\n", - "Jean Chen\n" - ] - } - ], - "source": [ - "rep_1 = Rep('Jean', 'Chen') \n", - "print(rep_1.email)\n", - "print(rep_1.fullname())" - ] - }, - { - "cell_type": "code", - "execution_count": 87, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Jean.Chen@smu.edu.sg\n", - "Jean Chen\n", - "academic\n" - ] - } - ], - "source": [ - "class Rep(Student):\n", - " def __init__(self, first, last, cat):\n", - " super().__init__(first, last)\n", - " self.cat = cat\n", - "\n", - "rep_1 = Rep('Jean', 'Chen', 'academic')\n", - "print(rep_1.email) \n", - "print(rep_1.fullname())\n", - "print(rep_1.cat) " - ] - }, - { - "cell_type": "code", - "execution_count": 88, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "'academic representative: Jean Chen'" - ] - }, - "execution_count": 88, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "class Rep(Student):\n", - " def __init__(self, first, last, cat):\n", - " super().__init__(first, last) \n", - " self.cat = cat\n", - "\n", - " def fullname(self):\n", - " return self.cat + ' representative: ' + self.first + ' ' + self.last\n", - " \n", - "rep_1 = Rep('Jean', 'Chen', 'academic')\n", - "rep_1.fullname()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Magic Method" - ] - }, - { - "cell_type": "code", - "execution_count": 81, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "['__abs__',\n", - " '__add__',\n", - " '__and__',\n", - " '__bool__',\n", - " '__ceil__',\n", - " '__class__',\n", - " '__delattr__',\n", - " '__dir__',\n", - " '__divmod__',\n", - " '__doc__',\n", - " '__eq__',\n", - " '__float__',\n", - " '__floor__',\n", - " '__floordiv__',\n", - " '__format__',\n", - " '__ge__',\n", - " '__getattribute__',\n", - " '__getnewargs__',\n", - " '__gt__',\n", - " '__hash__',\n", - " '__index__',\n", - " '__init__',\n", - " '__init_subclass__',\n", - " '__int__',\n", - " '__invert__',\n", - " '__le__',\n", - " '__lshift__',\n", - " '__lt__',\n", - " '__mod__',\n", - " '__mul__',\n", - " '__ne__',\n", - " '__neg__',\n", - " '__new__',\n", - " '__or__',\n", - " '__pos__',\n", - " '__pow__',\n", - " '__radd__',\n", - " '__rand__',\n", - " '__rdivmod__',\n", - " '__reduce__',\n", - " '__reduce_ex__',\n", - " '__repr__',\n", - " '__rfloordiv__',\n", - " '__rlshift__',\n", - " '__rmod__',\n", - " '__rmul__',\n", - " '__ror__',\n", - " '__round__',\n", - " '__rpow__',\n", - " '__rrshift__',\n", - " '__rshift__',\n", - " '__rsub__',\n", - " '__rtruediv__',\n", - " '__rxor__',\n", - " '__setattr__',\n", - " '__sizeof__',\n", - " '__str__',\n", - " '__sub__',\n", - " '__subclasshook__',\n", - " '__truediv__',\n", - " '__trunc__',\n", - " '__xor__',\n", - " 'bit_length',\n", - " 'conjugate',\n", - " 'denominator',\n", - " 'from_bytes',\n", - " 'imag',\n", - " 'numerator',\n", - " 'real',\n", - " 'to_bytes']" - ] - }, - "execution_count": 81, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "dir(int)" - ] - }, - { - "cell_type": "code", - "execution_count": 83, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "3\n", - "3\n" - ] - } - ], - "source": [ - "num = 1\n", - "print(num + 2)\n", - "print(num.__add__(2))" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [], - "source": [ - "class iter_example(): \n", - " def __init__(self, data=1): \n", - " self.data = data \n", - "\n", - " def __iter__(self): \n", - " return self \n", - "\n", - " def __next__(self): \n", - " if self.data > 3:\n", - " raise StopIteration \n", - " else:\n", - " self.data += 1 \n", - " return self.data" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "2\n", - "3\n", - "4\n" - ] - } - ], - "source": [ - "for i in iter_example():\n", - " print(i)" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Id 1: Quan Nguyen\n" - ] - } - ], - "source": [ - "class Human:\n", - " def __init__(self, id, name, addresses=[], maps={}):\n", - " self.id = id\n", - " self.name = name\n", - " self.addresses = addresses\n", - " self.maps = maps\n", - " \n", - " def __str__(self):\n", - " return f'Id {self.id}: {self.name}'\n", - "human = Human(1, 'Quan Nguyen', ['Address1', 'Address1'], {'London':2, 'UK':3})\n", - "print(human)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Final exercises 2.13, 2.14 and 2.15: class inheritance" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.13: Write a parallelogram class that takes length, width and angle between sides as arguments:\n", - "- it has two functions: perimeter and area\n", - "- create an instant paral with length 5, width 6 and angle 60, print out its perimeter and area\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Write your python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.14: Write a rhombus class that inherits from parallelogram class:\n", - "- create an instant rh with length 5 and angle 60, print out its perimeter and area" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Write your python code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.15: Write a square class that inherits from rhombus class:\n", - "- create an instant sq with length 5, print out its perimeter and area\n", - "- write a new function area that will return \"The area of a square with length xxx is xxx\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Write your python code here" - ] - } - ], - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/W2_Function_Lambda/class_exercise_2_submit.ipynb b/W2_Function_Lambda/class_exercise_2_submit.ipynb deleted file mode 100644 index 790c3dd..0000000 --- a/W2_Function_Lambda/class_exercise_2_submit.ipynb +++ /dev/null @@ -1,244 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Python programming and Data Analysis\n", - "\n", - "## Class Exercise 2 -- Python Intermediate" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.11: find out all the prime numbers in a given list" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": {}, - "outputs": [], - "source": [ - "num_list = [649, 778, 652, 653, 912, 402, 917, 536, 664, 922, 284, 158, 415, 672, 673, 33, 419, 414, 421, 811, 683, 48, 818, 566, 567, 310, 580, 838, 199, 586, 458, 460, 337, 728, 604, 94, 607, 865, 354, 230, 367, 752, 625, 371, 505, 635, 893, 382, 767]" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[649, 653, 917, 415, 673, 33, 419, 421, 811, 683, 567, 199, 337, 607, 865, 367, 625, 371, 505, 635, 893, 767]\n" - ] - } - ], - "source": [ - "import math\n", - "# write your Python code here\n", - "def is_prime(num):\n", - " for i in range(2, math.floor(math.sqrt(num))+1, 2):\n", - " if num%i == 0:\n", - " return False\n", - " return True\n", - "prime_list = [num for num in num_list if is_prime(num)]\n", - "print(prime_list)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.12: use the prime function you created in exercise 1 and lambda to find out all the prime numbers in a given list in one line" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "[649, 653, 917, 415, 673, 33, 419, 421, 811, 683, 567, 199, 337, 607, 865, 367, 625, 371, 505, 635, 893, 767]\n" - ] - } - ], - "source": [ - "# write your Python code here\n", - "\n", - "print(list(filter(lambda num: is_prime(num), num_list)))" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.13: Write a parallelogram class that takes length, width and angle between sides as arguments:\n", - "- it has two functions: perimeter and area\n", - "- create an instant paral with length 5, width 6 and angle 60, print out its perimeter and area\n" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], - "source": [ - "import math\n", - "class parallel:\n", - " def __init__(self, length, width, angle):\n", - " self.length = length\n", - " self.width = width\n", - " self.angle = angle\n", - " def perimeter(self):\n", - " return (self.length + self.width)*2\n", - " def area(self):\n", - " return f\"{self.length*self.width*math.sin(math.radians(self.angle)):.2f}\"" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "22\n", - "25.98\n" - ] - } - ], - "source": [ - "paral = parallel(5, 6, 60)\n", - "print(paral.perimeter())\n", - "print(paral.area())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.14: Write a rhombus class that inherits from parallelogram class:\n", - "- create an instant rh with length 5 and angle 60, print out its perimeter and area" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here\n", - "class rhombus(parallel):\n", - " def __init__(self, length, angle):\n", - " self.length = length\n", - " self.angle = angle\n", - " def perimeter(self):\n", - " return 4*self.length\n", - " def area(self):\n", - " return f\"{pow(self.length,2)*math.sin(math.radians(self.angle)):.2f}\"\n", - " " - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "20\n", - "21.65\n" - ] - } - ], - "source": [ - "rh = rhombus(5, 60)\n", - "print(rh.perimeter())\n", - "print(rh.area())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Exercise 2.15: Write a square class that inherits from rhombus class:\n", - "- create an instant sq with length 5, print out its perimeter and area\n", - "- write a new function area that will return \"The area of a square with length xxx is xxx\"" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], - "source": [ - "# write your Python code here\n", - "class square(rhombus):\n", - " def __init__(self, length):\n", - " self.length = length\n", - " def area(self):\n", - " return f\"The area of a square with length {self.length} is {self.length*self.length}\"" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "20\n", - "The area of a square with length 5 is 25\n" - ] - } - ], - "source": [ - "sq = square(5)\n", - "print(sq.perimeter())\n", - "print(sq.area())" - ] - }, - { - "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.8.8" - } - }, - "nbformat": 4, - "nbformat_minor": 2 -} diff --git a/W2_Function_Lambda/tutorial_2.ipynb b/W2_Function_Lambda/tutorial_2.ipynb deleted file mode 100644 index 2ebc27f..0000000 --- a/W2_Function_Lambda/tutorial_2.ipynb +++ /dev/null @@ -1,730 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 2.21: Elevator -- return correct floor" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The code below defines an *Elevator* class. In this class,
\n", - "* The elevator is associated with a current floor where it stands by.\n", - "* All floors are numbered by continuous integers except that *floor -1* is one level below *floor 1*.\n", - "* The first floor aboveground is *floor 1*, and the first floor undergound is *floor -1* if there is any underground floor.\n", - "* There is a pair of integers representing the top floor and the bottom floor the elevator can go to.\n", - "* The elevator only stops at floors numbered with an odd integer.\n", - "\n", - "Fill in the blanks to simulate the movement of the elevator between the requested floors." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class Elevator:\n", - " def __init__(self, bottom, top, current):\n", - " '''Initialize the Elevator instance.\n", - " If the current floor is not an odd number,\n", - " the current floor will be one level below the desired floor.'''\n", - "\n", - " def up(self):\n", - " '''Make the elevator go up to the next possible floor.'''\n", - "\n", - " def down(self):\n", - " '''Make the elevator go down to the next possible floor.'''\n", - "\n", - " def go_to(self, floor):\n", - " '''Make the elevator go to the specific floor.\n", - " If the number of specific floor is not an odd number, \n", - " the specific floor will be one level below the desired floor.'''\n", - "\n", - " def __str__(self):\n", - " return \"Current floor: \" + str(self.current)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "elevator = Elevator(-1, 11, 2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "To test whether your *Elevator* class is working correctly, run the code blocks below." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "elevator.up()\n", - "elevator.current #should output 3" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "elevator.down() \n", - "elevator.current #should output 1" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "elevator.go_to(9) \n", - "elevator.current #should output 9" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Go to the top floor. Try to go up, it should stay. Then go down.\n", - "elevator.go_to(11)\n", - "elevator.up()\n", - "elevator.down()\n", - "print(elevator.current) # should be 9" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Try to go up, then go down.\n", - "elevator.go_to(10)\n", - "elevator.up()\n", - "elevator.down()\n", - "print(elevator.current) # should be 9, why?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "# Go to the bottom floor. Try to go down, it should stay. Then go up.\n", - "elevator.go_to(-1)\n", - "print(elevator.current) # should be -1\n", - "elevator.down()\n", - "elevator.down()\n", - "elevator.up()\n", - "elevator.up()\n", - "print(elevator.current) # should be 3" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now add the __str__ method to your *Elevator* class definition above so that when printing the elevator using the **print( )** method, we get the current floor together with a message. For example, in the 5th floor it should say \"Current floor: 5\"" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "elevator.go_to(5)\n", - "print(elevator)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 2.22: Netflix" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The code below defines a *Netflix* class. A Netflix object stores its title and the year it was first published." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Write your class here\n", - "class Netflix:\n", - " def __init__(self, title, year):\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Test your code here\n", - "netflix = Netflix('The call', 2020)\n", - "print(netflix)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "What if we want to search movie by actor/actress's name and year?\n", - "* We would like to define a more structured class
\n", - "\n", - "The code below defines a *StructuredNetflix* class.
\n", - "This class stores the movie's title, cast, length and year.
\n", - "Add the method __display__ to show all the information stored." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Write your class here\n", - "class StructuredNetflix:\n", - " def __init__(self, title, cast, length, year):\n", - "\n", - "\n", - " def display(self):\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Test your code here\n", - "netflix = StructuredNetflix('The call', ['Park Shine-hye', 'Jun Jong-seo', 'Kim Sung-ryoung'], '1h 52m', 2020)\n", - "netflix.display()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:
\n", - "Title: The call
\n", - "Year: 2020
\n", - "Cast: Park Shine-hye, Jun Jong-seo, Kim Sung-ryoung
\n", - "Movie length: 1h 52m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now, if we have a list of StructuredNetflix objects and we want to find all of the ones that Park Shine-hye acted and shows in 2020 except the movie we just watched ('The call')" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "netList = [StructuredNetflix('The call', ['Park Shine-hye', 'Jun Jong-seo', 'Kim Sung-ryoung'], '1h 52m', 2020),\n", - " StructuredNetflix('Alive', ['Yoo Ah-in', 'Park Shine-hye'], '1h 38m', 2020),\n", - " StructuredNetflix('Miss Americana', ['Taloy Swift'], '1h 25m', 2020)]" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Write your code here" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:
\n", - "Title: Alive
\n", - "Year: 2020
\n", - "Cast: Yoo Ah-in, Park Shine-hye
\n", - "Movie length: 1h 38m" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "But now we have another problem. Our StructuredAddress works fine for movies, but not for TV series. We could improve the **display()** method to handle lengths for movies and seasons for TV series. Let's think about the details:\n", - "\n", - "- Create a *BaseNetflix* class instead to store common attributes (title, cast and year).\n", - "- *BaseNetflix* class has the method __display__ to show the information stored.\n", - "- Create a child class *Movie* that has one more attribute length.\n", - "- When call the method __display__ with movies, it should show the movie's title, cast, year and length.\n", - "- Create a child class *TVseries* that has attributes title, cast, year and season.\n", - "- When call the method __display__ with TV series, it should show title, cast, year and season.\n", - "- Add method __update_season__ for class *TVseries*, this method will update the no. of season. Check the sample output for tv.update_season()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Write your code here\n", - "class BaseNetflix:\n", - " def __init__(self, title, cast, year):\n", - "\n", - " \n", - " def display(self):\n", - "\n", - "\n", - "class Movie(BaseNetflix):\n", - " def __init__(self, title, cast, year, length):\n", - "\n", - "\n", - " def display(self):\n", - "\n", - "\n", - "class TVseries(BaseNetflix):\n", - " def __init__(self, title, cast, year, season):\n", - "\n", - "\n", - " def display(self):\n", - "\n", - "\n", - " def update_season(self):\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Test your code here\n", - "movie = Movie('The call', ['Park Shine-hye', 'Jun Jong-seo', 'Kim Sung-ryoung'], 2020, '1h 52m')\n", - "movie.display()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:
\n", - "Title: The call
\n", - "Year: 2020
\n", - "Cast: Park Shine-hye, Jun Jong-seo, Kim Sung-ryoung
\n", - "Movie length: 1h 52m" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "#Test your code here\n", - "tv = TVseries('The crown', ['Olivia Colman', 'Tobias Menzies'], 2020, 4)\n", - "tv.display()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:
\n", - "Title: The crown
\n", - "Year: 2020
\n", - "Cast: Olivia Colman, Tobias Menzies
\n", - "Seasons: 4" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "tv.update_season()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Expected output:
\n", - "Title: The crown
\n", - "Year: 2020
\n", - "Cast: Olivia Colman, Tobias Menzies
\n", - "Seasons: 4
\n", - "After update
\n", - "Title: The crown
\n", - "Year: 2020
\n", - "Cast: Olivia Colman, Tobias Menzies
\n", - "Seasons: 5" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 2.23: Teaching load" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Let us first define a *Course* class.\n", - "Each course is associated with a course complexity, which is a random number between 10 and 15." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "import random\n", - "\n", - "class Course:\n", - " def __init__(self, course_id):\n", - " '''Create a new instance of course.'''\n", - " self.course_id = course_id # attribute: course_id\n", - " self.complexity = 10 + random.random() * 5\n", - "\n", - " def __str__(self):\n", - " return 'The complexity of course {:s} is {:.2f}'.format(self.course_id, self.complexity)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "all_courses = {'cs6' + '%02d' % (i+1): Course('cs6' + '%02d' % (i+1)) for i in range(30)}" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "for c in all_courses.values():\n", - " print(c)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The code below defines a *Professor* class.\n", - "* Each instance of this class is associated to a professor.\n", - "* The instance records the active courses that the professor is currently teaching.\n", - "* A professor can teach multiple sections of the same course.\n", - "* The workload of a professor is the sum of the complexity of all sections she is currently teaching across all different courses." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class Professor:\n", - " def __init__(self):\n", - " '''Create a new instance, with no active courses.'''\n", - "\n", - " def add_section(self, course):\n", - " '''Add a new course to this professor.'''\n", - "\n", - " def deactive_course(self, course):\n", - " '''Remove all teaching sections of the same course from this professor'''\n", - "\n", - " def load(self):\n", - " '''Calculate the current load for all courses.'''\n", - "\n", - " def __str__(self):\n", - " '''Return a string with the current load of the professor'''\n", - " \n", - " def __lt__(self, other):\n", - " return self.load() < other.load()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prof = Professor()\n", - "prof.add_section(all_courses['cs604'])\n", - "\n", - "print(prof.load())" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "prof.deactive_course(all_courses['cs604'])\n", - "print(prof.load()) # should be 0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We now have a basic implementation of the *Professor* class. What if we wish to balance the load between all professors? Let's use the strategy below:\n", - "1. If there is a new section of a course, assign the new section to the professor has the lowest load
\n", - "2. If adding the new section makes the average load more than 50, hire a new professor.
\n", - "How would you define a new *LoadBalancing* class?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class LoadBalancing:\n", - " def __init__(self, courses = {}):\n", - " '''Initialize with one professor'''\n", - "\n", - " def add_course(self, course_id):\n", - " '''Add a new course into available courses'''\n", - "\n", - " def add_section(self, course_id):\n", - " '''Select a professor with the lowest load and add a section of that course to him/ her.\n", - " If it's a new course, add the course first'''\n", - "\n", - " def deactive_course(self, course_id):\n", - " '''Deactive the course from all teaching professors.'''\n", - "\n", - " def avg_load(self):\n", - " '''Calculate the average load of all professors'''\n", - "\n", - " def ensure_availability(self):\n", - " '''If the average load is higher than 50, hire a new professor'''\n", - "\n", - " def __str__(self):\n", - " '''Return a string with the load for each professor.'''" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "load = LoadBalancing(all_courses)\n", - "load.add_section('cs604')\n", - "print(load.avg_load())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "What if we hire a new professor?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "load.profs.append(Professor())\n", - "print(load.avg_load())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now what about deactivating the course?" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "load.deactive_course('cs604')\n", - "print(load.avg_load()) # should return 0.0" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We hired a new professor manually. But we want this to happen automatically when the average load is more than 50%. To make this possible, we add a method **ensure_availability** and call it from the method **add_course** after a new course has been added. You can test it with the following code:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "load = LoadBalancing()\n", - "for c in random.choices(list(all_courses.keys()), k = 50):\n", - " load.add_section(c)\n", - " print(load)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The code above adds 50 new sections and then prints the loads for each professor. Run the following code to verify that the average load is not more than 50." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "print(load.avg_load())" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "How would you change your code to make sure no professor has load more than 50?" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "### Question 2.24: Sudoku checker (II) -- return cells which you are certain about its value" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "| | | | | | | | | |\n", - "|---|---|---|---|---|---|---|---|---|\n", - "| | |7| | | |1| | |\n", - "| |5|9| | | |2|3| |\n", - "|8|2|3| | | |4|5|6|\n", - "|5|1| | | | | |7|8|\n", - "|9| | |1| |3| | |4|\n", - "| | |4|2| |8|9| | |\n", - "| |7|5|3| |6|8|9| |\n", - "| |8|6| | | |7|1| |\n", - "| |9| | | | | |4| |" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "config1 = [' 7 1 ', ' 59 23 ', '823 456', '51 78', '9 1 3 4', ' 42 89 ', ' 753 689 ', ' 86 71 ', ' 9 4 ']\n", - "config2 = [' ', ' 528 614 ', ' 98 27 ', ' 12 39 ', '735 682', ' 695 741 ', ' 1 3 8 9 ', '42 7 1 65', ' ']\n", - "config3 = [' 76 3 ', ' 13 8 92', ' 4 2 31 ', ' 86 5 9', '26 78', '4 9 82 ', ' 17 5 2 ', '95 3 41 ', ' 2 96 ']" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "class SudokuChecker:\n", - " def __init__(self, config):\n", - " \n", - " def process(self):\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sudoku1 = SudokuChecker(config1)\n", - "sudoku1.process()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sudoku2 = SudokuChecker(config2)\n", - "sudoku2.process()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "sudoku3 = SudokuChecker(config3)\n", - "sudoku3.process()" - ] - } - ], - "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.6.9" - } - }, - "nbformat": 4, - "nbformat_minor": 4 -} diff --git a/advanced/README.md b/advanced/README.md new file mode 100644 index 0000000..e93cd9b --- /dev/null +++ b/advanced/README.md @@ -0,0 +1,24 @@ +# Advanced Python + +## Data Class + +Dataclasses, as the name clearly suggests, are classes that are meant to hold data. The motivation behind this module is that we sometimes define classes that only act as data containers and when we do that, we spend a consequent amount of time writing boilerplate code with tons of arguments, an ugly `__init__` method and many overridden functions. +- Type annotation for each attribute. Although this doesn’t enforce type validation, it helps your text editor provide better linting +- dataclass decorator is actually a code generator that automatically adds other methods under the hood: `__init__` , `__eq__` and `__repr__` methods: these methods are responsible for setting the attribute values, testing for equality and representing objects in a nice string format. +```Python +class Person(): + def __init__(self, first_name, last_name, age, job): + self.first_name = first_name + self.last_name = last_name + self.age = age + self.job = job + +# dataclass help to remove ugly __init__ method +from dataclasses import dataclass +@dataclass +class Person: + first_name: str + last_name: str + age: int + job: str +``` diff --git a/advanced/dataclass.py b/advanced/dataclass.py new file mode 100644 index 0000000..41c0217 --- /dev/null +++ b/advanced/dataclass.py @@ -0,0 +1,50 @@ +# dataclass +from dataclasses import asdict, dataclass, field + +# frozen=True create objects that are read-only, +# prevent anyone from modifying the values of +# @dataclass(frozen=True) +# class Person: +# first_name: str +# last_name: str +# age: int +# job: str + + +@dataclass +class Person: + """Data Class with default value""" + + first_name: str = "Code" + last_name: str = "Xplore" + age: int = 30 + job: str = "Data Scientist" + # field(init=False): create attribute that is only defined internally, + # not when the class is instantiated. + # If we try to access it, an AttributeError is thrown. + full_name: str = field(init=False, repr=False) + + def __post_init__(self): + """__post_init__ to perform initialization of attributes that depend on others""" + self.full_name = self.first_name + " " + self.last_name + + def __repr__(self): + return f"{self.first_name} {self.last_name}: {self.age}" + + def __eq__(self, other): + if isinstance(other, self.__class__): + return self.age == other.age + return NotImplemented + + def __lt__(self, other): + if isinstance(other, self.__class__): + return self.age < other.age + return NotImplemented + + +if __name__ == "__main__": + student = Person("Quan", "Nguyen", 28, "student") + doctor = Person("WY", "Peh", 30) + print(student) + print(student < 5) + print(asdict(student)) # convert to dictionary diff --git a/advanced/decorators_tutorial.py b/advanced/decorators_tutorial.py new file mode 100644 index 0000000..62503ff --- /dev/null +++ b/advanced/decorators_tutorial.py @@ -0,0 +1,86 @@ +import logging +import time +from functools import lru_cache, wraps + +logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s") + + +# Basic Decorators +def logger_decorator(orig_func): + def wrapper_func(*args, **kwargs): + """This is logger_decorator's wrapper func""" + logging.info(f"Function name: {orig_func.__name__}") + return orig_func(*args, **kwargs) + + return wrapper_func + + +def another_decorator(orig_func): + def wrapper_func(*args, **kwargs): + """This is another_decorator's wrapper func""" + logging.info("Inside another decorator func") + return orig_func(*args, **kwargs) + + return wrapper_func + + +# Timeit decorators +def timeit(func): + @wraps(func) + def wrapper(*args, **kwargs): + """This is timeit's wrapper func""" + start = time.perf_counter() + result = func(*args, **kwargs) + end = time.perf_counter() + print(f"{func.__name__} took {end - start:.6f} seconds to complete") + return result + + return wrapper + + +# Call Count +def countcall(func): + @wraps(func) + def wrapper(*args, **kwargs): + wrapper.count += 1 + result = func(*args, **kwargs) + print(f"{func.__name__} has been called {wrapper.count} times") + return result + + wrapper.count = 0 + return wrapper + + +@another_decorator +@logger_decorator +def plus_two_number(a, b): + """This is plus_two_number function""" + return a + b + + +@timeit +@countcall +@lru_cache # LRU Cache +def add_two_number(a, b): + """This is add_two_number function""" + return a + b + + +if __name__ == "__main__": + result = plus_two_number(1, 2) + + # @wraps(orig_func): + print( + plus_two_number.__name__, plus_two_number.__doc__ + ) # wrapper_func instead of plus_two_number + print( + add_two_number.__name__, add_two_number.__doc__ + ) # add_two_number This is add_two_number function since we use @wraps() + + # @lru_cache: When calling the input function, + # it first checks if its arguments are present in the cache. + # If it’s the case, return the result. + # Otherwise, compute it and put it in the cache + add_two_number(1000, 999) # call the 1st time same input + add_two_number(1000, 999) # call the 2nd time same input + add_two_number(1000, 999) # call the 3rd time same input diff --git a/advanced/logging_tutorial.py b/advanced/logging_tutorial.py new file mode 100644 index 0000000..56c0109 --- /dev/null +++ b/advanced/logging_tutorial.py @@ -0,0 +1,29 @@ +import logging + +def basic_logging() -> None: + logging.basicConfig(level=logging.WARNING) + + logging.debug("This is a debug message.") + logging.info("This is an info message.") + logging.warning("This is a warning message.") + logging.error("This is an error message.") + logging.critical("This is a critical message.") + +def format_logging() -> None: + logging.basicConfig( + level=logging.DEBUG, + format="%(asctime)s %(levelname)s %(message)s", + datefmt="%Y-%m-%d %H:%M:%S", + #filename="basic.log", log to file + ) + + logging.debug("This is a debug message.") + logging.info("This is an info message.") + logging.warning("This is a warning message.") + logging.error("This is an error message.") + logging.critical("This is a critical message.") + + +if __name__ == "__main__": + basic_logging() + #format_logging() diff --git a/basics/.gitkeep b/basics/.gitkeep new file mode 100644 index 0000000..e69de29 From e7476c5d54f5a5029816ec5589ac792fb332be40 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Tue, 21 Feb 2023 00:08:01 +0800 Subject: [PATCH 006/150] update the class encapsulation --- advanced/README.md | 18 +++++++++ advanced/class_2_encapsulation_tutorial.py | 37 +++++++++++++++++++ advanced/class_3_decorator_tutorial.py | 5 +++ .../{dataclass.py => dataclass_tutorial.py} | 0 4 files changed, 60 insertions(+) create mode 100644 advanced/class_2_encapsulation_tutorial.py create mode 100644 advanced/class_3_decorator_tutorial.py rename advanced/{dataclass.py => dataclass_tutorial.py} (100%) diff --git a/advanced/README.md b/advanced/README.md index e93cd9b..e4037c0 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -1,10 +1,28 @@ # Advanced Python +## Class + +### Encapsulation + +#### Access Modifiers + +**Encapsulation** means hiding the change +**Access modifiers**: Python doesn't have any mechanism that effectively restricts access to any instance variable or method. Python prescribes a convention of prefixing the name of the variable/method with a single (`_`) or double underscore (`__`) to emulate the behavior of protected and private access specifiers. + +1. **Public** +2. **Protected**: to add a prefix `_` (single underscore) to it + - Protected members of a class are accessible from within the class and are also available to its sub-classes. No other environment is permitted access to it. +3. **Private**: + - The double underscore `__` prefixed to a variable makes it private. It gives a strong suggestion not to touch it from outside the class. Any attempt to do so will result in an `AttributeError` + - **Name mangling**: Every member with a double underscore will be changed to `_object.___`. So, it can still be accessed from outside the class, but the practice should be refrained. + ## Data Class Dataclasses, as the name clearly suggests, are classes that are meant to hold data. The motivation behind this module is that we sometimes define classes that only act as data containers and when we do that, we spend a consequent amount of time writing boilerplate code with tons of arguments, an ugly `__init__` method and many overridden functions. + - Type annotation for each attribute. Although this doesn’t enforce type validation, it helps your text editor provide better linting - dataclass decorator is actually a code generator that automatically adds other methods under the hood: `__init__` , `__eq__` and `__repr__` methods: these methods are responsible for setting the attribute values, testing for equality and representing objects in a nice string format. + ```Python class Person(): def __init__(self, first_name, last_name, age, job): diff --git a/advanced/class_2_encapsulation_tutorial.py b/advanced/class_2_encapsulation_tutorial.py new file mode 100644 index 0000000..fa581d8 --- /dev/null +++ b/advanced/class_2_encapsulation_tutorial.py @@ -0,0 +1,37 @@ +""" +Encapsulation: hiding the change + +Access modifiers +1. Public +2. Protected: '_' +3. Private +""" + + +# --- Public --- +class Student(object): + school_name = "NTU" # public class attribute + + def __init__(self, name, class_no, age): + self.name = name + self._class_no = class_no + self.__age = age # protected instance attribute + + def __private_method(self): + print("This is private method") + + def __str__(self): + return f"Student {self.name}, {self.__age} y.o, is at class {self._class_no}" + + +if __name__ == "__main__": + s1 = Student("Bob", "10A1", "16") + print(s1) + print(dir(s1)) + # print(help(s1)) + print(s1._class_no) + # private attribute/method still can access outside the class + # via _object.___ + print(s1._Student__age) + s1._Student__private_method() + print(s1.__age) diff --git a/advanced/class_3_decorator_tutorial.py b/advanced/class_3_decorator_tutorial.py new file mode 100644 index 0000000..9775e7c --- /dev/null +++ b/advanced/class_3_decorator_tutorial.py @@ -0,0 +1,5 @@ +""" +@property decorator: https://www.tutorialsteacher.com/python/property-decorator +@classmethod +@staticmethod +""" diff --git a/advanced/dataclass.py b/advanced/dataclass_tutorial.py similarity index 100% rename from advanced/dataclass.py rename to advanced/dataclass_tutorial.py From 34a327ffd67d374e90df0ca86b590e3da0f9e07a Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Wed, 22 Feb 2023 23:15:23 +0800 Subject: [PATCH 007/150] add the encapsulation --- advanced/README.md | 10 +- advanced/args_kwargs_tutorial.py | 33 +++++++ advanced/class_0_basics_tutorial.py | 3 + ...ass_1_inheritance_polymorphism_tutorial.py | 3 + advanced/class_2_encapsulation_tutorial.py | 20 +++- advanced/dataclass_tutorial.py | 96 ++++++++++++++++++- requirements.txt | 2 + 7 files changed, 159 insertions(+), 8 deletions(-) create mode 100644 advanced/args_kwargs_tutorial.py create mode 100644 advanced/class_0_basics_tutorial.py create mode 100644 advanced/class_1_inheritance_polymorphism_tutorial.py create mode 100644 requirements.txt diff --git a/advanced/README.md b/advanced/README.md index e4037c0..3eb1c15 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -4,19 +4,25 @@ ### Encapsulation +**Encapsulation** describes the idea of wrapping data and the methods that work on data within one unit. This puts restrictions on accessing variables and methods directly and can prevent the accidental modification of data + +- The goal of information hiding is to ensure that an object’s state is always valid by controlling access to attributes that are hidden from the outside world. + #### Access Modifiers -**Encapsulation** means hiding the change **Access modifiers**: Python doesn't have any mechanism that effectively restricts access to any instance variable or method. Python prescribes a convention of prefixing the name of the variable/method with a single (`_`) or double underscore (`__`) to emulate the behavior of protected and private access specifiers. 1. **Public** 2. **Protected**: to add a prefix `_` (single underscore) to it - Protected members of a class are accessible from within the class and are also available to its sub-classes. No other environment is permitted access to it. + - Although the protected variable can be accessed out of the class as well as in the derived class (modified too in derived class), it is customary(convention not a rule) to not access the protected out the class body. 3. **Private**: - The double underscore `__` prefixed to a variable makes it private. It gives a strong suggestion not to touch it from outside the class. Any attempt to do so will result in an `AttributeError` - **Name mangling**: Every member with a double underscore will be changed to `_object.___`. So, it can still be accessed from outside the class, but the practice should be refrained. -## Data Class +## Attrs, Pydantic, or Python Data Classes + +### Python Data Classes Dataclasses, as the name clearly suggests, are classes that are meant to hold data. The motivation behind this module is that we sometimes define classes that only act as data containers and when we do that, we spend a consequent amount of time writing boilerplate code with tons of arguments, an ugly `__init__` method and many overridden functions. diff --git a/advanced/args_kwargs_tutorial.py b/advanced/args_kwargs_tutorial.py new file mode 100644 index 0000000..233951a --- /dev/null +++ b/advanced/args_kwargs_tutorial.py @@ -0,0 +1,33 @@ +a_list = [1, 2, 3] +b_list = [2, 10] +print(a_list) +print(*a_list) + + +def product_list(*args): + result = 1 + for arg in args: + result *= arg + return result + + +print(product_list(*a_list, *b_list)) + + +# merging_dicts.py +my_first_dict = {"A": 1, "B": 2, "C": 3, "D": 4} +my_second_dict = { + "country_capital": {"Vietnam": "Ha Noi", "England": "London", "Japan": "Tokyo"}, + "colors": ["red", "white", "blue"], +} +config_dict = {**my_first_dict, **my_second_dict} +print(config_dict) + + +def demo_func(colors, country_capital, A, B, C, D): + print("\n") + print(colors) + print(country_capital) + + +demo_func(**config_dict) diff --git a/advanced/class_0_basics_tutorial.py b/advanced/class_0_basics_tutorial.py new file mode 100644 index 0000000..3ad95a9 --- /dev/null +++ b/advanced/class_0_basics_tutorial.py @@ -0,0 +1,3 @@ +""" +- Class/Static Variable in Python: https://www.geeksforgeeks.org/g-fact-34-class-or-static-variables-in-python/?ref=lbp +""" diff --git a/advanced/class_1_inheritance_polymorphism_tutorial.py b/advanced/class_1_inheritance_polymorphism_tutorial.py new file mode 100644 index 0000000..338d33b --- /dev/null +++ b/advanced/class_1_inheritance_polymorphism_tutorial.py @@ -0,0 +1,3 @@ +""" +https://www.geeksforgeeks.org/polymorphism-in-python/ +""" diff --git a/advanced/class_2_encapsulation_tutorial.py b/advanced/class_2_encapsulation_tutorial.py index fa581d8..027a3ba 100644 --- a/advanced/class_2_encapsulation_tutorial.py +++ b/advanced/class_2_encapsulation_tutorial.py @@ -9,10 +9,18 @@ # --- Public --- -class Student(object): +class Person: + def __init__(self, id): + self._id = id + + +class Student(Person): + """Student is a derived class from person""" + school_name = "NTU" # public class attribute - def __init__(self, name, class_no, age): + def __init__(self, name, id, class_no, age): + super(Student, self).__init__(id) self.name = name self._class_no = class_no self.__age = age # protected instance attribute @@ -21,14 +29,16 @@ def __private_method(self): print("This is private method") def __str__(self): - return f"Student {self.name}, {self.__age} y.o, is at class {self._class_no}" + return f"Student {self.name}, ID: {self._id}, Age: {self.__age} y.o, is at class {self._class_no}" if __name__ == "__main__": - s1 = Student("Bob", "10A1", "16") + s1 = Student("Bob", "GM18999M", "10A1", "16") print(s1) - print(dir(s1)) + # print(dir(s1)) # print(help(s1)) + + # protected member can be accessed but should not be done due to convention print(s1._class_no) # private attribute/method still can access outside the class # via _object.___ diff --git a/advanced/dataclass_tutorial.py b/advanced/dataclass_tutorial.py index 41c0217..44d256d 100644 --- a/advanced/dataclass_tutorial.py +++ b/advanced/dataclass_tutorial.py @@ -1,5 +1,7 @@ # dataclass from dataclasses import asdict, dataclass, field +from datetime import date +from typing import List # frozen=True create objects that are read-only, # prevent anyone from modifying the values of @@ -42,9 +44,101 @@ def __lt__(self, other): return NotImplemented +@dataclass +class Product: + name: str = field(compare=True) # use for comparison Product's instance + category: str = field(compare=True) + shipping_weight: float = field(compare=False) + unit_price: int = field(compare=False) + tax_percent: float = field(compare=False) + + def __post_init__(self) -> None: + if self.unit_price < 0: + raise ValueError("unit_price attribute must greater then zero.") + + if self.shipping_weight < 0: + raise ValueError("shipping_weight attribute must greater then zero.") + + if not 0 < self.tax_percent < 1: + raise ValueError("tax_percent attribute must be between zero and one.") + + +@dataclass +class Order: + creation_date: date = date.today() + products: List[Product] = field(default_factory=list) # default value is a List + + def add_product(self, product: Product) -> None: + self.products.append(product) + + @property + def sub_total(self) -> int: + return sum((p.unit_price for p in self.products)) + + @property + def tax(self) -> float: + return sum( + (product.unit_price * product.tax_percent for product in self.products) + ) + + @property + def total_price(self) -> float: + return self.sub_total + self.tax + + @property + def total_shipping_weight(self) -> float: + return sum((product.shipping_weight for product in self.products)) + + +def test_product_order_dataclasses() -> None: + banana = Product( + name="banana", + category="fruit", + shipping_weight=0.5, + unit_price=215, + tax_percent=0.07, + ) + + mango = Product( + name="mango", + category="fruit", + shipping_weight=2, + unit_price=319, + tax_percent=0.11, + ) + mango_large = Product( + name="mango", + category="fruit", + shipping_weight=10, + unit_price=319, + tax_percent=0.11, + ) + + expensive_mango = Product( + name="Mango", + category="Fruit", + shipping_weight=4.0, + unit_price=800, + tax_percent=0.20, + ) + + order = Order() + for product in [banana, mango, mango_large, expensive_mango]: + order.add_product(product) + + print(f"Comparison between mango and expensive mango: {mango == expensive_mango}") + print(f"Comparison between mango and mango large: {mango == mango_large}") + print(f"Total order price: ${order.total_price/100:.2f}") + print(f"Subtotal order price: ${order.sub_total/100:.2f}") + print(f"Value paid in taxes: ${order.tax/100:.2f}") + print(f"Total weight order: {order.total_shipping_weight} kg") + + if __name__ == "__main__": student = Person("Quan", "Nguyen", 28, "student") doctor = Person("WY", "Peh", 30) print(student) - print(student < 5) + # print(student < 5) print(asdict(student)) # convert to dictionary + + test_product_order_dataclasses() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..599ee5c --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +attrs +pydantic From 0ff7ea9f298f58ba3ca89f9344f00fc7a4139798 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Wed, 22 Feb 2023 23:33:18 +0800 Subject: [PATCH 008/150] update to docs folder --- README.md | 430 +++++++++++++++++----------- {Readings => docs}/common_syntax.md | 0 {Readings => docs}/matplotlib.md | 0 {Readings => docs}/numpy.md | 0 {Readings => docs}/pandas.md | 0 5 files changed, 269 insertions(+), 161 deletions(-) rename {Readings => docs}/common_syntax.md (100%) rename {Readings => docs}/matplotlib.md (100%) rename {Readings => docs}/numpy.md (100%) rename {Readings => docs}/pandas.md (100%) diff --git a/README.md b/README.md index 7624291..41d9fde 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,11 @@ # Python + Python Programming and Data Analysis # Table of contents + - [Table of contents](#table-of-contents) -- [0. Common Syntax](./Readings/common_syntax.md) +- [0. Common Syntax](./docs/common_syntax.md) - [1. Basics](#1-basics) - [1.1. Naming Convention](#11-naming-convention) - [1.2 Operators](#12-operators) @@ -14,11 +16,11 @@ Python Programming and Data Analysis - [2.2. Variable Scopes](#22-variable-scopes) - [3. Lambda Expressions](#3-lambda-expressions) - [3.1. Sorted](#31-sorted) - - [3.2. Filter and Map](#32-filter-and-map) + - [3.2. Filter and Map](#32-filter-and-map) - [4. Module](#4-module) - [5. Class](#5-class) - [5.1. Object](#51-Object) - - [5.1.1. Variable Assignment and Aliasing](#511-variable-assignment-and-aliasing) + - [5.1.1. Variable Assignment and Aliasing](#511-variable-assignment-and-aliasing) - [5.1.2. Comparison Operators](#512-comparison-operators) - [5.1.3. Integer Caching](#513-integer-caching) - [5.1.4. Shallow Copy vs Deep Copy](#514-shallow-copy-vs-deep-copy) @@ -28,52 +30,60 @@ Python Programming and Data Analysis - [5.4. Magic Methods](#54-magic-methods) - [6. Regular Expression](#6-regular-expression) - [6.0. Regex Summary](#60-regex-summary) - - [6.1. What is Regex](#61-what-is-regex) + - [6.1. What is Regex](#61-what-is-regex) - [6.2. Search for a pattern](#62-search-for-a-pattern) - [6.3. Metacharacters](#63-metacharacters) - [6.4. Grouping Constructs](#64-grouping-constructs) - [6.5. Flags](#65-flags) - [6.6. Module-Level re Methods](#66-module-level-re-methods) - [6.7. Look ahead & Look behind](#67-look-ahead-and-look-behind) -- [7. Numpy](./readings/numpy.md) -- [8. Pandas](./readings/pandas.md) -- [9. Matplotlib](./readings/matplotlib.md) +- [7. Numpy](./docs/numpy.md) +- [8. Pandas](./docs/pandas.md) +- [9. Matplotlib](./docs/matplotlib.md) # 1. Basics + ## 1.1. Naming Convention +

Screenshot 2021-09-08 at 22 32 46

## 1.2. Operators -* **4 Bascis Data Types**: String, Integer, Float and Boolean -* **Logical Variable**: `not`, `and`, `or` - -| Operator | Name | Description | -|--------------|----------------|--------------------------------------------------------| -| ``a / b`` | True division | Quotient of ``a`` and ``b`` | -| ``a // b`` | Floor division | Quotient of ``a`` and ``b``, removing fractional parts | -| ``a % b`` | Modulus | Integer remainder after division of ``a`` by ``b`` | -| ``a ** b`` | Exponentiation | ``a`` raised to the power of ``b`` | -* **Membership Operators**: `in` and `not in` -* **Identify Operators**: `is` and `is not` to identify if 2 variables are same class + +- **4 Bascis Data Types**: String, Integer, Float and Boolean +- **Logical Variable**: `not`, `and`, `or` + +| Operator | Name | Description | +| -------- | -------------- | -------------------------------------------------- | +| `a / b` | True division | Quotient of `a` and `b` | +| `a // b` | Floor division | Quotient of `a` and `b`, removing fractional parts | +| `a % b` | Modulus | Integer remainder after division of `a` by `b` | +| `a ** b` | Exponentiation | `a` raised to the power of `b` | + +- **Membership Operators**: `in` and `not in` +- **Identify Operators**: `is` and `is not` to identify if 2 variables are same class + ```Python x =5 type(x) is int #True ``` ## 1.3. Iterables and Iterators + - **iterable**: types of iterables - list/tuple/str/dict - zip/enumerate/range/reversed - **iterator**: An iterable can be passed to the built-in function `iter()`, which returns some object called **iterator** + ```Python -it = iter([4, 3, 2, 1]) +it = iter([4, 3, 2, 1]) print(next(it))#4 print(next(it))#3 ``` -

Screenshot 2021-09-08 at 22 32 46

+

Screenshot 2021-09-08 at 22 32 46

## 1.4. Zip and Enumerate + - `zip()`: to zip 2 lists together - `enumerate()`: to return both item & index corresponding to that item in the list @@ -85,6 +95,7 @@ print(next(it))#3 >>> list(zipped) [(1, 'a', 4.0), (2, 'b', 5.0), (3, 'c', 6.0)] ``` + ```Python l1 = ['h', 'e', 'l', 'l', 'o'] for idx, item in enumerate(l1): @@ -100,71 +111,88 @@ for idx, item in enumerate(l1): [(Back to top)](#table-of-contents) # 2. Functions -## 2.1. Argument Types + +## 2.1. Argument Types + - **2.1.1. Positional Arguments** - **2.1.2. Keyword Arguments** - **2.1.3. Default Arguments** - **2.1.4. Variable-Length Arguments** - 1) `*args` (Non-Keyword Arguments): extra arguments can be tacked on to your current formal parameters (including zero extra arguments) - 2) `**kwargs` (Keyword Arguments) : dictionary that maps each keyword to the value that we pass alongside it - **Example of** `*args` - ```Python - def info(name, *args): - hobby = [] - for a in args: - hobby.append(a) - print(name +"'s hobbies: " + ', '.join(hobby)) - info('Mike') #Mike's hobbies: - info('Mike', 'hiking', 'reading') #Mike's hobbies: hiking, reading - ``` - **Example of** `**kwargs` - ```Python - def info(name, **kwargs): - hobby = [] - for k, v in kwargs.items(): - hobby.append(k+'-'+v) - print(name +"'s hobbies: " + ', '.join(hobby)) - info('Mike', first='hiking', second='reading') #Mike's hobbies: first-hiking, second-reading - ``` + 1. `*args` (Non-Keyword Arguments): extra arguments can be tacked on to your current formal parameters (including zero extra arguments) + 2. `**kwargs` (Keyword Arguments) : dictionary that maps each keyword to the value that we pass alongside it + + **Example of** `*args` + + ```Python + def info(name, *args): + hobby = [] + for a in args: + hobby.append(a) + print(name +"'s hobbies: " + ', '.join(hobby)) + info('Mike') #Mike's hobbies: + info('Mike', 'hiking', 'reading') #Mike's hobbies: hiking, reading + ``` + + **Example of** `**kwargs` + + ```Python + def info(name, **kwargs): + hobby = [] + for k, v in kwargs.items(): + hobby.append(k+'-'+v) + print(name +"'s hobbies: " + ', '.join(hobby)) + info('Mike', first='hiking', second='reading') #Mike's hobbies: first-hiking, second-reading + ``` [(Back to top)](#table-of-contents) ## 2.2. Variable Scopes + - There are 2 types of Variable: `Local` and `Global` scope - - `global` variable + + - `global` variable ```Python y = 'global' - def test(): + def test(): global y #This to declare y is global scope print(y) test() #will print 'global' ``` -[(Back to top)](#table-of-contents) + + [(Back to top)](#table-of-contents) # 3. Lambda Expressions + - Syntax: `lambda argument_list: expression` - - **argument_list** (same as argument list in functions): `x,y, *arg, **kwargs` + - **argument_list** (same as argument list in functions): `x,y, *arg, **kwargs` - **expression** (Output) must be single line -**Example of** `lambda` +**Example of** `lambda` + ```Python lambda x, y: x*y #input: x, y; output: x*y lambda *args: sum(args). #input: any number of parameters; output: their summation lambda x: 1 #input: x; output: 1 ``` + ## 3.1. Sorted + - Syntax: `sorted(iterable, key=None, reverse=False)` sorts the elements in the given iterable by key + ```Python sorted([1, 2, 3, 4, 5], key = lambda x: abs(3 - x)) #[3, 2, 4, 1, 5] ``` + ## 3.2. Filter and Map + - **Filter** syntax: `filter(function, iterable)` filters the given iterable (list) based on the given function -- **Map** syntax : `map(function, iterable)` applies a given function to each item of the given iterable +- **Map** syntax : `map(function, iterable)` applies a given function to each item of the given iterable - Note: Both Filter and Map will return **Iterable Object**, so need to use `list()` function to convert to a lsit -**Example of** `filter` and `map` +**Example of** `filter` and `map` + ```Python list(filter(lambda n: n % 2 == 1, [1, 2, 3, 4, 5])) #[1, 3, 5] @@ -174,7 +202,9 @@ list(map(lambda x: x + 1, [1, 2, 3])) #[2, 3, 4] [(Back to top)](#table-of-contents) # 4. Module + ## 4.1. Random Module + ```Python import random random.seed(42) #make results reproducible, @@ -204,22 +234,26 @@ random.shuffle(items) #randomize a sequence in-place [(Back to top)](#table-of-contents) # 5. Class +

Screenshot 2021-09-08 at 22 38 12

## 5.1. Object + ### 5.1.1. Variable Assignment and Aliasing + - **Aliasing**: many variables (a,b) refer to the same object list `[1,2]`

Screenshot 2021-09-08 at 22 52 48

### 5.1.2. Comparison Operators + - `==`: compares the values of the object - `is`: compares objects ```Python a = [1,2] -b = [1,2] +b = [1,2] -print(id(a)) #2661200625736 +print(id(a)) #2661200625736 print(id(b)) #2661202091528 a == b #True @@ -227,11 +261,13 @@ a is b #False ``` ### 5.1.3. Integer Caching -- In Python, interpreters will typically cache small integers in the range of -5 to 256. + +- In Python, interpreters will typically cache small integers in the range of -5 to 256. - When the Python interpreter is launched, these integer objects will be created and available for later use in the memory.

Screenshot 2021-09-08 at 23 32 57

### 5.1.4. Shallow Copy vs Deep Copy + ```Python import copy a = [[0, 1], 2, 3] @@ -240,78 +276,90 @@ c = copy.deepcopy(a) ``` #### Shallow Copy - copy() -- Shallow Copy will **only create a new object for the parent layer**. + +- Shallow Copy will **only create a new object for the parent layer**. - It will **NOT** create a new object **for any of the child layer**.

Screenshot 2021-09-08 at 23 38 28

#### Deep Copy - deepcopy() -- Deep Copy will **create new objects for the parent & child layers**. + +- Deep Copy will **create new objects for the parent & child layers**.

Screenshot 2021-09-08 at 23 45 50

### 5.1.5. Data Mutability -- **Immutable** (when values are changed, a new object will be created): integers, strings, and tuples -- **Mutable** (values can be changed after creation): lists, dictionaries, and sets + +- **Immutable** (when values are changed, a new object will be created): integers, strings, and tuples +- **Mutable** (values can be changed after creation): lists, dictionaries, and sets

Screenshot 2021-09-09 at 04 35 03

[(Back to top)](#table-of-contents) ## 5.2. Class + ### 5.2.1. Class Definition + - **Class** is a "blue-print" for creating **Object** - - For example: Cars may not be exactly same, but the structures are same. -

Screenshot 2021-09-09 at 04 38 24

+ - For example: Cars may not be exactly same, but the structures are same. +

Screenshot 2021-09-09 at 04 38 24

### 5.2.2. Class Syntax -- **Class attribute**: `Student.num_of_stu` is an attribute for the whole class, *cannot* use self.num_of_stu + +- **Class attribute**: `Student.num_of_stu` is an attribute for the whole class, _cannot_ use self.num_of_stu - **Init method**: `__init__` & using self as the first argument - **Class Method**: at least one argument – self and can be include other method argument like `birth_year` ```Python class Student: #Class attribute - num_of_stu = 0 - + num_of_stu = 0 + #Special init method def __init__(self, first, last): #use self as the first argument self.first = first self.last = last self.email = first + '.' + last + '@smu.edu.sg' Student.num_of_stu += 1 #attribute for the whole class, cannot use self.num_of_stu - + def full_name(self, birth_year): #Method, we have at least one argument – self & birth_year - return self.first + ' ' + self.last + ' was born in ' + birth_year + return self.first + ' ' + self.last + ' was born in ' + birth_year -print(Student.num_of_stu) #0 -stu_1 = Student('Ryan','Tan') +print(Student.num_of_stu) #0 +stu_1 = Student('Ryan','Tan') stu_1.full_name('1995') # "Ryan Tan was born in 1995" print(Student.num_of_stu) #1 ``` ## 5.3. Inheritance + - For example, Create `Representative` class based on the `Student` class - `super()`: to inherite all the attributes in parent class & Initiate more information than parent class - **Override**: to override the method of parent class + ```Python class Rep(Student): def __init__(self, first, last, cat): - #parent class Student handles existing arguments + #parent class Student handles existing arguments super().__init__(first, last) #new information - self.cat = cat + self.cat = cat def full_name(self): #override the full_name method of parent - return self.cat + ' representative: ' + super().full_name() + return self.cat + ' representative: ' + super().full_name() ``` + [(Back to top)](#table-of-contents) ## 5.4. Magic Methods -- Magic methods in Python are the special methods that start and end with the double underscores __ + +- Magic methods in Python are the special methods that start and end with the double underscores \_\_ - Built-in classes in Python define many magic methods. Use the `dir()` function to see the number of magic methods inherited by a class. ```Python >>> dir(int) ['__abs__', '__add__', '__and__', '__bool__', '__ceil__', '__class__', '__delattr__', ...] ``` - Magic methods are most **frequently used to define behaviors of predefined operators** in Python + - For example: `__str__()` method is executed when we want to `print` an object in a printable format. We can override the functionality of the `__str__()` method. As an instance: + ```Python class Human: def __init__(self, id, name, addresses=[], maps={}): @@ -326,36 +374,41 @@ class Rep(Student): print(human) #Id 1: Quan Nguyen ``` - [(Back to top)](#table-of-contents) - # 6. Regular Expression + ## 6.0. Regex Summary -- **Character class**: `[]` specify a set of characters to match -- **Metacharacters**: `\w` [a-zA-Z0-9_], `\W` [^a-zA-Z0-9_], `\d`, `\D`, `\s` (white-space), `\S` (non white-space), `.` match anything except \n -- `\` to remove special meaning of the metacharacter. For example: [\.] means match "." dot in the text, not mean match anything -- **Anchors**: `^`, `$`, `\b` to get grid of \n at beginning & end of text: + +- **Character class**: `[]` specify a set of characters to match +- **Metacharacters**: `\w` [a-zA-Z0-9_], `\W` [^a-za-z0-9_], `\d`, `\D`, `\s` (white-space), `\S` (non white-space), `.` match anything except \n +- `\` to remove special meaning of the metacharacter. For example: [\.] means match "." dot in the text, not mean match anything +- **Anchors**: `^`, `$`, `\b` to get grid of \n at beginning & end of text: - `^` beginning of text line, `$` end of text line: use `re.M` to match the beginning ^ /end $ pattern in multiple lines - `\b` word boundary match until last word character `[a-zA-Z0-9_]` -- **Quantifiers**: `*` zero or more , `?` zero or one, `+` one or more, `{m}` m repetitions, `{m, n}` any number of repetitions from m to n, inclusive: to repeating literal/metacharacter/group/backreference +- **Quantifiers**: `*` zero or more , `?` zero or one, `+` one or more, `{m}` m repetitions, `{m, n}` any number of repetitions from m to n, inclusive: to repeating literal/metacharacter/group/backreference - **Group**: to keep certain part out of the entire match, or match a repeat with backref - **Backreference**: Numbered groups: `\1`, `\2`, `\3` numbering: from out to in, from left to right - [**Look ahead & Look behind**](#67-look-ahead-and-look-behind) -## 6.1. What is Regex + +## 6.1. What is Regex + - **Regex**: is a tiny programming language used for data manipulation -- **re** module: is a Python module containing *re engine* and providing the regular expression functionality +- **re** module: is a Python module containing _re engine_ and providing the regular expression functionality

Screenshot 2021-09-09 at 04 35 03

## 6.2. Search for a pattern + - To search for a pattern, there are 2 steps: - **Step 1**: Compile the pattern - - **Step 2**: Perform the search -

Screenshot 2021-09-09 at 04 35 03

+ - **Step 2**: Perform the search +

Screenshot 2021-09-09 at 04 35 03

### 6.2.1. Compile the pattern -- `re.compile()` function compiles a pattern so that the re engine can perform the search. + +- `re.compile()` function compiles a pattern so that the re engine can perform the search. + ```Python pat = re.compile(r'abc') print(pat) @@ -364,9 +417,13 @@ print(type(pat)) re.compile('abc') ``` + ### 6.2.2. Perform the search + #### 6.2.2.1. Match() + - `match()`: match the pattern **from the beginning**. + ```Python mat_abc1 = pat.match('ABC,ABc,AbC,abc') mat_abc2 = pat.match('abc,ABc,AbC,abc') @@ -375,8 +432,10 @@ print(mat_abc2) # ``` #### 6.2.2.2. Search() + - `search()`: match the pattern in **any position** in the text and returns the match in `re.Match` class. -- BUT it **only returns the first match** +- BUT it **only returns the first match** + ```Python sear_abc1 = pat.search('ABC,ABc,AbC,abc') sear_abc2 = pat.search('abc,ABc,AbC,abc') @@ -387,7 +446,9 @@ print(type(sear_abc1))# ``` #### 6.2.2.3. Findall() + - `findall()` method: finds all the matched strings and return them in a list. + ```Python find_abc1 = pat.findall('ABC,ABc,AbC,abc') find_abc2 = pat.findall('abc,ABc,AbC,abc') @@ -397,8 +458,10 @@ print(find_abc2) #['abc', 'abc'] ``` #### 6.2.2.4. FindIter() + - The `findall()` method returns all the matched strings in a list. - `finditer()`: returns an iterator that lazily splits matches one at a time. + ```Python finditer_abc = pat.finditer('abc,ABc,AbC,abc') @@ -407,120 +470,140 @@ print(finditer_abc) # for m in finditer_abc: # # - print(m) + print(m) ``` ## 6.3. Metacharacters + The metacharacters can be categorized into several types as below: - `. ^ $ * + ? { } [ ] \ | ( )` - `"["` and `"]"` -- *Type 1* `. [] - ^ \d \D \w \W \s \S`: Metacharacters that match a single character: - - `.` **Dot**: match any single character except the newline **\n** character +- _Type 1_ `. [] - ^ \d \D \w \W \s \S`: Metacharacters that match a single character: + + - `.` **Dot**: match any single character except the newline **\n** character ```Python p = re.compile(r'.at') m = p.findall('cat bat\n sat cap') #['cat', 'bat', 'sat'] - ``` + ``` - `[]` **character class**: specify a set of characters to match - - Metacharacters lose their special meaning inside character class. + - Metacharacters lose their special meaning inside character class. ```Python p = re.compile(r'[abcABC]') m = p.findall('abcABC') #['a', 'b', 'c', 'A', 'B', 'C'] - ``` + ``` - `-` **hyphen**: specify a range of characters to match + - If you want to match a literal hyphen, put it in the beginning or the end inside [], for ex: `[-a-e]` or `[a-e-]` + ```Python p = re.compile(r'[a-z0-9]') m = p.findall('d0A3z6P') #['d', '0', '3', 'z', '6'] p = re.compile(r'[-a-e]') # or [a-e-] if you want to match a hyphen - m = p.findall('e-a-s-y, easy') #['e', '-', 'a', '-', '-', 'e', 'a'] - ``` - - `^` **caret**: match any character NOT in the character class + ``` + + - `^` **caret**: match any character NOT in the character class + - A caret ^ not at the beginning of a character class, it works as a normal character - A caret outside a character class has a different meaning. + ```Python p = re.compile(r'[^0-9a-z]') #Pattern exclude 0-9 and lowecase of a to z m = p.findall('1 2 3 Go') #Result: [' ', ' ', ' ', 'G'] → Only match space + G p = re.compile(r'[0-9^a-z]')#if ^ not at the beginning of a character class, it works as a normal character m = p.findall('1 2 3 ^Go') #['1', '2', '3', '^', 'o'] - ``` + ``` + - `\d` vs `\D` **digits**: \d (numeric digits) \D (non-digit, including \n) ```Python p = re.compile(r'\d') m = p.findall('a1\nA#') #['1'] p = re.compile(r'\D') m = p.findall('a1\nA#') #['a', '\n', 'A', '#'] - ``` + ``` - `\w` vs `\W` **word characters**: \w (`[a-zA-Z0-9_]`) \W (`[^a-zA-Z0-9_]`)

Screenshot 2021-09-09 at 04 35 03

- + ```Python p = re.compile(r'\w') m = p.findall('_#a!E$4-') #['_', 'a', 'E', '4'] p = re.compile(r'\W') m = p.findall('_#a!E$4-') #['#', '!', '$', '-'] - ``` + ``` + - `\s` vs `\S` **white space**: \s (white-space) \S (non white-space) match based on whether a character is a whitespace

Screenshot 2021-09-09 at 04 35 03

```Python - text = 'Name\tISSS610\tISSS666\nJoe Jones\tA\tA\n' + text = 'Name\tISSS610\tISSS666\nJoe Jones\tA\tA\n' p = re.compile(r'\s') m = p.findall(text) #['\t', '\t', '\n', ' ', '\t', '\t', '\n'] - ``` -- *Type 2*: Escaping metacharacters: `\` Removes the special meaning of a metacharacter + ``` + +- _Type 2_: Escaping metacharacters: `\` Removes the special meaning of a metacharacter + ```Python p1 = re.compile(r'.') p2 = re.compile(r'\.') m1 = p1.findall('smu.edu.sg') #['s', 'm', 'u', '.', 'e', 'd', 'u', '.', 's', 'g'] m2 = p2.findall('smu.edu.sg') #['.', '.'] - + p = re.compile(r'\d\\d') #First \d is to match any digit, then second \\d is to match "\d" m = p.findall('135\d') #['5\\d'] i.e: 5\d ``` -- *Type 3*: Anchors: `^` beginning of text, `$` end of text, `\b` word boundary - - `^` **beginning of text**: We have seen a caret used in a character class. Here the caret is used without a character class. - - It matches the starting position in the text. - - In the case of Multiline text, we can add flag `re.MULTILINE` or `re.M` in `re.compile` - ```Python - p = re.compile(r'^a[ab]c') - m = p.findall('''aac\nabc''') #['aac'] - - p = re.compile(r'^a[ab]c', re.M) #Add flag re.M to match multiple text - m = p.findall('''aac\nabc''') #['aac', 'abc'] - ``` - - `$` **end of text**: - - It matches the ending position in the text - - Similar to caret, dollar sign matches the ending position but not in each line in multiline text, but this behavior can also be changed with `re.MULTILINE` or `re.M` - ```Python - p = re.compile(r'ab.$') - m = p.findall('abc abd abe abf') #['abf'] - - p = re.compile(r'[ab]c$', re.M) #Add flag re.M to match multiple text - m = p.findall('ac\nbc') #['ac', 'bc'] - ``` - - `\b` **word boundary**: Match based on whether a position is a word boundary - ```Python - p = re.compile(r'\b\d\d\b') - m = p.findall('1 2 3 11 12 13 111 112 113') #['11', '12', '13'] - - p = re.compile(r'\b\w\w\b') - m = p.findall('aa,ab;ac(AA)AB AC') #['aa', 'ab', 'ac', 'AA', 'AB', 'AC'] - ``` - -- *Type 4*: Quantifiers: - - `*`: zero or more - - `?`: zero or one +- _Type 3_: Anchors: `^` beginning of text, `$` end of text, `\b` word boundary + + - `^` **beginning of text**: We have seen a caret used in a character class. Here the caret is used without a character class. + + - It matches the starting position in the text. + - In the case of Multiline text, we can add flag `re.MULTILINE` or `re.M` in `re.compile` + + ```Python + p = re.compile(r'^a[ab]c') + m = p.findall('''aac\nabc''') #['aac'] + + p = re.compile(r'^a[ab]c', re.M) #Add flag re.M to match multiple text + m = p.findall('''aac\nabc''') #['aac', 'abc'] + ``` + + - `$` **end of text**: + + - It matches the ending position in the text + - Similar to caret, dollar sign matches the ending position but not in each line in multiline text, but this behavior can also be changed with `re.MULTILINE` or `re.M` + + ```Python + p = re.compile(r'ab.$') + m = p.findall('abc abd abe abf') #['abf'] + + p = re.compile(r'[ab]c$', re.M) #Add flag re.M to match multiple text + m = p.findall('ac\nbc') #['ac', 'bc'] + ``` + + - `\b` **word boundary**: Match based on whether a position is a word boundary + + ```Python + p = re.compile(r'\b\d\d\b') + m = p.findall('1 2 3 11 12 13 111 112 113') #['11', '12', '13'] + + p = re.compile(r'\b\w\w\b') + m = p.findall('aa,ab;ac(AA)AB AC') #['aa', 'ab', 'ac', 'AA', 'AB', 'AC'] + ``` + +- _Type 4_: Quantifiers: + + - `*`: zero or more + - `?`: zero or one - `+`: one or more - `{m}`: m repetitions - `{m, n}`: any number of repetitions from m to n, inclusive. - + ```Python p = re.compile(r'a[ab]*c') m = p.findall('a ab ac abc aac aabc aaac ababc') #['ac', 'abc', 'aac', 'aabc', 'aaac', 'ababc'] @@ -537,36 +620,43 @@ The metacharacters can be categorized into several types as below: p = re.compile(r'\d{2,3}') m = p.findall('1 2 3 11 12 13 111 112 113') #['11', '12', '13', '111', '112', '113'] ``` - - + ## 6.4. Grouping Constructs +

Screenshot 2021-09-23 at 11 08 51

### 6.4.1. Grouped Pattern -- We can group pattern using `()` into sub-patterns - ```Python - p = re.compile(r'(\w+): (\d+)') #Sub-patterns are 2 group - m = p.findall('Course: Grade\nMath: 89\nPhysics: 92\n English: 78') #[('Math', '89'), ('Physics', '92'), ('English', '78')] - - chapters = 'Chapter 12: Numpy\n\ - Chapter 13: Pandas\n\ - Chapter 14: Data Visualzation' - p = re.compile(r'^Chapter (\d+: .+)', re.M) #['12: Numpy', '13: Pandas', '14: Data Visualzation'] - m = p.findall(chapters) - ``` + +- We can group pattern using `()` into sub-patterns + + ```Python + p = re.compile(r'(\w+): (\d+)') #Sub-patterns are 2 group + m = p.findall('Course: Grade\nMath: 89\nPhysics: 92\n English: 78') #[('Math', '89'), ('Physics', '92'), ('English', '78')] + + chapters = 'Chapter 12: Numpy\n\ + Chapter 13: Pandas\n\ + Chapter 14: Data Visualzation' + p = re.compile(r'^Chapter (\d+: .+)', re.M) #['12: Numpy', '13: Pandas', '14: Data Visualzation'] + m = p.findall(chapters) + ``` + ### 6.4.2. Alternation + - Match the sub-pattern before or the one after - - ```Python - p = re.compile(r'(\w+)\.(bat|zip|exe)') - m = p.findall('game.exe auto.bat text.zip') #[('game', 'exe'), ('auto', 'bat'), ('text', 'zip')] - ``` + ```Python + p = re.compile(r'(\w+)\.(bat|zip|exe)') + m = p.findall('game.exe auto.bat text.zip') #[('game', 'exe'), ('auto', 'bat'), ('text', 'zip')] + ``` + ### 6.4.3. re.Match.groups() vs re.Match.group() + - `.groups()`: return all matched groups - `.group()`: allows users to choose different groups by giving the indices of the groups. + - group(0) returns the whole match. - group(1) returns the 1st captured group. - group(2, 3, 4) returns the 2nd, 3rd and 4th groups. + ```Python #Ex 1: re.Match.groups() vs re.Match.group() p = re.compile(r'(\w+\.\w+)\s(\w+\.\w+)') @@ -574,35 +664,40 @@ The metacharacters can be categorized into several types as below: print(m.groups()) #('game.exe', 'auto.bat') print(m.group(1)) # game.exe - + #Ex 2: re.Match.group() pattern = r'(\w+)\W+(\w+)\W+(\w+)\W+(\w)+' p = re.compile(pattern) m = p.search('one,,,two:three++++++4') print(m.group(0)) #one,,,two:three++++++4 (i.e: the whole match) print(m.group(1)) #one (i.e: match only group 1) - print(m.group(2, 3, 4)) #('two', 'three', '4') + print(m.group(2, 3, 4)) #('two', 'three', '4') ``` -### 6.4.4. Back Reference (\1, \2, \3, ...) + +### 6.4.4. Back Reference (\1, \2, \3, ...) + - `'(\w+)-\1'` is different from `'(\w+)-\w+'` - `'(\w+)-\1'` : when the first group is matched, `\1` match the same literal string in group1 -- For example: two patterns both match ‘one-one’, but the one with backreference, `'(\w+)-\1'`, won’t match ‘one-two’. +- For example: two patterns both match ‘one-one’, but the one with backreference, `'(\w+)-\1'`, won’t match ‘one-two’. ```Python - # pattern tries to match the type of number that starts with a few digits followed by one digit + # pattern tries to match the type of number that starts with a few digits followed by one digit # and then repeats the first few digits. p = re.compile(r'((\d+)\d\2)') m = p.finditer('1234123, 11311, 123, 54345') for string in m: - print(string.group(1, 2)) + print(string.group(1, 2)) #('1234123', '123') (i.e: 123 - 4 - same as group 2, in this case is 123) #('11311', '11') #('434', '4') ``` + ## 6.5. Flags + Three common flags that are very useful are: -- `re.MULTILINE` or `re.M` : make “^”/“$” match starting/ending position of each line. + +- `re.MULTILINE` or `re.M` : make “^”/“$” match starting/ending position of each line. - `re.IGNORECASE` or `re.I`: match letters in a case-insensitive way. -- `re.DOTALL` or `re.S` : make “.” match any character, including newlines \n. +- `re.DOTALL` or `re.S` : make “.” match any character, including newlines \n. ```Python p1 = re.compile(r'abc') @@ -613,7 +708,9 @@ m2 = p2.findall('abc ABC aBC Abc') #['abc', 'ABC', 'aBC', 'Abc'] because re.I me ``` ## 6.6. Module-Level re Methods + ### 6.6.1. re.match, re.search, re.findall, re.finditer + - Using the module-level methods can skip the step compiling the pattern. ```Python @@ -629,9 +726,12 @@ print(f'finditer: {finditer}') # ``` ### 6.6.2. String-modifying methods + #### Split() + - By default, the `split()` method returns a list of strings broken down, **excluding the matched strings**. - It is also possible to make split() return the matched strings, simply by using a group to capture the whole pattern. + ```Python p = re.compile(r'\W+') split = p.split('The~split*method-is%powerful') #['The', 'split', 'method', 'is', 'powerful'], by default @@ -640,7 +740,9 @@ split = p.split('The~split*method-is%powerful') #['The', 'split', 'method', 'is' p = re.compile(r'(\W+)') split = p.split('The~split*method-is%powerful') #'The', '~', 'split', '*', 'method', '-', 'is', '%', 'powerful'] ``` + #### Sub(replacement string, text to match the pattern) & Subn() + - `sub()` returns a new string after replacement. - `subn()` returns a tuple containing the new string and the number of replacements. @@ -651,9 +753,13 @@ subn = p.subn('Tokyo', 'Toko is Toko') #('Tokyo is Tokyo', 2) ``` ## 6.7. Look ahead and Look behind + ### 6.7.1. Look ahead (Look Forward) + #### Look ahead positive `(?=)` + - Find expression A where expression B is matching: `A(?=B)` + ```Python p = re.compile(r"\s(\w+(-\w+){1,3}(?=[\s.]))") #(?=[\s.]) match A if B=[\s.] is matching either space or dot. m = p.findall(''' @@ -665,15 +771,17 @@ There is a five-and-one-half-foot-long sign at the outskirt of the town.''') ``` #### Look ahead negative `(?!)` + - Find expression A where expression B does not follow:`A(?!B)` ### 6.7.2. Look behind (Look Backward) + #### Look behind positive `(?<=)` + - Find expression A where expression B precedes: `(?<=B)A` -#### Look behind negative `(? Date: Thu, 23 Feb 2023 23:52:40 +0800 Subject: [PATCH 009/150] update pyaml --- advanced/README.md | 8 ++++++ basics/.gitkeep | 0 basics/README.md | 23 ++++++++++++++++ {advanced => basics}/args_kwargs_tutorial.py | 0 basics/pyaml.py | 2 ++ daily_knowledge.md | 28 +++++++++++++++----- requirements.txt | 1 + 7 files changed, 55 insertions(+), 7 deletions(-) delete mode 100644 basics/.gitkeep create mode 100644 basics/README.md rename {advanced => basics}/args_kwargs_tutorial.py (100%) create mode 100644 basics/pyaml.py diff --git a/advanced/README.md b/advanced/README.md index 3eb1c15..966f53c 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -46,3 +46,11 @@ class Person: age: int job: str ``` + +## Test-driven development + +- The basic idea is that we write tests even before we write code. The tests define what it means to say that our program works “correctly.” +- Test templates: + - The first test in every exercise checks whether the expected program exists. + - The second test checks that the program will print a help message if we ask for help. + - After that, your program will be run with various inputs and options. diff --git a/basics/.gitkeep b/basics/.gitkeep deleted file mode 100644 index e69de29..0000000 diff --git a/basics/README.md b/basics/README.md new file mode 100644 index 0000000..54c444e --- /dev/null +++ b/basics/README.md @@ -0,0 +1,23 @@ +# Basics Python + +## Code Formater + +- The [PEP 8 (Python Enhancement Proposal)](www.python.org/dev/peps/pep-0008/) describes best practices for formatting code, and most IDEs and text editors will have tools to help you format your code so that it’s easier to read and find problems. + +## Code Linter + +- A code linter is a tool that will report problems in your code, such as declaring a variable but never using it. +- Two most popular code linter: [Pylint](www.pylint.org/) and [Flake8](http://flake8.pycqa.org/en/latest/), and both can find errors in your code that the Python interpreter itself will not complain about. +- [Mypy](http://mypy-lang.org/) can use to find problems along with type hints, such as using text when you should be using a number. + +## Python IDLE + +- Python can run into 2 modes: Interactive (**Python IDLE**, **IPython**) & Script mode +- The _IDLE_ application (REPL because it’s a Read-Evaluate-Print-Loop) allows you to interact directly with the Python language. Each statement you type is evaluated when you press Enter, and the results are shown in the window. +- The _IPython_ program is yet another “interactive Python” REPL that has many enhancements over IDLE and python3 + +## Pip + +- Show package information: `pip show -f ` +- Upgrade package: `pip install --upgrade ` +- Uninstall & install again: `pip install --ignore-installed ` diff --git a/advanced/args_kwargs_tutorial.py b/basics/args_kwargs_tutorial.py similarity index 100% rename from advanced/args_kwargs_tutorial.py rename to basics/args_kwargs_tutorial.py diff --git a/basics/pyaml.py b/basics/pyaml.py new file mode 100644 index 0000000..3d6a50d --- /dev/null +++ b/basics/pyaml.py @@ -0,0 +1,2 @@ +# !pip install pyaml + diff --git a/daily_knowledge.md b/daily_knowledge.md index 36d2ab6..36368ac 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,34 +1,48 @@ # 2023 -## Day 2 -### Git -#### Edit Git Commits -- + ### Matplotlib + - Set params: + ```Python plt.rcParams.update({'font.size': 14}) ``` + ### Python General + - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. + ## Day 1 + ### VS Code + #### VS Code Shortcuts + - `CMD + Shift + P`: Command Palette - `CMD + P`: Quickly open files + +#### Auto Venv Activation + +```json +# in .vscode settings.json + "python.terminal.activateEnvironment": true +``` + #### Code Formatter + - The main coding standard for Python is PEP8 (Python Enhancement Proposal 8) - **Linters** such as `flake8` and `pylint` highlight places where your code doesn’t conform with PEP8. - **Automatic formatters** such as `black` that will update your code automatically to conform with coding standards. -- How to install `flack8`: +- How to install `flack8`: - Step 1: Install `black` in virtual environment: `pip install flake8` - Step 2: Open the Command Palette (`CMD + Shift + P`) → Search the “Python: Select Linter” and press enter. Select the “flake8” - How to install `black`: - Step 1: Install `black` in virtual environment: `pip install black` - Step 2: Open the Command Palette (`CMD + Shift + P`) → “Preferences → Settings” - Search “format on save” and check the checkbox - - Search “python formatting provider” and select the `black`. + - Search “python formatting provider” and select the `black`. - How to install `isort`: - - Open the Command Palette (`CMD + Shift + P`). Search the “Preferences: Configure Language Specific Settings” and press enter. And search the “Python” and press enter. It will open the “settings.json”. + - Open the Command Palette (`CMD + Shift + P`). Search the “Preferences: Configure Language Specific Settings” and press enter. And search the “Python” and press enter. It will open the “settings.json”. ```json "editor.codeActionsOnSave": { "source.organizeImports": true diff --git a/requirements.txt b/requirements.txt index 599ee5c..6954ac5 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ attrs pydantic +pyaml From 056bc0335b070f822a6be97d4989a01054da83de Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Sat, 25 Feb 2023 12:09:26 +0800 Subject: [PATCH 010/150] update shebang & linux command --- advanced/pytest/README.md | 9 +++++++++ basics/README.md | 33 +++++++++++++++++++++++++++++---- docs/linux_commands.md | 31 +++++++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 advanced/pytest/README.md create mode 100644 docs/linux_commands.md diff --git a/advanced/pytest/README.md b/advanced/pytest/README.md new file mode 100644 index 0000000..5c25e10 --- /dev/null +++ b/advanced/pytest/README.md @@ -0,0 +1,9 @@ +# PyTest + +## Execution Flag +- `-x` to stop on the first failing test. No more tests are run after that. +- `-v` to print verbose output. + +```Shell +pytest -xv test.py +``` \ No newline at end of file diff --git a/basics/README.md b/basics/README.md index 54c444e..2666e4e 100644 --- a/basics/README.md +++ b/basics/README.md @@ -10,14 +10,39 @@ - Two most popular code linter: [Pylint](www.pylint.org/) and [Flake8](http://flake8.pycqa.org/en/latest/), and both can find errors in your code that the Python interpreter itself will not complain about. - [Mypy](http://mypy-lang.org/) can use to find problems along with type hints, such as using text when you should be using a number. +## Pip + +- Show package information: `pip show -f ` +- Upgrade package: `pip install --upgrade ` +- Uninstall & install again: `pip install --ignore-installed ` + ## Python IDLE - Python can run into 2 modes: Interactive (**Python IDLE**, **IPython**) & Script mode - The _IDLE_ application (REPL because it’s a Read-Evaluate-Print-Loop) allows you to interact directly with the Python language. Each statement you type is evaluated when you press Enter, and the results are shown in the window. - The _IPython_ program is yet another “interactive Python” REPL that has many enhancements over IDLE and python3 -## Pip +## Shebang `#!` -- Show package information: `pip show -f ` -- Upgrade package: `pip install --upgrade ` -- Uninstall & install again: `pip install --ignore-installed ` +- Python programs live in plain text files +- It’s common to put a special comment line in programs like `#!/usr/bin/env python3` these to indicate which language needs to be used to execute the commands in the file. +- Python will ignore the shebang, but the operating systems (like macOS or Windows) will use it to decide which program to use to run the rest of the file. +- Below is the shebang you should add at the beginning of the file + +``` +#!/usr/bin/env python3 +``` + +- The shebang line tells the operating system to use the `env` program (located at `/usr/bin/env`) to find the **python3** that is specific to the machine on which it’s running. + +### Executable Python Program + +- So far we’ve been explicitly telling python3 to run our program (`python3 hello.py`), but since we added the shebang, we can execute the program directly and let the OS figure out that it should use python3. +- The first step in doing this is to make our program “executable” using the command `chmod` + +```bash +chmod +x hello.py # +x will add an “executable” attribute to the file + +# Now can run the program like +./hello.py +``` diff --git a/docs/linux_commands.md b/docs/linux_commands.md new file mode 100644 index 0000000..50689cc --- /dev/null +++ b/docs/linux_commands.md @@ -0,0 +1,31 @@ +# Linux Command + +- `chmod` make our program “executable” + - `+x` add an “executable” attribute to the file +```bash +chmod +x hello.py # +x will add an “executable” attribute to the file + +# Now can run the program like +./hello.py +``` + +- `echo` to print + +```bash +echo $USER +# quannguyen +echo $HOME +# /Users/quannguyen +``` + +- `env` is the env program will tell you about your “environment.” + - If you run `env` on your computer, you should see your login name and your home directory. + - use the `env ` command to find and run programs, say if we type`env python3`, the env program is looking for python3 in the environment. If Python has not been installed, it won’t be able to find it, but it’s also possible that Python has been installed more than once. +- `which` to see where the program is installed + +```bash +which env +# /usr/bin/env +which python3 +# /usr/local/bin/python3 +``` From 21cdfa73b90b8165b8ecf23337218ef39fc9dc08 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Mon, 27 Feb 2023 00:44:25 +0800 Subject: [PATCH 011/150] update argparse & makefile --- basics/README.md | 49 ++++++++++++++++++++++++++++++++++- basics/subprocess_tutorial.py | 1 + docs/linux_commands.md | 31 ++++++++++++++++++++++ 3 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 basics/subprocess_tutorial.py diff --git a/basics/README.md b/basics/README.md index 2666e4e..c7d43a8 100644 --- a/basics/README.md +++ b/basics/README.md @@ -1,5 +1,37 @@ # Basics Python +## Argument Parser + +- The `argparse` module will “parse” the “arguments” to the program. + - Make the `name` optional by changing the name of the argument to `--name` + - `-n` for the “short” and and `--name` for “long” option names. + - `metavar` value of “name” to describe what the value should be. + +```Python +import argparse + +parser = argparse.ArgumentParser(description='Say hello') +# parser.add_argument('name', help='user_name to greet') # positional argument 'name' +parser.add_argument('-n', '--name', metavar='user_name', + default='World', help='user_name to greet') +args = parser.parse_args() + +print('Hello, ' + args.name + '!') +``` + +| Type | Example | Required | Default | +| ---------- | ------------------------------ | -------- | ------- | +| Positional | `name` | Yes | No | +| Optinal | `-n` (short), `--name` (long)) | No | Yes | + +- `-h` and `--help` to get the documentation + +```Python +optional arguments: + -h, --help show this help message and exit + -n user_name, --name user_name user_name to greet +``` + ## Code Formater - The [PEP 8 (Python Enhancement Proposal)](www.python.org/dev/peps/pep-0008/) describes best practices for formatting code, and most IDEs and text editors will have tools to help you format your code so that it’s easier to read and find problems. @@ -10,6 +42,20 @@ - Two most popular code linter: [Pylint](www.pylint.org/) and [Flake8](http://flake8.pycqa.org/en/latest/), and both can find errors in your code that the Python interpreter itself will not complain about. - [Mypy](http://mypy-lang.org/) can use to find problems along with type hints, such as using text when you should be using a number. +## Makefile + +- If there is something you need to do literally hundreds of times, say run pytest, so you can creat a **Makefile** that looks like this: + +```Python +.PHONY: test + +test: + pytest -xv test.py +``` + +- If you have the program `make` installed on your computer, you can run you can run `make test` to execute `pytest -xv test.py` + - The `make` program will look for a Makefile in your current working directory and then look for a recipe called “test.” + ## Pip - Show package information: `pip show -f ` @@ -43,6 +89,7 @@ ```bash chmod +x hello.py # +x will add an “executable” attribute to the file -# Now can run the program like +# Now can run the program like +# The . / is the current directory, and it’s necessary to run a program when you are in the same directory as the program. ./hello.py ``` diff --git a/basics/subprocess_tutorial.py b/basics/subprocess_tutorial.py new file mode 100644 index 0000000..54d5ee6 --- /dev/null +++ b/basics/subprocess_tutorial.py @@ -0,0 +1 @@ +# Link: https://www.simplilearn.com/tutorials/python-tutorial/subprocess-in-python \ No newline at end of file diff --git a/docs/linux_commands.md b/docs/linux_commands.md index 50689cc..ab76a8f 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -1,7 +1,36 @@ # Linux Command +## Special Variables + +### `$PATH` variable + +- Windows, macOS, and Linux all have a `$PATH` variable, which is a list of directories the OS will look in to find a program (using the `env` program) + - The `$PATH` variable is a way of telling your computer to only look in places where executable programs can be found. + - The directories are separated by colons (`:`). Notice that the directory where **python3** lives is the first one in `$PATH` + +```bash + echo $PATH +/Users/quannguyen/repos/tiny_python_projects/venv/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin +``` + +### Altering your `$PATH` + +- Simply add the path where your program (script) is located to $PATH, You should now be able to execute the script anywhere on your system by just typing in its name, without having to include the full path as you type it. + +```bash +$ mkdir ~/bin # Use the mkdir (“make directory”) command to create ~/bin. +$ cp 01_hello/hello.py ~/bin # Use the cp command to copy the 01_hello/hello.py program to the ~/bin directory. +$ PATH=~/bin:$PATH # Put the ~/bin directory first in $PATH. +$ PATH=$PATH:~/bin # Put the ~/bin directory last in $PATH. +$ which hello.py # /home/quannguyen/bin/hello.py + +``` + +## Command Linux Commands + - `chmod` make our program “executable” - `+x` add an “executable” attribute to the file + ```bash chmod +x hello.py # +x will add an “executable” attribute to the file @@ -19,8 +48,10 @@ echo $HOME ``` - `env` is the env program will tell you about your “environment.” + - If you run `env` on your computer, you should see your login name and your home directory. - use the `env ` command to find and run programs, say if we type`env python3`, the env program is looking for python3 in the environment. If Python has not been installed, it won’t be able to find it, but it’s also possible that Python has been installed more than once. + - `which` to see where the program is installed ```bash From 5dc0a72f96afe8ba11eccc3a7e3097b18b79a6c0 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 3 Mar 2023 23:16:55 +0800 Subject: [PATCH 012/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 36368ac..5b6e632 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -9,8 +9,8 @@ plt.rcParams.update({'font.size': 14}) ``` ### Python General - - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. +- `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. ## Day 1 From 4304857cf5980c8d3ab6961766075f4a834e59d2 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Sun, 5 Mar 2023 10:07:48 +0800 Subject: [PATCH 013/150] update google colab --- basics/data/items.yaml | 12 + basics/google_colab_tutorial.ipynb | 516 +++++++++++++++++++++++++++++ basics/pyaml.py | 2 - basics/pyaml_tutorial.py | 13 + 4 files changed, 541 insertions(+), 2 deletions(-) create mode 100644 basics/data/items.yaml create mode 100644 basics/google_colab_tutorial.ipynb delete mode 100644 basics/pyaml.py create mode 100644 basics/pyaml_tutorial.py diff --git a/basics/data/items.yaml b/basics/data/items.yaml new file mode 100644 index 0000000..f614a17 --- /dev/null +++ b/basics/data/items.yaml @@ -0,0 +1,12 @@ +cities: + - Bratislava + - Kosice + - Trnava + - Moldava + - Trencin +--- +companies: + - Eset + - Slovnaft + - Duslo Sala + - Matador Puchov diff --git a/basics/google_colab_tutorial.ipynb b/basics/google_colab_tutorial.ipynb new file mode 100644 index 0000000..6f5da0a --- /dev/null +++ b/basics/google_colab_tutorial.ipynb @@ -0,0 +1,516 @@ +{ + "nbformat": 4, + "nbformat_minor": 0, + "metadata": { + "colab": { + "provenance": [], + "toc_visible": true + }, + "kernelspec": { + "name": "python3", + "display_name": "Python 3" + }, + "language_info": { + "name": "python" + } + }, + "cells": [ + { + "cell_type": "markdown", + "source": [ + "# Introduction to Google Colab\n", + "\n", + "## Jupyter Notebook\n", + "\n", + "- a browser-based environment that integrates code and its output into a single document that combines texts, images, visualizations, mathematical equations.\n", + "- displays outputs, results and data visualization without leaving the environment \n", + "- handy for end to end data science workflows - data cleaning, statistical modeling, building and training machine learning models, visualizing data etc.\n", + "- code is written in independent cells which are executed individually \n", + "- allows the user to test a specific block of code in a project without having to execute the code from the start of the script\n", + "- hosted and run on local machine\n", + "\n", + "## Google Colab\n", + "\n", + "- similar to Jupyter Notebook, but runs entirely in the cloud\n", + "- provides the use of free GPU \n", + "- runs on Google servers using virtual machines – do not need to install any packages\n", + "- allows easy sharing of notebook (just like Google Docs) or to GitHub repository\n", + "- Jupyter Notebook can be uploaded to and run in Google Colab \n", + "\n", + "All the lab materials will be prepared and run on Colab. If you need to access data that are not provided on cloud, you will have to use your Google drive to store the data so that you can access the data in Colab environment. To do so, you must mount your Google Drive on Colab." + ], + "metadata": { + "id": "cN87HBJM6j1R" + } + }, + { + "cell_type": "code", + "source": [ + "print(\"Hello World\")" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "KXK8GEoX3obD", + "outputId": "4450b11b-8668-4f65-c380-fb79b19ce2c2" + }, + "execution_count": 1, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Hello World\n" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Linux Commands & Pip Install" + ], + "metadata": { + "id": "PuUGb5hpJCJh" + } + }, + { + "cell_type": "code", + "source": [ + "!ls" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "rvM23hQc6hD-", + "outputId": "8bff903e-b308-47f0-de21-0a8c16fe6e18" + }, + "execution_count": 2, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "sample_data\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "!pwd" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "FZgGHnhTJMnf", + "outputId": "bcb31dc8-142e-42e3-8839-e139ec5923b3" + }, + "execution_count": 3, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "/content\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "!pip freeze | grep tensorflow" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "h2OdrL5xJTLG", + "outputId": "126b5da6-d5b9-4893-dc5e-a903188b758c" + }, + "execution_count": 7, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "tensorflow==2.11.0\n", + "tensorflow-datasets==4.8.3\n", + "tensorflow-estimator==2.11.0\n", + "tensorflow-gcs-config==2.11.0\n", + "tensorflow-hub==0.12.0\n", + "tensorflow-io-gcs-filesystem==0.31.0\n", + "tensorflow-metadata==1.12.0\n", + "tensorflow-probability==0.19.0\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "!pip show tensorflow" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "TqzXNt0rJeKB", + "outputId": "99c5c86e-38ba-4470-bf6e-8c7043d7a36b" + }, + "execution_count": 8, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Name: tensorflow\n", + "Version: 2.11.0\n", + "Summary: TensorFlow is an open source machine learning framework for everyone.\n", + "Home-page: https://www.tensorflow.org/\n", + "Author: Google Inc.\n", + "Author-email: packages@tensorflow.org\n", + "License: Apache 2.0\n", + "Location: /usr/local/lib/python3.8/dist-packages\n", + "Requires: absl-py, astunparse, flatbuffers, gast, google-pasta, grpcio, h5py, keras, libclang, numpy, opt-einsum, packaging, protobuf, setuptools, six, tensorboard, tensorflow-estimator, tensorflow-io-gcs-filesystem, termcolor, typing-extensions, wrapt\n", + "Required-by: \n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "!pip install tensorflow==2.12.0" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "yTl_4aCZKsA0", + "outputId": "b1784fdb-2e46-44da-c2c7-137787e95a29" + }, + "execution_count": 12, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Looking in indexes: https://pypi.org/simple, https://us-python.pkg.dev/colab-wheels/public/simple/\n", + "\u001b[31mERROR: Could not find a version that satisfies the requirement tensorflow==2.12.0 (from versions: 2.2.0, 2.2.1, 2.2.2, 2.2.3, 2.3.0, 2.3.1, 2.3.2, 2.3.3, 2.3.4, 2.4.0, 2.4.1, 2.4.2, 2.4.3, 2.4.4, 2.5.0, 2.5.1, 2.5.2, 2.5.3, 2.6.0rc0, 2.6.0rc1, 2.6.0rc2, 2.6.0, 2.6.1, 2.6.2, 2.6.3, 2.6.4, 2.6.5, 2.7.0rc0, 2.7.0rc1, 2.7.0, 2.7.1, 2.7.2, 2.7.3, 2.7.4, 2.8.0rc0, 2.8.0rc1, 2.8.0, 2.8.1, 2.8.2, 2.8.3, 2.8.4, 2.9.0rc0, 2.9.0rc1, 2.9.0rc2, 2.9.0, 2.9.1, 2.9.2, 2.9.3, 2.10.0rc0, 2.10.0rc1, 2.10.0rc2, 2.10.0rc3, 2.10.0, 2.10.1, 2.11.0rc0, 2.11.0rc1, 2.11.0rc2, 2.11.0, 2.12.0rc0)\u001b[0m\u001b[31m\n", + "\u001b[0m\u001b[31mERROR: No matching distribution found for tensorflow==2.12.0\u001b[0m\u001b[31m\n", + "\u001b[0m" + ] + } + ] + }, + { + "cell_type": "markdown", + "source": [ + "# Mount Google Drive" + ], + "metadata": { + "id": "eULiCOinLmFI" + } + }, + { + "cell_type": "code", + "source": [ + "from google.colab import drive\n", + "drive.mount('/content/drive/')" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "aR0WVsK6LXpb", + "outputId": "e4def66b-cea2-4471-e267-3944320a1a61" + }, + "execution_count": 15, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "Mounted at /content/drive/\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "!ls \"/content/drive/MyDrive\"" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/" + }, + "id": "a25i6fFKL4yR", + "outputId": "32bf0556-2242-4e64-8f0f-67398f5e54a2" + }, + "execution_count": 16, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "'Colab Notebooks'\t ML_Algo\n", + " CS608-Recommender-Systems NLP_Transformers-for-NLP-2nd-Edition\n", + " Drift_Detection\t SMU_MITB_NLP\n", + " FSDL_2021\t\t Table_Extraction\n", + " FSDL_2022\t\t YOLO\n" + ] + } + ] + }, + { + "cell_type": "code", + "source": [ + "import pandas as pd" + ], + "metadata": { + "id": "Kz1x6Wg3MKtX" + }, + "execution_count": 17, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "df = pd.read_csv('/content/drive/MyDrive/ML_Algo/Boosting/data/diamonds.csv', index_col='Unnamed: 0')" + ], + "metadata": { + "id": "_gpj7L9PMdkv" + }, + "execution_count": 20, + "outputs": [] + }, + { + "cell_type": "code", + "source": [ + "df.head()" + ], + "metadata": { + "colab": { + "base_uri": "https://localhost:8080/", + "height": 206 + }, + "id": "iWWnsaG8MjaR", + "outputId": "2b1dcdcb-dc9e-4f4d-c257-82f197800ac2" + }, + "execution_count": 21, + "outputs": [ + { + "output_type": "execute_result", + "data": { + "text/plain": [ + " carat cut color clarity depth table price x y z\n", + "1 0.23 Ideal E SI2 61.5 55.0 326 3.95 3.98 2.43\n", + "2 0.21 Premium E SI1 59.8 61.0 326 3.89 3.84 2.31\n", + "3 0.23 Good E VS1 56.9 65.0 327 4.05 4.07 2.31\n", + "4 0.29 Premium I VS2 62.4 58.0 334 4.20 4.23 2.63\n", + "5 0.31 Good J SI2 63.3 58.0 335 4.34 4.35 2.75" + ], + "text/html": [ + "\n", + "
\n", + "
\n", + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
caratcutcolorclaritydepthtablepricexyz
10.23IdealESI261.555.03263.953.982.43
20.21PremiumESI159.861.03263.893.842.31
30.23GoodEVS156.965.03274.054.072.31
40.29PremiumIVS262.458.03344.204.232.63
50.31GoodJSI263.358.03354.344.352.75
\n", + "
\n", + " \n", + " \n", + " \n", + "\n", + " \n", + "
\n", + "
\n", + " " + ] + }, + "metadata": {}, + "execution_count": 21 + } + ] + }, + { + "cell_type": "code", + "source": [], + "metadata": { + "id": "J8KeUpLCMkj9" + }, + "execution_count": null, + "outputs": [] + } + ] +} \ No newline at end of file diff --git a/basics/pyaml.py b/basics/pyaml.py deleted file mode 100644 index 3d6a50d..0000000 --- a/basics/pyaml.py +++ /dev/null @@ -1,2 +0,0 @@ -# !pip install pyaml - diff --git a/basics/pyaml_tutorial.py b/basics/pyaml_tutorial.py new file mode 100644 index 0000000..eeefd62 --- /dev/null +++ b/basics/pyaml_tutorial.py @@ -0,0 +1,13 @@ +# !pip install pyaml +from pathlib import Path + +import yaml + +curr_dir = Path(__file__).resolve().parent +with open(curr_dir / "data/items.yaml", "r") as f: + # load_all: is to load multiple document in a single YAML + docs = yaml.load_all(f, Loader=yaml.FullLoader) + + for doc in docs: + for k, v in doc.items(): + print(k, v) From ec9b40fdc511e803791bba7125e94352e2ac2092 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 5 Mar 2023 23:24:10 +0800 Subject: [PATCH 014/150] Update daily_knowledge.md --- daily_knowledge.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5b6e632..cee42c3 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,16 +1,17 @@ # 2023 - +## Day 2 +### Pandas +- `to_csv` to prevent `nnamed: 0` column to be appended along with your original df + - Solution: set `df.to_csv(, index=False)` ### Matplotlib - - Set params: - ```Python plt.rcParams.update({'font.size': 14}) ``` - -### Python General +### Python - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. - `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. +- Randomly select an item in a list: `random.randint(0, len_x)` ## Day 1 From a079c5d704e93e62c0f62ce2fd00ccafe3d88593 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 7 Mar 2023 18:08:30 +0800 Subject: [PATCH 015/150] Update daily_knowledge.md --- daily_knowledge.md | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index cee42c3..3fc3d8f 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,8 +1,23 @@ # 2023 ## Day 2 ### Pandas -- `to_csv` to prevent `nnamed: 0` column to be appended along with your original df - - Solution: set `df.to_csv(, index=False)` +- `to_csv` to prevent `nnamed: 0` column to be appended along with your original df by set `df.to_csv(, index=False)` +- `.apply` based on the condition of certain columns +```Python +df.loc[:,'C'] = df.apply(lambda row: 'Hi' if row['A'] > 10 and row['B'] < 5 else '') +``` +### Numpy +- Numpy vs Tensor: A significant difference between NumPy arrays and TensorFlow tensors is that TensorFlow tensors aren’t assignable: they’re constant +```Python +import numpy as np +x = np.ones(shape=(2, 2)) +x[0, 0] = 0. + +x = tf.ones(shape=(2, 2)) +x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. +``` + + ### Matplotlib - Set params: ```Python From 61641267409971a48356a30cbf524901cfe5f94e Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 7 Mar 2023 18:14:09 +0800 Subject: [PATCH 016/150] Update daily_knowledge.md --- daily_knowledge.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 3fc3d8f..95d0b59 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -26,8 +26,10 @@ plt.rcParams.update({'font.size': 14}) ### Python - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. - `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. -- Randomly select an item in a list: `random.randint(0, len_x)` - +- `random` module + - Randomly select an item in a list: `random.randint(0, len_x)` + - Normal distribution with mean 0 and standard deviation 1: `np.random.normal(size=(3,1), loc=0., scale=1.)` + - Uniform distribution between 0 and 1: ` np.random.uniform(size=(3, 1), low=0., high=1.)` ## Day 1 ### VS Code From 84ffd6afac5f3a8ad060c04c1f568fecfe241070 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 7 Mar 2023 18:45:20 +0800 Subject: [PATCH 017/150] Update daily_knowledge.md --- daily_knowledge.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 95d0b59..f482c2e 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -7,7 +7,10 @@ df.loc[:,'C'] = df.apply(lambda row: 'Hi' if row['A'] > 10 and row['B'] < 5 else '') ``` ### Numpy -- Numpy vs Tensor: A significant difference between NumPy arrays and TensorFlow tensors is that TensorFlow tensors aren’t assignable: they’re constant +- Numpy vs Tensor: + - TensorFlow seems to look a lot like NumPy. But here’s something NumPy can’t do: retrieve the gradient of any differentiable expression with respect to any of its inputs. + - Open a `GradientTape` scope, apply some computation to one or several input tensors, and retrieve the gradient of the result with respect to the inputs. + - A significant difference between NumPy arrays and TensorFlow tensors is that TensorFlow tensors aren’t assignable: they’re constant ```Python import numpy as np x = np.ones(shape=(2, 2)) From 67261927af7c129a1d84a1331e3f1adb43bc69e1 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 7 Mar 2023 19:12:25 +0800 Subject: [PATCH 018/150] Update daily_knowledge.md --- daily_knowledge.md | 1 + 1 file changed, 1 insertion(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index f482c2e..59e485f 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -31,6 +31,7 @@ plt.rcParams.update({'font.size': 14}) - `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. - `random` module - Randomly select an item in a list: `random.randint(0, len_x)` + - Randomly select subset of items in a list: `indices_permutation = random.permutation(len(x)); x[indices_permutation][:10]` - Normal distribution with mean 0 and standard deviation 1: `np.random.normal(size=(3,1), loc=0., scale=1.)` - Uniform distribution between 0 and 1: ` np.random.uniform(size=(3, 1), low=0., high=1.)` ## Day 1 From 8433c9840619ce61dc161021a8734b57d200f17a Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 9 Mar 2023 23:06:42 +0700 Subject: [PATCH 019/150] Update daily_knowledge.md --- daily_knowledge.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 59e485f..d23a500 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -27,8 +27,14 @@ x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. plt.rcParams.update({'font.size': 14}) ``` ### Python -- `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. - `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. +- `iter()`: return an iterator for the given a list, set, tuple or object with `__next__()` method. +```Python +phones = ['apple', 'samsung', 'oneplus'] +phones_iter = iter(phones) +print(next(phones_iter)) +``` +- `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. - `random` module - Randomly select an item in a list: `random.randint(0, len_x)` - Randomly select subset of items in a list: `indices_permutation = random.permutation(len(x)); x[indices_permutation][:10]` From 584463676ab478d534cff89658ae6809711b7afc Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 15 Mar 2023 22:17:49 +0800 Subject: [PATCH 020/150] Update daily_knowledge.md --- daily_knowledge.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index d23a500..85427a3 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -7,6 +7,8 @@ df.loc[:,'C'] = df.apply(lambda row: 'Hi' if row['A'] > 10 and row['B'] < 5 else '') ``` ### Numpy +- Dense & Sparse Matrix Conversion: + - Sparse → Dense: `A.toarray()` - Numpy vs Tensor: - TensorFlow seems to look a lot like NumPy. But here’s something NumPy can’t do: retrieve the gradient of any differentiable expression with respect to any of its inputs. - Open a `GradientTape` scope, apply some computation to one or several input tensors, and retrieve the gradient of the result with respect to the inputs. From 9f18a472b87a7dce930a9f0cdbe62f177d98a249 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 15 Mar 2023 22:19:42 +0800 Subject: [PATCH 021/150] Update daily_knowledge.md --- daily_knowledge.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 85427a3..372aa8e 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,4 +1,10 @@ # 2023 +## Day 3 +### Python +- Load pickle file using `joblib` +```Python +model = joblib.load('lgbm_mode.pkl') +``` ## Day 2 ### Pandas - `to_csv` to prevent `nnamed: 0` column to be appended along with your original df by set `df.to_csv(, index=False)` @@ -22,12 +28,12 @@ x = tf.ones(shape=(2, 2)) x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. ``` - ### Matplotlib - Set params: ```Python plt.rcParams.update({'font.size': 14}) ``` + ### Python - `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. - `iter()`: return an iterator for the given a list, set, tuple or object with `__next__()` method. @@ -42,24 +48,19 @@ print(next(phones_iter)) - Randomly select subset of items in a list: `indices_permutation = random.permutation(len(x)); x[indices_permutation][:10]` - Normal distribution with mean 0 and standard deviation 1: `np.random.normal(size=(3,1), loc=0., scale=1.)` - Uniform distribution between 0 and 1: ` np.random.uniform(size=(3, 1), low=0., high=1.)` -## Day 1 +## Day 1 ### VS Code - #### VS Code Shortcuts - - `CMD + Shift + P`: Command Palette - `CMD + P`: Quickly open files - #### Auto Venv Activation ```json # in .vscode settings.json "python.terminal.activateEnvironment": true ``` - #### Code Formatter - - The main coding standard for Python is PEP8 (Python Enhancement Proposal 8) - **Linters** such as `flake8` and `pylint` highlight places where your code doesn’t conform with PEP8. - **Automatic formatters** such as `black` that will update your code automatically to conform with coding standards. From dee29e60601f04809cb3216c96dc6282eed2d8ec Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 16 Mar 2023 23:40:07 +0800 Subject: [PATCH 022/150] Update daily_knowledge.md --- daily_knowledge.md | 1 + 1 file changed, 1 insertion(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 372aa8e..a4e3f65 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -42,6 +42,7 @@ phones = ['apple', 'samsung', 'oneplus'] phones_iter = iter(phones) print(next(phones_iter)) ``` +- `os.environ[variable]=value` a mapping object that represents the user’s environmental variables. - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. - `random` module - Randomly select an item in a list: `random.randint(0, len_x)` From 58258044ba98195a3a4901dac28c752cfce865a4 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 17 Mar 2023 21:53:49 +0800 Subject: [PATCH 023/150] Update daily_knowledge.md --- daily_knowledge.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index a4e3f65..0979e81 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,6 +1,8 @@ # 2023 ## Day 3 ### Python +- `python -m pip install ` + - [`-m` flag](https://stackoverflow.com/a/69527909/7973510) makes sure that you are using the pip that's tied to the active Python executable. - Load pickle file using `joblib` ```Python model = joblib.load('lgbm_mode.pkl') From 6f26e07330b3b51c3cb9b9f94b3ede1a61c0fdb9 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 17 Mar 2023 21:56:50 +0800 Subject: [PATCH 024/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 0979e81..b8c4756 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -76,7 +76,7 @@ print(next(phones_iter)) - Search “format on save” and check the checkbox - Search “python formatting provider” and select the `black`. - How to install `isort`: - - Open the Command Palette (`CMD + Shift + P`). Search the “Preferences: Configure Language Specific Settings” and press enter. And search the “Python” and press enter. It will open the “settings.json”. + - Open the Command Palette (`CMD + Shift + P`). Search the “Preferences: Open User Settings (JSON)” and press enter. It will open the “settings.json” and add the follow code into that: ```json "editor.codeActionsOnSave": { "source.organizeImports": true From eeeee844c39e3ba258185c5900be9885810a5ee9 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 17 Mar 2023 21:59:30 +0800 Subject: [PATCH 025/150] Update daily_knowledge.md --- daily_knowledge.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index b8c4756..de499d6 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,6 +1,14 @@ # 2023 ## Day 3 ### Python +- Reload a module in Jupyter notebook +```Python +from importlib import reload +from abc import module_a +# By doing this, whatever code change in class_xyz will be reflected in the notebook +reload(module_a) +from abc.module_a import class_xyz +``` - `python -m pip install ` - [`-m` flag](https://stackoverflow.com/a/69527909/7973510) makes sure that you are using the pip that's tied to the active Python executable. - Load pickle file using `joblib` From 07e2c69374a9ac3b91d789a24f99a4bd1a65ba75 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 17 Mar 2023 22:02:53 +0800 Subject: [PATCH 026/150] Update daily_knowledge.md --- daily_knowledge.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index de499d6..eaef166 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,6 +1,8 @@ # 2023 ## Day 3 ### Python +- Logging level: `DEBUG > INFO > WARNING > ERROR > CRITICAL` + - If set `logging.basicConfig(level=logging.ERROR)` means that only log `ERROR` & `CRITICAL` - Reload a module in Jupyter notebook ```Python from importlib import reload From 4b9bc605cefbe242d7969a5504afa2bf62bfa0a3 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 17 Mar 2023 22:03:35 +0800 Subject: [PATCH 027/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index eaef166..eb1e494 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -3,7 +3,7 @@ ### Python - Logging level: `DEBUG > INFO > WARNING > ERROR > CRITICAL` - If set `logging.basicConfig(level=logging.ERROR)` means that only log `ERROR` & `CRITICAL` -- Reload a module in Jupyter notebook +- `reload` a module in Jupyter notebook ```Python from importlib import reload from abc import module_a From cd08a2f6a96ab0fd8fa8c0c4fc787b9edfac516e Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 18 Mar 2023 11:12:24 +0800 Subject: [PATCH 028/150] Update daily_knowledge.md --- daily_knowledge.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index eb1e494..9c23442 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -41,10 +41,9 @@ x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. ``` ### Matplotlib -- Set params: -```Python -plt.rcParams.update({'font.size': 14}) -``` +- Set params: `plt.rcParams.update({'font.size': 14})` +- Set vertical axis range: `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` + ### Python - `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. From 0cab347f63f868afadba42a93ac47d54492f00ff Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 18 Mar 2023 11:13:26 +0800 Subject: [PATCH 029/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 9c23442..5a4e844 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -42,7 +42,7 @@ x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. ### Matplotlib - Set params: `plt.rcParams.update({'font.size': 14})` -- Set vertical axis range: `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` +- Set vertical axis range: `ax.set_ylim([0,1])` or `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` ### Python From bf2a67d67d8f6317f29a0e0b1e2e8dcc3b6e7d31 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 21 Mar 2023 23:54:05 +0800 Subject: [PATCH 030/150] Update daily_knowledge.md --- daily_knowledge.md | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5a4e844..c8df44e 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -57,7 +57,15 @@ print(next(phones_iter)) - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. - `random` module - Randomly select an item in a list: `random.randint(0, len_x)` - - Randomly select subset of items in a list: `indices_permutation = random.permutation(len(x)); x[indices_permutation][:10]` + - Randomly select subset of items in a list: + ```Python + # Method 1 + indices_permutation = random.permutation(len(x)) + dataset[indices_permutation][:10] + # Method 2: select 10 out of the dataset + indices_permutation = random.sample(range(len(trainset)), 10) + dataset[indices_permutation] + ``` - Normal distribution with mean 0 and standard deviation 1: `np.random.normal(size=(3,1), loc=0., scale=1.)` - Uniform distribution between 0 and 1: ` np.random.uniform(size=(3, 1), low=0., high=1.)` From a1ad058373ad26766949ff03ddebbf14e349e901 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 2 Apr 2023 09:16:10 +0800 Subject: [PATCH 031/150] Update README.md --- advanced/README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/advanced/README.md b/advanced/README.md index 966f53c..7d1f79b 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -20,8 +20,9 @@ - The double underscore `__` prefixed to a variable makes it private. It gives a strong suggestion not to touch it from outside the class. Any attempt to do so will result in an `AttributeError` - **Name mangling**: Every member with a double underscore will be changed to `_object.___`. So, it can still be accessed from outside the class, but the practice should be refrained. -## Attrs, Pydantic, or Python Data Classes - +## Data Modeling & Validation +- Common Package: Attrs, Pydantic, or Python Data Classes + - `Pydantic` is a Python library for data modeling/parsing that has efficient error handling and a custom validation mechanism. ### Python Data Classes Dataclasses, as the name clearly suggests, are classes that are meant to hold data. The motivation behind this module is that we sometimes define classes that only act as data containers and when we do that, we spend a consequent amount of time writing boilerplate code with tons of arguments, an ugly `__init__` method and many overridden functions. From 583954cd901b5d432007bce87d06db4c6ed575d0 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 2 Apr 2023 09:19:08 +0800 Subject: [PATCH 032/150] Update README.md --- advanced/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/advanced/README.md b/advanced/README.md index 7d1f79b..e7da24f 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -55,3 +55,19 @@ class Person: - The first test in every exercise checks whether the expected program exists. - The second test checks that the program will print a help message if we ask for help. - After that, your program will be run with various inputs and options. + +## Virtual Environment +### Virtual Env Creation & Activation + +- Step 1: `python3 -m venv venv` for initialising the virtual environment +- Step 2: Activating the virtual environment + - Linux or MacOS `source venv/bin/activate` + - Window `venv/venv\Scripts\activate.bat` + +### Dependency Installation + +The following commands shall be ran **after activating the virtual environment**. + +- `pip install --upgrade pip` for upgrading the pip +- `pip install -r requirements.txt` for the functional dependencies +- `pip install -r requirements-dev.txt` for the development dependencies. (should include `pre-commit` module) From dedd91122d8a29ebb70ca7ce953eb140ae164be1 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 4 Apr 2023 22:36:31 +0800 Subject: [PATCH 033/150] Update daily_knowledge.md --- daily_knowledge.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index c8df44e..321336f 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -24,6 +24,32 @@ model = joblib.load('lgbm_mode.pkl') ```Python df.loc[:,'C'] = df.apply(lambda row: 'Hi' if row['A'] > 10 and row['B'] < 5 else '') ``` +#### Joining Pandas DataFrame +- Experience: before joining (either `concat`, `merge`), need to careful about the *index* of the dataframes (might need to `.reset_index()`) as apart from the joining condition, pandas also matching the index of each dataframe. +

+- `concat()` for combining DataFrames across rows or columns + - **axis** represents the axis that you’ll concatenate along. + - The default value is **0**, which concatenates **along the index**, or row axis. + - Alternatively, a value of **1** will concatenate vertically, **along columns**. You can also use the string values "index" or "columns". + - `ignore_index` defaults to False. + - If True, then the new combined dataset won’t preserve the original index values in the axis specified in the axis parameter. This lets you have entirely new index values. +- `merge()` for combining data on common columns or indices + - **how** defaults to `inner`, but other possible options include `outer`, `left`, and `right` + - `on`; `left_on` and `right_on` specify a column or index that’s present only in the left or right object that you’re merging +```Python +# ------------ pd.concat() examples ------------ +reindexed = pd.concat( + [df1, df2], ignore_index=True, axis=1 +) +# ------------ pd.merge() examples ------------- +pd.merge( + df1, df2, how="left", on=["col_A", "col_B"] +) +# if left & right DF has diff joining col names +pd.merge( + df1, df2, how="left", left_on=["col_A1"], right_on=["col_A2"] +) +``` ### Numpy - Dense & Sparse Matrix Conversion: - Sparse → Dense: `A.toarray()` From f87921b22876187753da5a9f6c3d802406d4046f Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 4 Apr 2023 22:39:06 +0800 Subject: [PATCH 034/150] Update daily_knowledge.md --- daily_knowledge.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 321336f..ffcead2 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -26,7 +26,12 @@ df.loc[:,'C'] = df.apply(lambda row: 'Hi' if row['A'] > 10 and row['B'] < 5 else ``` #### Joining Pandas DataFrame - Experience: before joining (either `concat`, `merge`), need to careful about the *index* of the dataframes (might need to `.reset_index()`) as apart from the joining condition, pandas also matching the index of each dataframe. -

+ +


Column Concat
+
+Merge [Inner, Outter (Left, Right)] +

+ - `concat()` for combining DataFrames across rows or columns - **axis** represents the axis that you’ll concatenate along. - The default value is **0**, which concatenates **along the index**, or row axis. From be4c3c80338065a3f8618206edc849b62d5bb7e7 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 29 Apr 2023 00:10:34 +0700 Subject: [PATCH 035/150] Update daily_knowledge.md --- daily_knowledge.md | 1 + 1 file changed, 1 insertion(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index ffcead2..30806af 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -74,6 +74,7 @@ x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. ### Matplotlib - Set params: `plt.rcParams.update({'font.size': 14})` - Set vertical axis range: `ax.set_ylim([0,1])` or `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` +- Enable subplots share the same axis with `sharex` or `sharey`: `plt.subplots(nrows=3, sharey=True)` ### Python From 83705a37f68fdfbb1e01fbafee33530b91aae82f Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 29 Apr 2023 00:12:24 +0700 Subject: [PATCH 036/150] Update daily_knowledge.md --- daily_knowledge.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 30806af..a11c071 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -74,8 +74,10 @@ x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. ### Matplotlib - Set params: `plt.rcParams.update({'font.size': 14})` - Set vertical axis range: `ax.set_ylim([0,1])` or `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` +#### Subplots - Enable subplots share the same axis with `sharex` or `sharey`: `plt.subplots(nrows=3, sharey=True)` - +- `fig.tight_layout(pad=2)` function of matplotlib allows to adhust the gap between subplots + - `pad` parameter to specify gap size ### Python - `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. From 02d01d1d5d225457cb100cce1e39fbbb4bd422ff Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 29 Apr 2023 00:26:32 +0700 Subject: [PATCH 037/150] Update daily_knowledge.md --- daily_knowledge.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index a11c071..c00f8d9 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -24,6 +24,11 @@ model = joblib.load('lgbm_mode.pkl') ```Python df.loc[:,'C'] = df.apply(lambda row: 'Hi' if row['A'] > 10 and row['B'] < 5 else '') ``` +- `df.insert()` Avoid error `Try using .loc[row_indexer,col_indexer] ` when creating the new column in df from an existing df +```Python +# insert(position of the newly_inserted_col in the df, newly_inserted_col's name, newly_inserted_col's value) +data.insert(len(data.columns), 'rolling', data['open'].rolling(5).mean().values) +``` #### Joining Pandas DataFrame - Experience: before joining (either `concat`, `merge`), need to careful about the *index* of the dataframes (might need to `.reset_index()`) as apart from the joining condition, pandas also matching the index of each dataframe. From bc8365b9582254422de98f0d0ac08a1add90141f Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 5 May 2023 22:26:58 +0800 Subject: [PATCH 038/150] Update daily_knowledge.md --- daily_knowledge.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index c00f8d9..79e5341 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,15 @@ # 2023 ## Day 3 +### Matplotlib +#### Figure +- Figure object is the overall window where everything is drawn. +```Python +def draw_smtg(): + fig = plt.figure(figsize=(10,10)) + plt.plot(...) + + return fig #whatever the graphs in fig will be returned +``` ### Python - Logging level: `DEBUG > INFO > WARNING > ERROR > CRITICAL` - If set `logging.basicConfig(level=logging.ERROR)` means that only log `ERROR` & `CRITICAL` From 99bf8ed85779fc75771d13b621a66eaf8ea1b9c6 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 6 May 2023 09:03:37 +0800 Subject: [PATCH 039/150] Update daily_knowledge.md --- daily_knowledge.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 79e5341..4d3fb6b 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,10 @@ # 2023 ## Day 3 +### VScode +- Multiline editing in Visual Studio Code: + - Mac: `⌥ Opt`+`⌘ Cmd`+`↑/↓` + - Windows: `Shift`+`Alt`+`↑/↓` + ### Matplotlib #### Figure - Figure object is the overall window where everything is drawn. From 71d215fc86d2842fcd062decf0cd5d8129e24431 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 6 May 2023 14:00:35 +0800 Subject: [PATCH 040/150] Update daily_knowledge.md --- daily_knowledge.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 4d3fb6b..c3f1afb 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,16 @@ # 2023 ## Day 3 +### Notebook Env +- Both `!` and `%` allow you to run shell commands from a Jupyter notebook + - Difference: `!` calls out to a shell (in a new process), while `%` affects the process associated with the notebook + - `!cd foo`, by itself, has **no lasting effect**, since the process with the changed directory immediately terminates. + - `%cd foo` changes the current directory of the notebook process, which is a **lasting effect**. + - Example + ```Bash + # in a notebook cell + !git clone https://github.com/full-stack-deep-learning/fsdl-text-recognizer-2021-labs # ! can use for git clone, pip install + %cd fsdl-text-recognizer-2021-labs # % use for cd + ``` ### VScode - Multiline editing in Visual Studio Code: - Mac: `⌥ Opt`+`⌘ Cmd`+`↑/↓` From f639e6264e72a0ecfb866b42963357f568574514 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Wed, 10 May 2023 23:10:20 +0800 Subject: [PATCH 041/150] update logging tutorial --- advanced/class_3_inheritance_composition.py | 3 +++ ...ecorator_tutorial.py => class_4_decorator_tutorial.py} | 0 advanced/logging_tutorial.py | 8 +++++--- daily_knowledge.md | 1 + 4 files changed, 9 insertions(+), 3 deletions(-) create mode 100644 advanced/class_3_inheritance_composition.py rename advanced/{class_3_decorator_tutorial.py => class_4_decorator_tutorial.py} (100%) diff --git a/advanced/class_3_inheritance_composition.py b/advanced/class_3_inheritance_composition.py new file mode 100644 index 0000000..90c6a3b --- /dev/null +++ b/advanced/class_3_inheritance_composition.py @@ -0,0 +1,3 @@ +""" +https://realpython.com/inheritance-composition-python/ +""" diff --git a/advanced/class_3_decorator_tutorial.py b/advanced/class_4_decorator_tutorial.py similarity index 100% rename from advanced/class_3_decorator_tutorial.py rename to advanced/class_4_decorator_tutorial.py diff --git a/advanced/logging_tutorial.py b/advanced/logging_tutorial.py index 56c0109..fb13e16 100644 --- a/advanced/logging_tutorial.py +++ b/advanced/logging_tutorial.py @@ -1,7 +1,8 @@ import logging + def basic_logging() -> None: - logging.basicConfig(level=logging.WARNING) + logging.basicConfig(level=logging.ERROR) logging.debug("This is a debug message.") logging.info("This is an info message.") @@ -9,12 +10,13 @@ def basic_logging() -> None: logging.error("This is an error message.") logging.critical("This is a critical message.") + def format_logging() -> None: logging.basicConfig( level=logging.DEBUG, format="%(asctime)s %(levelname)s %(message)s", datefmt="%Y-%m-%d %H:%M:%S", - #filename="basic.log", log to file + # filename="basic.log", log to file ) logging.debug("This is a debug message.") @@ -26,4 +28,4 @@ def format_logging() -> None: if __name__ == "__main__": basic_logging() - #format_logging() + # format_logging() diff --git a/daily_knowledge.md b/daily_knowledge.md index 5b6e632..3dd63fa 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -9,6 +9,7 @@ plt.rcParams.update({'font.size': 14}) ``` ### Python General + - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. - `assert`: to check if the data is expected (`assert len(x.shape) == 2`) and will raise Exception if not matching. From 9f0ce94c52ffb5c677185eab5fbf464b5f0e835e Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Thu, 11 May 2023 00:02:18 +0800 Subject: [PATCH 042/150] yaml tutorial --- basics/pyaml_tutorial.py | 13 ------- basics/yaml/README.md | 35 +++++++++++++++++++ basics/yaml/data/config.yaml | 25 +++++++++++++ .../data/multiple_docs.yaml} | 0 basics/yaml/pyaml_tutorial.py | 21 +++++++++++ 5 files changed, 81 insertions(+), 13 deletions(-) delete mode 100644 basics/pyaml_tutorial.py create mode 100644 basics/yaml/README.md create mode 100644 basics/yaml/data/config.yaml rename basics/{data/items.yaml => yaml/data/multiple_docs.yaml} (100%) create mode 100644 basics/yaml/pyaml_tutorial.py diff --git a/basics/pyaml_tutorial.py b/basics/pyaml_tutorial.py deleted file mode 100644 index eeefd62..0000000 --- a/basics/pyaml_tutorial.py +++ /dev/null @@ -1,13 +0,0 @@ -# !pip install pyaml -from pathlib import Path - -import yaml - -curr_dir = Path(__file__).resolve().parent -with open(curr_dir / "data/items.yaml", "r") as f: - # load_all: is to load multiple document in a single YAML - docs = yaml.load_all(f, Loader=yaml.FullLoader) - - for doc in docs: - for k, v in doc.items(): - print(k, v) diff --git a/basics/yaml/README.md b/basics/yaml/README.md new file mode 100644 index 0000000..f7b4c2f --- /dev/null +++ b/basics/yaml/README.md @@ -0,0 +1,35 @@ +# YAML + +## Read YAML file + +- `yaml.load_all(file, Loader=yaml.FullLoader)` load multiple yaml docs +- `yaml.safe_load(file)` load the yaml in a safe manner + +## Define YAML + +- List: + +```yaml +item: + - apple + - oragnge + - banana +# {'item': ['apple', 'oragnge', 'banana']} +``` + +### Anchor & Alias + +```yaml +age: &age 22 +# Anchors (&) & Alias (*) +person_a: &person_a + name: Harry Potter + age: *age_anchor + occupation: Software Engineer +person_a_copy: *person_a +person_b: + <<: *person_a # <<: create merging of mapping (put whatever mapping on &person_a) + name: Stacy # overwrite the mapping of &person_a + age: 12 # overwrite the mapping of &person_a + +``` diff --git a/basics/yaml/data/config.yaml b/basics/yaml/data/config.yaml new file mode 100644 index 0000000..573e67d --- /dev/null +++ b/basics/yaml/data/config.yaml @@ -0,0 +1,25 @@ +job_server: + job_name: yaml_tutorial + job_version: "1.0.0" +data_type: + - string_value: "Hello, World" + - int_value: &age_anchor 22 + - float_value: 3.14 + - bool_value: false # true, false, yes, no + - null_value: null +routes: + - path: /api/posts + methods: [GET] + - path: /api/new_post + method: [POST, PUT] +# Anchors (&) & Alias (*) +person_a: &person_a + name: Harry Potter + age: *age_anchor + occupation: Software Engineer +person_a_copy: *person_a +person_b: + <<: *person_a # <<: create merging of mapping (put whatever mapping on &person_a) + name: Stacy # overwrite the mapping of &person_a + age: 12 # overwrite the mapping of &person_a + diff --git a/basics/data/items.yaml b/basics/yaml/data/multiple_docs.yaml similarity index 100% rename from basics/data/items.yaml rename to basics/yaml/data/multiple_docs.yaml diff --git a/basics/yaml/pyaml_tutorial.py b/basics/yaml/pyaml_tutorial.py new file mode 100644 index 0000000..742b97e --- /dev/null +++ b/basics/yaml/pyaml_tutorial.py @@ -0,0 +1,21 @@ +# !pip install pyaml +from pathlib import Path +from pprint import pprint + +import yaml + +curr_dir = Path(__file__).resolve().parent + +with open(curr_dir / "data/config.yaml", "r") as f: + # load_all: is to load multiple document in a single YAML + # safe_load: is to load the config in safe manner + """ + docs = yaml.load_all(f, Loader=yaml.FullLoader) # multiple_docs.yaml + + for doc in docs: + for k, v in doc.items(): + print(k, v) + """ + + config = yaml.safe_load(f) + pprint(config, sort_dicts=False) From 4bbe74f3093f0a3d8ea55176d0be6d8bd58bdec5 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 1 Jun 2023 17:00:41 +0700 Subject: [PATCH 043/150] Update daily_knowledge.md --- daily_knowledge.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 9e75b94..1147a7b 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,4 +1,20 @@ # 2023 +## Day 4 +### Python +- `IPython` debug: when executing `main.py` script in the terminal, we still can insert **ipython** checkpoint at the line we want to debug + - `from IPython import embed; embed()` +- Avoid circular imports + ``` + # __init__.py of utils folder + from .base_logger import * + from .data_loader import * + + def load_yaml() + + # data_loader.py + from utils import load_yaml # this will cause circular import + ``` + - Solution: do not `from .data_loader import *` if a data_loader refer to any functions in `utils.__init__.py` ## Day 3 From a32a616eb4868e7af1bd76913f1d2adf4a63db8b Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 1 Jun 2023 17:00:56 +0700 Subject: [PATCH 044/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 1147a7b..5a6f201 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -14,7 +14,7 @@ # data_loader.py from utils import load_yaml # this will cause circular import ``` - - Solution: do not `from .data_loader import *` if a data_loader refer to any functions in `utils.__init__.py` + - Solution: DO NOT `from .data_loader import *` if a data_loader refer to any functions in `utils.__init__.py` ## Day 3 From 3bc2b7222b9a67148bd504b50e5e2d9a629d2d40 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 9 Jun 2023 22:51:25 +0800 Subject: [PATCH 045/150] Update daily_knowledge.md --- daily_knowledge.md | 41 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 39 insertions(+), 2 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5a6f201..440201e 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -201,11 +201,11 @@ print(next(phones_iter)) "python.terminal.activateEnvironment": true ``` -#### Code Formatter - +### Code Formatter & Linting - The main coding standard for Python is PEP8 (Python Enhancement Proposal 8) - **Linters** such as `flake8` and `pylint` highlight places where your code doesn’t conform with PEP8. - **Automatic formatters** such as `black` that will update your code automatically to conform with coding standards. +### Setup inside VS Code - How to install `flack8`: - Step 1: Install `black` in virtual environment: `pip install flake8` - Step 2: Open the Command Palette (`CMD + Shift + P`) → Search the “Python: Select Linter” and press enter. Select the “flake8” @@ -221,3 +221,40 @@ print(next(phones_iter)) "source.organizeImports": true } ``` +### Setup pre-commit using `git hooks` +This is to ensure the code formatter, linting is running before the commit +- install requirements-dev dependencies + +```sh +# requirements-dev.txt +flake8 +black +mypy +coverage +``` + +- add `hooksPath` into git config core: `git config --local core.hooksPath .git/hooks/` +- `pre-commit` file inside `.git/hooks/` + ```sh + # content inside pre-commit file + echo "Running lint.sh before commit" + bash lint.sh + echo "Linting completed" + ``` + - make pre-commit file executable via `chmod +x .git/hooks//pre-commit` +- Define the content in `lint.sh` + + ```sh + # content inside lint.sh + linting_path="." + echo "-------------Formatter with black-----------------" + black $linting_path --line-length=88 + + echo "-------------Linting with flake8-----------------" + flake8 $linting_path --max-line-length=88 --ignore=E203,W503,E231,E266,E722 + + echo "-------------Type checking with mypy-----------------" + mypy $linting_path --ignore-missing-imports + ``` +### Setup pre-commit using `pre-commit` package +- [Reading](https://medium.com/@anton-k./how-to-set-up-pre-commit-hooks-with-python-2b512290436) From c193a8f0d6d386b0665ca9e164181c72adee557e Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 9 Jun 2023 22:52:56 +0800 Subject: [PATCH 046/150] Update daily_knowledge.md --- daily_knowledge.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 440201e..dbca215 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -201,10 +201,11 @@ print(next(phones_iter)) "python.terminal.activateEnvironment": true ``` -### Code Formatter & Linting +## Code Formatter & Linting - The main coding standard for Python is PEP8 (Python Enhancement Proposal 8) - **Linters** such as `flake8` and `pylint` highlight places where your code doesn’t conform with PEP8. - **Automatic formatters** such as `black` that will update your code automatically to conform with coding standards. + - **Type Checker** `mypy` is a static type checker for Python. Type checkers help ensure that you're using variables and functions in your code correctly. With mypy, add type hints (PEP 484) to your Python programs, and mypy will warn you when you use those types incorrectly. ### Setup inside VS Code - How to install `flack8`: - Step 1: Install `black` in virtual environment: `pip install flake8` From a9078a25619c5ae91dbc6bed900625265ace9b4a Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 9 Jun 2023 22:53:26 +0800 Subject: [PATCH 047/150] Update daily_knowledge.md --- daily_knowledge.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index dbca215..2cde99b 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -191,8 +191,8 @@ print(next(phones_iter)) #### VS Code Shortcuts -- `CMD + Shift + P`: Command Palette -- `CMD + P`: Quickly open files +- `CMD + Shift + P` Command Palette +- `CMD + P` Quickly open files #### Auto Venv Activation From 63923a515662bf41a3b1af7879a6053dc8a59297 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 24 Jun 2023 22:26:27 +0700 Subject: [PATCH 048/150] Create dotvenv.md --- basics/dotvenv.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 basics/dotvenv.md diff --git a/basics/dotvenv.md b/basics/dotvenv.md new file mode 100644 index 0000000..aef373e --- /dev/null +++ b/basics/dotvenv.md @@ -0,0 +1,15 @@ +# `.env` +- Installation: `pip install python-dotenv==1.0.0` +- Config file stores in `.env` file +```shell +HUGGINGFACEHUB_API_TOKEN="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" +``` +- Load environmental variables +```Python +import os +from dotenv import load_dotenv, find_dotenv + +load_dotenv("../config/.env") +# load_dotenv(find_dotenv()) # find_dotenv() is to find the .env +os.environ["HUGGINGFACEHUB_API_TOKEN"] = ... # insert your API_TOKEN here +``` From 6475543c8eedcc13381927569b3bca16c16af1c4 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 24 Jun 2023 22:27:04 +0700 Subject: [PATCH 049/150] Update daily_knowledge.md --- daily_knowledge.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 2cde99b..de7991a 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,4 +1,21 @@ # 2023 +## Day 5 +### `.env` +- Installation: `pip install python-dotenv==1.0.0` +- Config file stores in `.env` file +```shell +HUGGINGFACEHUB_API_TOKEN="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" +``` +- Load environmental variables +```Python +import os +from dotenv import load_dotenv, find_dotenv + +load_dotenv("../config/.env") +# load_dotenv(find_dotenv()) # find_dotenv() is to find the .env +os.environ["HUGGINGFACEHUB_API_TOKEN"] = ... # insert your API_TOKEN here +``` + ## Day 4 ### Python - `IPython` debug: when executing `main.py` script in the terminal, we still can insert **ipython** checkpoint at the line we want to debug From fb61ba971dfae74dab684f7ce4ccec935b60ac5c Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 24 Jun 2023 22:27:41 +0700 Subject: [PATCH 050/150] Update daily_knowledge.md --- daily_knowledge.md | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index de7991a..ea8081a 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,21 +1,4 @@ # 2023 -## Day 5 -### `.env` -- Installation: `pip install python-dotenv==1.0.0` -- Config file stores in `.env` file -```shell -HUGGINGFACEHUB_API_TOKEN="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" -``` -- Load environmental variables -```Python -import os -from dotenv import load_dotenv, find_dotenv - -load_dotenv("../config/.env") -# load_dotenv(find_dotenv()) # find_dotenv() is to find the .env -os.environ["HUGGINGFACEHUB_API_TOKEN"] = ... # insert your API_TOKEN here -``` - ## Day 4 ### Python - `IPython` debug: when executing `main.py` script in the terminal, we still can insert **ipython** checkpoint at the line we want to debug @@ -32,9 +15,23 @@ os.environ["HUGGINGFACEHUB_API_TOKEN"] = ... # insert your API_TOKEN here from utils import load_yaml # this will cause circular import ``` - Solution: DO NOT `from .data_loader import *` if a data_loader refer to any functions in `utils.__init__.py` +### `.env` +- Installation: `pip install python-dotenv==1.0.0` +- Config file stores in `.env` file +```shell +HUGGINGFACEHUB_API_TOKEN="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" +``` +- Load environmental variables +```Python +import os +from dotenv import load_dotenv, find_dotenv -## Day 3 +load_dotenv("../config/.env") +# load_dotenv(find_dotenv()) # find_dotenv() is to find the .env +os.environ["HUGGINGFACEHUB_API_TOKEN"] = ... # insert your API_TOKEN here +``` +## Day 3 ### Notebook Env - Both `!` and `%` allow you to run shell commands from a Jupyter notebook From 3ef88af506cc0eb2d049cbf1f5ef565a56dc160b Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 9 Jul 2023 23:04:29 +0800 Subject: [PATCH 051/150] Update daily_knowledge.md --- daily_knowledge.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index ea8081a..4b88ff4 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -32,8 +32,12 @@ os.environ["HUGGINGFACEHUB_API_TOKEN"] = ... # insert your API_TOKEN here ``` ## Day 3 -### Notebook Env - +### Notebook +- Surpass the warning +```Python +import warnings +warnings.filterwarnings('ignore') +``` - Both `!` and `%` allow you to run shell commands from a Jupyter notebook - Difference: `!` calls out to a shell (in a new process), while `%` affects the process associated with the notebook - `!cd foo`, by itself, has **no lasting effect**, since the process with the changed directory immediately terminates. From 4345404339e1dfbce8dc65be3a29adaa483fb3d0 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Thu, 20 Jul 2023 22:46:51 +0800 Subject: [PATCH 052/150] update pathlib tutorial --- basics/README.md | 8 ++++++++ basics/pathlib_tutorial.py | 8 ++++++++ 2 files changed, 16 insertions(+) create mode 100644 basics/pathlib_tutorial.py diff --git a/basics/README.md b/basics/README.md index c7d43a8..fb31af8 100644 --- a/basics/README.md +++ b/basics/README.md @@ -1,5 +1,13 @@ # Basics Python +## Topics + +- [`*args` and `**kwargs`](./args_kwargs_tutorial.py) +- [Google Colab](./google_colab_tutorial.ipynb) +- [Pathlib](./pathlib_tutorial.py) +- [Subprocess](./subprocess_tutorial.py) +- [YAML](./yaml/README.md) + ## Argument Parser - The `argparse` module will “parse” the “arguments” to the program. diff --git a/basics/pathlib_tutorial.py b/basics/pathlib_tutorial.py new file mode 100644 index 0000000..8af6ea9 --- /dev/null +++ b/basics/pathlib_tutorial.py @@ -0,0 +1,8 @@ +# Get current director +from pathlib import Path + +# need to provide .resolve() before calling parents to go up certain level +data_path = Path("__file__").resolve().parents[1] + +# convert Pathlib to String +data_path = data_path.as_posix() \ No newline at end of file From 7a1a152e409aa46d3bfe377bde7eca078f86a7eb Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Thu, 20 Jul 2023 23:01:59 +0800 Subject: [PATCH 053/150] update linux command --- docs/linux_commands.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index ab76a8f..892e03a 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -1,5 +1,9 @@ # Linux Command +## Day 1 + +- `du -sh` to find the size of the current folder + ## Special Variables ### `$PATH` variable From 648c5fed9890973c4bc9385c37407316e4fa8b46 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 1 Aug 2023 22:21:43 +0800 Subject: [PATCH 054/150] Update daily_knowledge.md --- daily_knowledge.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 4b88ff4..c20f0f6 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -161,9 +161,15 @@ x = tf.ones(shape=(2, 2)) x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. ``` -### Python General +### `sys.path` - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. +- To locate the installation path of the module: `print(module_name.__file__)` +- Python will locate the module based on the path appears first in `sys.path`, so in order to change prioritise the installation packages, we can do as follow: +```Python +import sys +sys.path.insert(0, '/path/to/site-packages') # location of src +``` ### Matplotlib From 698ba2c40a776ad13af328072e283861c4e50ccd Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:14:16 +0800 Subject: [PATCH 055/150] Update linux_commands.md --- docs/linux_commands.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index 892e03a..b3cb5c7 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -17,7 +17,7 @@ /Users/quannguyen/repos/tiny_python_projects/venv/bin:/usr/local/bin:/System/Cryptexes/App/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin:/Library/Apple/usr/bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin:/Applications/Visual Studio Code.app/Contents/Resources/app/bin ``` -### Altering your `$PATH` +#### Altering your `$PATH` - Simply add the path where your program (script) is located to $PATH, You should now be able to execute the script anywhere on your system by just typing in its name, without having to include the full path as you type it. From 4b1a545b2b29083fbc2c5293c26930d6b5dfbe0c Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:16:59 +0800 Subject: [PATCH 056/150] Update linux_commands.md --- docs/linux_commands.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index b3cb5c7..309608f 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -30,7 +30,7 @@ $ which hello.py # /home/quannguyen/bin/hello.py ``` -## Command Linux Commands +## Common Linux Commands - `chmod` make our program “executable” - `+x` add an “executable” attribute to the file From 86d0c84bc0a35ea71285e84f72e87139e6a22aec Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:22:34 +0800 Subject: [PATCH 057/150] Update linux_commands.md --- docs/linux_commands.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index 309608f..3f24e5a 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -31,7 +31,7 @@ $ which hello.py # /home/quannguyen/bin/hello.py ``` ## Common Linux Commands - +### `chmod` - `chmod` make our program “executable” - `+x` add an “executable” attribute to the file @@ -41,7 +41,7 @@ chmod +x hello.py # +x will add an “executable” attribute to the file # Now can run the program like ./hello.py ``` - +### `echo` - `echo` to print ```bash @@ -50,12 +50,18 @@ echo $USER echo $HOME # /Users/quannguyen ``` - +### `env` - `env` is the env program will tell you about your “environment.” - If you run `env` on your computer, you should see your login name and your home directory. - use the `env ` command to find and run programs, say if we type`env python3`, the env program is looking for python3 in the environment. If Python has not been installed, it won’t be able to find it, but it’s also possible that Python has been installed more than once. - +```bash +➜ ~ env python3 +Python 3.11.3 (v3.11.3:f3909b8bc8, Apr 4 2023, 20:12:10) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> +``` +### `which` - `which` to see where the program is installed ```bash From def2b2492408b55f7a2356c9dce73488b62f3ce6 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:23:21 +0800 Subject: [PATCH 058/150] Update linux_commands.md --- docs/linux_commands.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index 3f24e5a..ab344b4 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -1,9 +1,5 @@ # Linux Command -## Day 1 - -- `du -sh` to find the size of the current folder - ## Special Variables ### `$PATH` variable @@ -70,3 +66,7 @@ which env which python3 # /usr/local/bin/python3 ``` +## Daily Knowledge +### Day 1 + +- `du -sh` to find the size of the current folder From 584a057bb0edfb12c45936818761d24362ec203a Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:24:50 +0800 Subject: [PATCH 059/150] Update linux_commands.md --- docs/linux_commands.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index ab344b4..3237a28 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -7,6 +7,7 @@ - Windows, macOS, and Linux all have a `$PATH` variable, which is a list of directories the OS will look in to find a program (using the `env` program) - The `$PATH` variable is a way of telling your computer to only look in places where executable programs can be found. - The directories are separated by colons (`:`). Notice that the directory where **python3** lives is the first one in `$PATH` + - The `$PATH` is located at `~/.bashrc` user's file or or `~/.zshrc` ```bash echo $PATH From 700675e0b73d794772b9bfe4a06d01f4e13d1875 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:37:32 +0800 Subject: [PATCH 060/150] Update linux_commands.md --- docs/linux_commands.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index 3237a28..7b114f8 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -58,6 +58,12 @@ Python 3.11.3 (v3.11.3:f3909b8bc8, Apr 4 2023, 20:12:10) [Clang 13.0.0 (clang-1 Type "help", "copyright", "credits" or "license" for more information. >>> ``` +### `export` +- `export` command sets an environment variable named **key** to the **value** +```bash +# This command sets an environment variable named AWS_DEFAULT_PROFILE to the value quannguyen. +export AWS_DEFAULT_PROFILE=quannguyen +``` ### `which` - `which` to see where the program is installed From cf6a9bf57fbac6a4eb823808af5bbe9f11bfe566 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:43:17 +0800 Subject: [PATCH 061/150] Update linux_commands.md --- docs/linux_commands.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index 7b114f8..1e9f654 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -64,6 +64,18 @@ Type "help", "copyright", "credits" or "license" for more information. # This command sets an environment variable named AWS_DEFAULT_PROFILE to the value quannguyen. export AWS_DEFAULT_PROFILE=quannguyen ``` +- To persist the environment variable so that it remains available even after you close the terminal, you can add the `export` command to + - If using Bash terinmal, Bash profile file (`~/.bashrc` or `~/.bash_profile`) + - If using Zsh terminal, Zsh configuration file (`~/.zshrc`) +```bash +# Open & add the following line at the end of the ~/.bashrc or ~/.zshrc file +export AWS_DEFAULT_PROFILE=quannguyen + +# Save the file and exit the text editor. To apply the changes, either open a new terminal session or run the following command to reload the profile: +source ~/.bashrc +source ~/.zshrc +``` + ### `which` - `which` to see where the program is installed From 61140eda46a5d00134462e76908860fe7c26599a Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:45:11 +0800 Subject: [PATCH 062/150] Update linux_commands.md --- docs/linux_commands.md | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index 1e9f654..74b3c1f 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -47,17 +47,7 @@ echo $USER echo $HOME # /Users/quannguyen ``` -### `env` -- `env` is the env program will tell you about your “environment.” - - If you run `env` on your computer, you should see your login name and your home directory. - - use the `env ` command to find and run programs, say if we type`env python3`, the env program is looking for python3 in the environment. If Python has not been installed, it won’t be able to find it, but it’s also possible that Python has been installed more than once. -```bash -➜ ~ env python3 -Python 3.11.3 (v3.11.3:f3909b8bc8, Apr 4 2023, 20:12:10) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin -Type "help", "copyright", "credits" or "license" for more information. ->>> -``` ### `export` - `export` command sets an environment variable named **key** to the **value** ```bash @@ -76,6 +66,30 @@ source ~/.bashrc source ~/.zshrc ``` +### `env` +- `env` is the env program will tell you about your “environment.” + + - If you run `env` on your computer, you should see your login name and your home directory. + - use the `env ` command to find and run programs, say if we type`env python3`, the env program is looking for python3 in the environment. If Python has not been installed, it won’t be able to find it, but it’s also possible that Python has been installed more than once. +```bash +➜ ~ env python3 +Python 3.11.3 (v3.11.3:f3909b8bc8, Apr 4 2023, 20:12:10) [Clang 13.0.0 (clang-1300.0.29.30)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> +``` + +### shebang `#!` + +- It’s common to put a special comment line in programs like `#!/usr/bin/env python3` these to indicate which language needs to be used to execute the commands in the file. +- Below is the shebang you should add at the beginning of the file + +``` +#!/usr/bin/env python3 +``` + +- The shebang line tells the operating system to use the `env` program (located at `/usr/bin/env`) to find the **python3** that is specific to the machine on which it’s running. + + ### `which` - `which` to see where the program is installed From 7537020a02e3507fc2b634efea9a28eb93e367c1 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 5 Aug 2023 17:50:26 +0800 Subject: [PATCH 063/150] Update linux_commands.md --- docs/linux_commands.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/linux_commands.md b/docs/linux_commands.md index 74b3c1f..8048a1c 100644 --- a/docs/linux_commands.md +++ b/docs/linux_commands.md @@ -103,3 +103,7 @@ which python3 ### Day 1 - `du -sh` to find the size of the current folder +- `/dev/null1 file` which is a special device file that discards all data written to it + - `tail -f /dev/null` to keep a terminal session open but don't need any active process running in the background. +- `top` provides real-time monitoring of system resources and processes, to list down PID of each process + - `kill -9 1234` command isforcefully terminates the process, with **PID=1234** immediately, without giving it a chance to clean up or save any unsaved data. From 2190a1680653794717a3df973f69b94c5b529d52 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 18 Aug 2023 23:05:33 +0800 Subject: [PATCH 064/150] Update daily_knowledge.md --- daily_knowledge.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index c20f0f6..b0e13e4 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,7 @@ # 2023 ## Day 4 +### Pandas +- `df.loc[:, "col"] = df.col.map(mapping)` re-assign the updated value to originial column without any error ### Python - `IPython` debug: when executing `main.py` script in the terminal, we still can insert **ipython** checkpoint at the line we want to debug - `from IPython import embed; embed()` @@ -95,7 +97,7 @@ model = joblib.load('lgbm_mode.pkl') ### Pandas -- `to_csv` to prevent `nnamed: 0` column to be appended along with your original df by set `df.to_csv(, index=False)` +- `to_csv` to prevent `nnamed: 0` column to be appended along with your original df by set `df.to_csv('result.csv', index=False)` - `.apply` based on the condition of certain columns ```Python From 20772950cabde7defbf76ab72103b0999d4fa4ab Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 18 Aug 2023 23:44:15 +0800 Subject: [PATCH 065/150] Update daily_knowledge.md --- daily_knowledge.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index b0e13e4..7b14014 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -2,6 +2,16 @@ ## Day 4 ### Pandas - `df.loc[:, "col"] = df.col.map(mapping)` re-assign the updated value to originial column without any error +#### `groupby` +- create a new column by using the transform `function` of pandas along with `groupby` +```Python +# Group by col_1, count by col_2, and then count +df.groupby(["col_1"])["col_2"].count() + +# Group by col_1, count by col_2, and then count +# Create a new column with count values by using transform +df.groupby(["col_1"])["col_2"].transform("count") +``` ### Python - `IPython` debug: when executing `main.py` script in the terminal, we still can insert **ipython** checkpoint at the line we want to debug - `from IPython import embed; embed()` From 277fead612d4f689c1288f2c31019bb740860405 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 2 Sep 2023 17:31:14 +0700 Subject: [PATCH 066/150] Update daily_knowledge.md --- daily_knowledge.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 7b14014..8283510 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,7 +1,16 @@ # 2023 ## Day 4 +### Numpy +- Numpy 's `np.nan` vs Python 's `None` object + - In Numpy, a `np.nan` value is a native floating-point type array. + - When you try to do some arithmetic operations will `np.nan`, the result will always be `np.nan`. + - Fortunately, Numpy provides some special aggregation methods that can ignore the existence of `np.nan` value such as `np.nansum(arr)` + - `None` is a Python Object called **NoneType** + - Pandas automatically converts the `None` to a `np.nan` value. + - If you try to aggregate over this array, you will get an error because of the NoneType. ### Pandas -- `df.loc[:, "col"] = df.col.map(mapping)` re-assign the updated value to originial column without any error +- `df.loc[:, "col"] = df["col"].map(mapping)` re-assign the updated value to originial column without any error +- `pd.set_option('max_columns', 200)` to view all the columns in the df when `df.head()` #### `groupby` - create a new column by using the transform `function` of pandas along with `groupby` ```Python From 6bc4e20d6a8b83191d2f4f0bc93bf491f2599d3f Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 3 Sep 2023 11:15:31 +0700 Subject: [PATCH 067/150] Update daily_knowledge.md --- daily_knowledge.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 8283510..b5db0e2 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,4 +1,17 @@ # 2023 +## Day 5 +### Pandas +#### Check & Remove Duplicates +- `df.duplicated()` to check if there are any row duplicate. This will return `True` for the 2nd occurence of the duplicate + - `df.duplicated(subset=['col_A','col_B','col_C'])` in case there is no entire row duplciate, we can check duplicates for only subsets of columns +- `df.query("make == 'bmw' and model == '1_series' and year == 2013 and price == 31500")` using query to identify & view the duplicated rows +- Remove the duplicates + - `.reset_index(drop=True)` to reset the index after dropping the duplicates + - `.copy()` to make the deep copy of the dataframe +```Python + `df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ + .reset_index(drop=True).copy() +``` ## Day 4 ### Numpy - Numpy 's `np.nan` vs Python 's `None` object From 16b8988a2252d333e609dcf6ee51c1fd27ec59a9 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 3 Sep 2023 11:15:51 +0700 Subject: [PATCH 068/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index b5db0e2..9a5d008 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -9,7 +9,7 @@ - `.reset_index(drop=True)` to reset the index after dropping the duplicates - `.copy()` to make the deep copy of the dataframe ```Python - `df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ +df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ .reset_index(drop=True).copy() ``` ## Day 4 From b9cf35f462f0fd71dadc7d7962cf7473bc8a18f2 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 6 Sep 2023 23:20:53 +0700 Subject: [PATCH 069/150] Update daily_knowledge.md --- daily_knowledge.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 9a5d008..a016a7e 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -12,6 +12,21 @@ df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ .reset_index(drop=True).copy() ``` +### Matplotlib +- You can set matplotlib object to ax variable +```Python +# case 1: plot via pandas dataframe +ax = df['year'].value_counts() \ + .head(10) \ + .plot(kind='bar', title='Top 10 Years Coasters Introduced') +ax.set_xlabel('year') +ax.set_ylabel('count') + +# case 2: plot via seaborn +ax = sns.countplot(data=df, x='year') +ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=90, ha='center') +``` + ## Day 4 ### Numpy - Numpy 's `np.nan` vs Python 's `None` object From ebbcffb9506746fa5d94d0f43046d8dbc4d0edbc Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 6 Sep 2023 23:23:35 +0700 Subject: [PATCH 070/150] Update daily_knowledge.md --- daily_knowledge.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index a016a7e..5592337 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -15,18 +15,25 @@ df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ ### Matplotlib - You can set matplotlib object to ax variable ```Python -# case 1: plot via pandas dataframe +# case 1: get ax from the plot via pandas dataframe ax = df['year'].value_counts() \ .head(10) \ .plot(kind='bar', title='Top 10 Years Coasters Introduced') ax.set_xlabel('year') ax.set_ylabel('count') -# case 2: plot via seaborn +# case 2: get ax from the plot via seaborn ax = sns.countplot(data=df, x='year') ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=90, ha='center') ``` +- Rotate the xticks label +```Python +# rotate via plt +plt.xticks(rotation=90) +# rotate via ax +ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=45, ha='right') +``` ## Day 4 ### Numpy - Numpy 's `np.nan` vs Python 's `None` object From 0b4683f8a22ebada52f47f8bfece741ea91c1031 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 11 Sep 2023 21:29:15 +0700 Subject: [PATCH 071/150] Update daily_knowledge.md --- daily_knowledge.md | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5592337..bae69b9 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,31 @@ # 2023 ## Day 5 +### Python +- `yield` keyword is used in the context of defining generator functions. + - When a generator function is called, it doesn't execute the function immediately. + - Instead, it returns a generator object that can be used to control the execution of the function. + - The code inside the generator function is executed only when an item is requested from the generator using the `next()` function or a `for` loop. + +```Python +def simple_generator(): + yield 1 + yield 2 + yield 3 + +# Create a generator object +gen = simple_generator() + +# using next() to access the code inside +print(next(gen)) # 1 +print(next(gen)) # 2 +print(next(gen)) # 3 +print(next(gen)) # StopIteration raised + +# using for-loop to iterate through the generator +for value in simple_generator(): + print(value) + +``` ### Pandas #### Check & Remove Duplicates - `df.duplicated()` to check if there are any row duplicate. This will return `True` for the 2nd occurence of the duplicate From ec77dac071a9f96f951a74451e40685917a10ce9 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 13 Sep 2023 17:47:58 +0700 Subject: [PATCH 072/150] Update daily_knowledge.md --- daily_knowledge.md | 1 + 1 file changed, 1 insertion(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index bae69b9..b496dd7 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -321,6 +321,7 @@ print(next(phones_iter)) - Step 2: Open the Command Palette (`CMD + Shift + P`) → “Preferences → Settings” - Search “format on save” and check the checkbox - Search “python formatting provider” and select the `black`. + - NOTE: can run black seperately `black -l 80 --preview src/youtube_statistics.py` - How to install `isort`: - Open the Command Palette (`CMD + Shift + P`). Search the “Preferences: Open User Settings (JSON)” and press enter. It will open the “settings.json” and add the follow code into that: ```json From c87cde33ffd75e5098a041ca6718279c4da623ff Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 13 Sep 2023 22:20:47 +0700 Subject: [PATCH 073/150] Create class_41_property_decorator_tutorial.md --- .../class_41_property_decorator_tutorial.md | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 advanced/class_41_property_decorator_tutorial.md diff --git a/advanced/class_41_property_decorator_tutorial.md b/advanced/class_41_property_decorator_tutorial.md new file mode 100644 index 0000000..f26be91 --- /dev/null +++ b/advanced/class_41_property_decorator_tutorial.md @@ -0,0 +1,28 @@ +# `property()` Add Managed Attributes to Your Classes +- Data Validation: One of the most common use cases of `property()` is building managed attributes that validate the input data before storing or even accepting it as a secure input. +```Python + # point.py + +class Point: + def __init__(self, x): + self.x = x + @property + def x(self): + return self._x + + @x.setter + def x(self, value): + try: + self._x = float(value) + print("Validated!") + except ValueError: + raise ValueError('"x" must be a number') from None + +pt = Point("none", 2) # -> ValueError: "x" must be a number +pt = Point(12) +# Validated! +pt.x = 4 +# Validated! +point.x = "one" # -> ValueError: "x" must be a number + +``` From 1b7994d2e65f43466d3d584f1a07715f94c1ef60 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 13 Sep 2023 22:22:25 +0700 Subject: [PATCH 074/150] Update class_41_property_decorator_tutorial.md --- advanced/class_41_property_decorator_tutorial.md | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/advanced/class_41_property_decorator_tutorial.md b/advanced/class_41_property_decorator_tutorial.md index f26be91..0897560 100644 --- a/advanced/class_41_property_decorator_tutorial.md +++ b/advanced/class_41_property_decorator_tutorial.md @@ -1,5 +1,5 @@ # `property()` Add Managed Attributes to Your Classes -- Data Validation: One of the most common use cases of `property()` is building managed attributes that validate the input data before storing or even accepting it as a secure input. +- **Data Validation**: One of the most common use cases of `property()` is building managed attributes that validate the input data before storing or even accepting it as a secure input. ```Python # point.py @@ -26,3 +26,14 @@ pt.x = 4 point.x = "one" # -> ValueError: "x" must be a number ``` +- **Providing Computed Attributes** +```Python +class Rectangle: + def __init__(self, width, height): + self.width = width + self.height = height + + @property + def area(self): + return self.width * self.height +``` From 60ac99e492ca1301e43c26d5ecd727ccec333fb4 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 18 Sep 2023 13:32:24 +0700 Subject: [PATCH 075/150] Update daily_knowledge.md --- daily_knowledge.md | 1 + 1 file changed, 1 insertion(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index b496dd7..392d0d6 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -39,6 +39,7 @@ df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ .reset_index(drop=True).copy() ``` ### Matplotlib +- Style: `plt.style.use('fivethirtyeight') # set at the front of the notebook` - You can set matplotlib object to ax variable ```Python # case 1: get ax from the plot via pandas dataframe From 719214050abb2e86101aee2682f3118f03dff4ed Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 18 Sep 2023 13:32:44 +0700 Subject: [PATCH 076/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 392d0d6..2a0755a 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -39,7 +39,7 @@ df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ .reset_index(drop=True).copy() ``` ### Matplotlib -- Style: `plt.style.use('fivethirtyeight') # set at the front of the notebook` +- Style the plot `plt.style.use('fivethirtyeight') # set at the front of the notebook` - You can set matplotlib object to ax variable ```Python # case 1: get ax from the plot via pandas dataframe From 6e15661e24741956ec85bf17e654465dda511d35 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 18 Sep 2023 14:42:01 +0700 Subject: [PATCH 077/150] Update daily_knowledge.md --- daily_knowledge.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 2a0755a..4749b06 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -39,7 +39,7 @@ df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ .reset_index(drop=True).copy() ``` ### Matplotlib -- Style the plot `plt.style.use('fivethirtyeight') # set at the front of the notebook` + - You can set matplotlib object to ax variable ```Python # case 1: get ax from the plot via pandas dataframe @@ -177,7 +177,7 @@ model = joblib.load('lgbm_mode.pkl') ## Day 2 ### Pandas - +- `df = pd.read_csv('example.csv',index_col=[0], parse_dates=[0])` to set the col loc=0 as the index, and parsed as date time type - `to_csv` to prevent `nnamed: 0` column to be appended along with your original df by set `df.to_csv('result.csv', index=False)` - `.apply` based on the condition of certain columns @@ -258,7 +258,7 @@ sys.path.insert(0, '/path/to/site-packages') # location of src - Set params: `plt.rcParams.update({'font.size': 14})` - Set vertical axis range: `ax.set_ylim([0,1])` or `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` - +- Set the style of the plot `plt.style.use('fivethirtyeight') # set at the front of the notebook` #### Subplots - Enable subplots share the same axis with `sharex` or `sharey`: `plt.subplots(nrows=3, sharey=True)` From 5451154aec1db1c84e30f47f49256d042572f950 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 18 Sep 2023 15:30:55 +0700 Subject: [PATCH 078/150] Update daily_knowledge.md --- daily_knowledge.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 4749b06..5021ffa 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,25 @@ # 2023 ## Day 5 +### Seaborn +#### Pairplot +- Pairplot is to use scatterplot() for each pairing of the variables and histplot() for the marginal plots along the diagonal +- Customise with `x_var` and `y_var` and `hue` +```Python +sns.pairplot(df.dropna(), + hue='hour', + x_vars=['hour','dayofweek', + 'year','weekofyear'], + y_vars='PJME_MW', + height=5, + plot_kws={'alpha':0.15, 'linewidth':1.5} + ) +plt.suptitle('Power Use MW by Hour, Day of Week, Year and Week of Year') +plt.show() +``` + +

+ + ### Python - `yield` keyword is used in the context of defining generator functions. - When a generator function is called, it doesn't execute the function immediately. From 98359fcd6e49759e33a7eb7feeb84dd5f20e5b59 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 18 Sep 2023 15:32:29 +0700 Subject: [PATCH 079/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5021ffa..659e248 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -2,7 +2,7 @@ ## Day 5 ### Seaborn #### Pairplot -- Pairplot is to use scatterplot() for each pairing of the variables and histplot() for the marginal plots along the diagonal +- Pairplot is to use `scatterplot()` for each pairing of the variables and `histplot()` for the marginal plots along the diagonal - Customise with `x_var` and `y_var` and `hue` ```Python sns.pairplot(df.dropna(), From fbc851a5d3efd78d135d0965b1e1a9faf5749294 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Mon, 18 Sep 2023 16:55:59 +0700 Subject: [PATCH 080/150] Update daily_knowledge.md --- daily_knowledge.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 659e248..26d930c 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -47,6 +47,13 @@ for value in simple_generator(): ``` ### Pandas +#### `df.query` +- Can set multiple condition: `df.query("make == 'bmw' and model == '1_series')` +- Can query using a list +```Python +holiday_list = ['2021-01-01', '2022-09-02'] +df.query('datetime_col in @holiday_list') +``` #### Check & Remove Duplicates - `df.duplicated()` to check if there are any row duplicate. This will return `True` for the 2nd occurence of the duplicate - `df.duplicated(subset=['col_A','col_B','col_C'])` in case there is no entire row duplciate, we can check duplicates for only subsets of columns From 98279855a73367149f707b88b0cb978c796d0308 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 19 Sep 2023 08:58:47 +0700 Subject: [PATCH 081/150] Update daily_knowledge.md --- daily_knowledge.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 26d930c..cee11b3 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -67,12 +67,17 @@ df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ ``` ### Matplotlib -- You can set matplotlib object to ax variable +- You can set matplotlib object to `ax` variable + - You also can continue to plot on the same graph with `ax` variable ```Python # case 1: get ax from the plot via pandas dataframe ax = df['year'].value_counts() \ .head(10) \ .plot(kind='bar', title='Top 10 Years Coasters Introduced') + +# case 1.1: also can continue to plot on the same graph with ax variable +df.query('year < 2023').plot(style='.', ax=ax) + ax.set_xlabel('year') ax.set_ylabel('count') From 6c44d6cea76372098f7ea1ee25060f5952b319a1 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 19 Sep 2023 10:16:57 +0700 Subject: [PATCH 082/150] Update daily_knowledge.md --- daily_knowledge.md | 1 + 1 file changed, 1 insertion(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index cee11b3..6a20c4e 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,6 +1,7 @@ # 2023 ## Day 5 ### Seaborn +- To get color palatte `color_pal = sns.color_palette()` #### Pairplot - Pairplot is to use `scatterplot()` for each pairing of the variables and `histplot()` for the marginal plots along the diagonal - Customise with `x_var` and `y_var` and `hue` From 28900343ab7965f3a3a98e31613bdbc93aac0950 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 23 Sep 2023 22:37:53 +0700 Subject: [PATCH 083/150] Update daily_knowledge.md --- daily_knowledge.md | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 6a20c4e..324b532 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,4 +1,8 @@ # 2023 +## Day 6 +### Holidays package +- Pandas's holiday package: `pandas.tseries.holiday` +- `holidays` package ## Day 5 ### Seaborn - To get color palatte `color_pal = sns.color_palette()` @@ -48,6 +52,15 @@ for value in simple_generator(): ``` ### Pandas +### Time-series +- Convert the datetime index to a datetime col: `df['date'] = df.index.date` +- Slicing using 1 date by including `23:59:59` +```Python +end_train = '1980-01-01 23:59:59' +# including 23:59:59 means +data_train = df.loc[:end_train] # ends at 1980-01-01 +data_test = df.loc[end_train:] # start at 1980-01-02 +``` #### `df.query` - Can set multiple condition: `df.query("make == 'bmw' and model == '1_series')` - Can query using a list @@ -290,8 +303,11 @@ sys.path.insert(0, '/path/to/site-packages') # location of src ### Matplotlib - Set params: `plt.rcParams.update({'font.size': 14})` -- Set vertical axis range: `ax.set_ylim([0,1])` or `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` - Set the style of the plot `plt.style.use('fivethirtyeight') # set at the front of the notebook` + - Other styles: `seaborn-v0_8-darkgrid` +#### Ax +- Set vertical axis range: `ax.set_ylim([0,1])` or `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` +- Set horizontal axis range: #### Subplots - Enable subplots share the same axis with `sharex` or `sharey`: `plt.subplots(nrows=3, sharey=True)` From 6484b58b5757fc21d5285dd3e6992edf133a4c0a Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 27 Sep 2023 22:46:50 +0800 Subject: [PATCH 084/150] Update README.md --- advanced/README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/advanced/README.md b/advanced/README.md index e7da24f..5b6c819 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -1,5 +1,8 @@ # Advanced Python +## Topics +- [Type Hints](./type-hints.md) + ## Class ### Encapsulation From 2ba2dcc051f05d90ec2d02b099e7569af6a20aea Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 27 Sep 2023 22:47:14 +0800 Subject: [PATCH 085/150] Update README.md --- advanced/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/advanced/README.md b/advanced/README.md index 5b6c819..f1de9cb 100644 --- a/advanced/README.md +++ b/advanced/README.md @@ -1,7 +1,7 @@ # Advanced Python ## Topics -- [Type Hints](./type-hints.md) +- [Type Hints](./type_hints.md) ## Class From bf33e26370227355cda767d6b720a30bf608c68d Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 27 Sep 2023 22:50:26 +0800 Subject: [PATCH 086/150] Create type_hints.md --- advanced/type_hints.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 advanced/type_hints.md diff --git a/advanced/type_hints.md b/advanced/type_hints.md new file mode 100644 index 0000000..c38abe1 --- /dev/null +++ b/advanced/type_hints.md @@ -0,0 +1,14 @@ +# Type Hints + +## `mypy` Static Type Checker +- `mypy` is a static type checker for Python. It allows us to check our code for common type errors before we actually run anything. + +```Python +def main(name: str) -> str: + return 'Hello ' + name +if __name__=='__main__': + main('John') +# ------- +# mypy program.py +# >> Success: no issues found in 1 source file +``` From 9013abaa9b074a5ca650616e19aa09da596f0252 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 27 Sep 2023 23:00:14 +0800 Subject: [PATCH 087/150] Update type_hints.md --- advanced/type_hints.md | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/advanced/type_hints.md b/advanced/type_hints.md index c38abe1..8fae4d2 100644 --- a/advanced/type_hints.md +++ b/advanced/type_hints.md @@ -1,8 +1,30 @@ # Type Hints +## Common Types +### `Optional` +```Python +from typing import Optional + +Params = dict[str, dict[str, float]] +Descriptions = dict[str, str] +def foo(x: Params) -> Optional[Descriptions]: + pass +``` +### `Callable` +- `Callable` represents something that can be called (e.g. a function) that takes input arguments and returns an output type: +```Python +from typing import Callable +# func varibale is Callable that takes two integer arguments and returns an float +def apply_func(a: int, b: int, func: Callable[[int, int], float]) -> int: + return func(a, b) + +def divide_func(a: int, b: int) -> float: + return a/b +apply_func(1,2, divide_func) +``` ## `mypy` Static Type Checker - `mypy` is a static type checker for Python. It allows us to check our code for common type errors before we actually run anything. - + - Installation: `pip install mypy` ```Python def main(name: str) -> str: return 'Hello ' + name From 1ed80e1ea273c6a4f5f799d0664a7e6580bbe68c Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 27 Sep 2023 23:00:27 +0800 Subject: [PATCH 088/150] Update type_hints.md --- advanced/type_hints.md | 1 + 1 file changed, 1 insertion(+) diff --git a/advanced/type_hints.md b/advanced/type_hints.md index 8fae4d2..5d0fde9 100644 --- a/advanced/type_hints.md +++ b/advanced/type_hints.md @@ -20,6 +20,7 @@ def apply_func(a: int, b: int, func: Callable[[int, int], float]) -> int: def divide_func(a: int, b: int) -> float: return a/b + apply_func(1,2, divide_func) ``` ## `mypy` Static Type Checker From d9533f429a876d3a6a862a9b23cfa70c6c689e7a Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 27 Sep 2023 23:05:16 +0800 Subject: [PATCH 089/150] Update type_hints.md --- advanced/type_hints.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/advanced/type_hints.md b/advanced/type_hints.md index 5d0fde9..2fb6f60 100644 --- a/advanced/type_hints.md +++ b/advanced/type_hints.md @@ -1,5 +1,19 @@ # Type Hints ## Common Types +```Python +from typing import List, Dict, Tuple +def square_func(arr: List[float]) -> List[float]: + return [x ** 2 for x in arr] +print(square_func([1, 2, 3])) # 1, 4, 9 +``` +### `Union` +```Python +from typing import Union +# cache_dir variable either type str or Path +def filename_to_url(filename: str, cache_dir: Union[str, Path] = None) -> Tuple[str, str]: + pass + +``` ### `Optional` ```Python from typing import Optional From d29550def7f80e274d78e14a91aac364eb5eff63 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 28 Sep 2023 22:37:32 +0800 Subject: [PATCH 090/150] Update daily_knowledge.md --- daily_knowledge.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 324b532..fe5b607 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -3,6 +3,9 @@ ### Holidays package - Pandas's holiday package: `pandas.tseries.holiday` - `holidays` package +### Code Refactor +- Instead of `if '.yml' in file_path or '.yaml' in file_path` we can do as follows: + - Solution: `if any(ext in file_path for ext in ['.yml', '.yaml']` ## Day 5 ### Seaborn - To get color palatte `color_pal = sns.color_palette()` From 75be9182ee4e4659db8f5a6bbc9e26d0dcdaa199 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 28 Sep 2023 22:46:07 +0800 Subject: [PATCH 091/150] Update README.md --- basics/yaml/README.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/basics/yaml/README.md b/basics/yaml/README.md index f7b4c2f..1bf683d 100644 --- a/basics/yaml/README.md +++ b/basics/yaml/README.md @@ -1,9 +1,25 @@ # YAML ## Read YAML file +### PyYAML +- Install: `pip install pyyaml` - `yaml.load_all(file, Loader=yaml.FullLoader)` load multiple yaml docs - `yaml.safe_load(file)` load the yaml in a safe manner +### `ruamel.yaml` +- Install: `pip install ruamel.yaml` +- `typ='safe'` to achieve `safe_load()` +```Python +from ruamel.yaml import YAML + +yaml=YAML(typ='safe') # default, if not specfied, is 'rt' (round-trip) +yaml.load(doc) + +# set identation +yaml = YAML() +yaml.indent(mapping=4, sequence=6, offset=3) +yaml.load(doc) +``` ## Define YAML From ffab7404ff5e39833fb96e1d4d88607c6d19a0b9 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 28 Sep 2023 22:46:22 +0800 Subject: [PATCH 092/150] Update README.md --- basics/yaml/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/basics/yaml/README.md b/basics/yaml/README.md index 1bf683d..dbc91f5 100644 --- a/basics/yaml/README.md +++ b/basics/yaml/README.md @@ -3,7 +3,6 @@ ## Read YAML file ### PyYAML - Install: `pip install pyyaml` - - `yaml.load_all(file, Loader=yaml.FullLoader)` load multiple yaml docs - `yaml.safe_load(file)` load the yaml in a safe manner ### `ruamel.yaml` From 15714690a4194f5f5bb2eca8512e5370d02473cb Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 28 Sep 2023 22:48:52 +0800 Subject: [PATCH 093/150] Update pathlib_tutorial.py --- basics/pathlib_tutorial.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/basics/pathlib_tutorial.py b/basics/pathlib_tutorial.py index 8af6ea9..e8cbca2 100644 --- a/basics/pathlib_tutorial.py +++ b/basics/pathlib_tutorial.py @@ -5,4 +5,10 @@ data_path = Path("__file__").resolve().parents[1] # convert Pathlib to String -data_path = data_path.as_posix() \ No newline at end of file +data_path_str = data_path.as_posix() + +# to create a folder if it is not exist +folder_path = Path('/this/is/the/new/folder') +# parents=True -> will create if parent folder is not existed +# exist_ok=True -> to ignore the warning if the parent folder is already existed +folder_path.mkdir(parents=True, exist_ok=True) From 6815ccbcdad5de9e1f519c746443539c0fc4d260 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Thu, 28 Sep 2023 22:58:00 +0800 Subject: [PATCH 094/150] Update daily_knowledge.md --- daily_knowledge.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index fe5b607..d20e947 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -55,6 +55,9 @@ for value in simple_generator(): ``` ### Pandas +### Select columns based on Dtype +- Numerical columns: `num_cols = df.select_dtypes(include=np.number).columns.tolist()` +- Categorical columns: `cat_cols = df.select_dtypes(exclude=np.number).columns.tolist()` ### Time-series - Convert the datetime index to a datetime col: `df['date'] = df.index.date` - Slicing using 1 date by including `23:59:59` From adf44c8145a2d7e23ed97331fba1a038c3bb84aa Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 1 Oct 2023 16:55:03 +0800 Subject: [PATCH 095/150] Update daily_knowledge.md --- daily_knowledge.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index d20e947..bf4f170 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,26 @@ # 2023 ## Day 6 +### Numpy +- Stacking columns/rows +```Python +a = np.array((1,2,3)) +b = np.array((2,3,4)) +# column stack +np.column_stack((a,b)) +# array([[1, 2], +# [2, 3], +# [3, 4]]) + +# row_stack or vstack +np.row_stack((a,b)) +np.vstack((a,b)) +# array([[1, 2, 3], +# [2, 3, 4]]) + +# hstack +np.hstack((a,b)) +# array([1, 2, 3, 2, 3, 4]) +``` ### Holidays package - Pandas's holiday package: `pandas.tseries.holiday` - `holidays` package From f25b1343a285d7b017c0d7980c15c71042ad71f6 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sun, 1 Oct 2023 16:56:02 +0800 Subject: [PATCH 096/150] Update daily_knowledge.md --- daily_knowledge.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index bf4f170..89f497a 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -2,6 +2,8 @@ ## Day 6 ### Numpy - Stacking columns/rows + - `np.column_stack` & `np.row_stack` + - `np.hstack` & `np.vstack` ```Python a = np.array((1,2,3)) b = np.array((2,3,4)) From 9ecbe27a9447e6ba3767f5e0641c961e7f03e3d7 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 4 Oct 2023 00:05:53 +0800 Subject: [PATCH 097/150] Update daily_knowledge.md --- daily_knowledge.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 89f497a..0652a8d 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,7 @@ # 2023 ## Day 6 +### Matplotlib +- Plot horizontal line: `{plt, ax}.axhline(y=0.5, color='r', linestyle='-')` ### Numpy - Stacking columns/rows - `np.column_stack` & `np.row_stack` From 079649e54ca811800907e0c6c062eaa23894b2bf Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Wed, 18 Oct 2023 00:37:07 +0800 Subject: [PATCH 098/150] update decorator tutorials --- advanced/decorators_tutorial.ipynb | 537 +++++++++++++++++++++++++++++ advanced/decorators_tutorial.py | 86 ----- requirements.txt | 1 + 3 files changed, 538 insertions(+), 86 deletions(-) create mode 100644 advanced/decorators_tutorial.ipynb delete mode 100644 advanced/decorators_tutorial.py diff --git a/advanced/decorators_tutorial.ipynb b/advanced/decorators_tutorial.ipynb new file mode 100644 index 0000000..3073998 --- /dev/null +++ b/advanced/decorators_tutorial.ipynb @@ -0,0 +1,537 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Python Decorators Tutorials" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. What is Python Wrappers\n", + "- Python wrappers are functions that are added to another function which then can add additional functionality or modifies its behavior without directly changing its source code. " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- Example 1: Without `functools.wraps()`\n", + " - We can observe that both the `first_function` and `second_function` after applying the `a_decorator` have the same `__name__` and `__doc__` string which is `name='wrapper', doc='A wrapper function'`\n", + "- Ideally, it should show the name and docstring of wrapped function (`func`) instead of wrapping function `wrapper`." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "First Function : name='wrapper', doc='A wrapper function'\n", + "Second Function: name='wrapper', doc='A wrapper function'\n" + ] + } + ], + "source": [ + "def a_decorator(func):\n", + " def wrapper(*args, **kwargs):\n", + " \"\"\"A wrapper function\"\"\"\n", + " # Extend some capabilities of func\n", + " func()\n", + " return wrapper\n", + " \n", + "@a_decorator\n", + "def first_function():\n", + " \"\"\"This is docstring for first function\"\"\"\n", + " print(\"first function\")\n", + " \n", + "@a_decorator\n", + "def second_function(a):\n", + " \"\"\"This is docstring for second function\"\"\"\n", + " print(\"second function\")\n", + " \n", + "print(f\"First Function : name='{first_function.__name__}', doc='{first_function.__doc__}'\")\n", + "print(f\"Second Function: name='{second_function.__name__}', doc='{second_function.__doc__}'\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- `functools.wraps()` as decorator to wrapper function\n", + " - Now, the function names and docstrings of wrapped function have been display correctly" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "First Function : name='first_function', doc='This is docstring for first function'\n", + "Second Function: name='second_function', doc='This is docstring for second function'\n" + ] + } + ], + "source": [ + "import functools\n", + "def a_decorator(func):\n", + " @functools.wraps(func)\n", + " def wrapper(*args, **kwargs):\n", + " \"\"\"A wrapper function\"\"\"\n", + " func()\n", + " return wrapper\n", + " \n", + "@a_decorator\n", + "def first_function():\n", + " \"\"\"This is docstring for first function\"\"\"\n", + " print(\"first function\")\n", + " \n", + "@a_decorator\n", + "def second_function(a):\n", + " \"\"\"This is docstring for second function\"\"\"\n", + " print(\"second function\")\n", + " \n", + "print(f\"First Function : name='{first_function.__name__}', doc='{first_function.__doc__}'\")\n", + "print(f\"Second Function: name='{second_function.__name__}', doc='{second_function.__doc__}'\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Examples of Wrapper Function" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.1 Timer\n", + "- To create the **decorator** in Python, we need to define a function called `timer` that takes a parameter called `func` = *a decorator function*. \n", + "- Inside the `timer` function, we define another function called `wrapper` that takes the **arguments** typically *passed to the function we want to decorate*.\n", + "- Within the `wrapper` function, we invoke the desired function using the provided arguments. \n", + " - We can do this with the line: `result = func(*args, **kwargs)`.\n", + " - Finally, the `wrapper` function returns the **result of the decorated function’s execution**. \n", + "- To utilize the decorator, you can apply it to the desired function using the @ symbol." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "import functools\n", + "import time\n", + "\n", + "# Timeit decorators\n", + "def timer(func):\n", + " @functools.wraps(func)\n", + " def wrapper(*args, **kwargs):\n", + " \"\"\"This is timeit's wrapper func\"\"\"\n", + " start = time.perf_counter()\n", + " # call the decorated function\n", + " result = func(*args, **kwargs)\n", + " end = time.perf_counter()\n", + " print(f\"Function '{func.__name__}' took {end - start:.6f} seconds to complete\")\n", + " return result\n", + "\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "10000\n", + "Function 'train_model' took 2.001211 seconds to complete\n" + ] + } + ], + "source": [ + "@timer\n", + "def train_model(a, b):\n", + " # simulate a function execution by pausing the program for 2 seconds\n", + " time.sleep(2) \n", + " print(a*b)\n", + "\n", + "\n", + "train_model(1000, b=10) " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2. Debugger\n", + "- An additional useful wrapper function can be created to facilitate debugging by printing the inputs and outputs of each function. \n", + "- This approach allows us to gain insight into the execution flow of various functions without cluttering our applications with multiple print statements." + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [], + "source": [ + "def debug(func):\n", + " @functools.wraps(func)\n", + " def wrapper(*args, **kwargs):\n", + " # print the fucntion name and arguments\n", + " print(f\"Calling '{func.__name__}' with args: {args} kwargs: {kwargs}\")\n", + " # call the function\n", + " result = func(*args, **kwargs)\n", + " # print the results\n", + " print(f\"'{func.__name__}' returned: {result}\")\n", + " return result\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Calling 'add_numbers' with args: (7,) kwargs: {'y': 5}\n", + "'add_numbers' returned: 12\n" + ] + }, + { + "data": { + "text/plain": [ + "12" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "@debug\n", + "def add_numbers(x, y):\n", + " return x + y\n", + "add_numbers(7, y=5)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.3. Exception Handler\n", + "- The exception_handler the wrapper will catch any exceptions raised within the decorator function" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [], + "source": [ + "def exception_handler(func):\n", + " @functools.wraps(func)\n", + " def wrapper(*args, **kwargs):\n", + " try: \n", + " return func(*args, **kwargs)\n", + " except Exception as e:\n", + " # Handle the exception\n", + " print(f\"An exception occurred: {str(e)}\")\n", + " # Optionally, perform additional error handling or logging\n", + " # Reraise the exception if needed\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "An exception occurred: division by zero\n" + ] + } + ], + "source": [ + "@exception_handler\n", + "def divide(x, y):\n", + " return x / y\n", + "divide(10, 0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.4. Call Count" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [], + "source": [ + "# Call Count\n", + "def count_call(func):\n", + " @functools.wraps(func)\n", + " def wrapper(*args, **kwargs):\n", + " wrapper.count += 1\n", + " result = func(*args, **kwargs)\n", + " print(f\"{func.__name__} has been called {wrapper.count} times\")\n", + " return result\n", + "\n", + " wrapper.count = 0 # initialise to 0 before you ran any of them.\n", + " return wrapper" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "add_numbers has been called 1 times\n", + "1999\n", + "add_numbers has been called 2 times\n", + "3\n" + ] + } + ], + "source": [ + "@count_call\n", + "def add_numbers(a, b):\n", + " \"\"\"This is plus_two_number function\"\"\"\n", + " return a + b\n", + "\n", + "print(add_numbers(1000, 999))\n", + "print(add_numbers(1, 2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.5. Built-in `lru_cache`\n", + "\n", + "- `@fucntools.lru_cache`: When calling the input function,\n", + " - It first checks if its arguments are present in the cache.\n", + " - If it’s the case, return the result.\n", + " - Otherwise, compute it and put it in the cache" + ] + }, + { + "cell_type": "code", + "execution_count": 60, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Function 'multiply_numbers' took 0.000002 seconds to complete\n", + "987644223459\n", + "Function 'multiply_numbers' took 0.000002 seconds to complete\n", + "2\n", + "Function 'multiply_numbers' took 0.000001 seconds to complete\n", + "987644223459\n" + ] + } + ], + "source": [ + "@timer\n", + "@functools.lru_cache\n", + "def multiply_numbers(a, b):\n", + " \"\"\"This is plus_two_number function\"\"\"\n", + " return a * b\n", + "\n", + "print(multiply_numbers(99999, 9876541))\n", + "print(multiply_numbers(1, 2))\n", + "print(multiply_numbers(99999, 9876541))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "- As you can see that `multiply_numbers` with input` a=99999, b=9876541` called 2 times\n", + " - For the first time, it took 0.000002 to complete\n", + " - For the second time, it only took 0.000001 to complete this is because the result from the second time is retrieved from the cache thanks to the `@functools.lru_cache`\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.6. Retry\n", + "- This wrapper retries the execution of a function a specified number of times with a delay between retries." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "import logging\n", + "import traceback\n", + "\n", + "LOG_FORMAT = \"%(asctime)s - %(levelname)s - %(pathname)s - %(funcName)s - %(lineno)d -msg: %(message)s\"\n", + "logging.basicConfig(level=logging.INFO, format=LOG_FORMAT)\n", + "\n", + "def retry(max_attempts, delay):\n", + " \"\"\"\n", + " retry help decorator.\n", + " :param max_attempts: the retry num; retry sleep sec\n", + " :return: decorator\n", + " \"\"\"\n", + " def decorator(func):\n", + " \"\"\"decorator\"\"\"\n", + " @functools.wraps(func) # preserve information about the original function, or else the wrapped func name will be \"wrapper\" not \"func\"\n", + " def wrapper(*args, **kwargs):\n", + " \"\"\"wrapper\"\"\"\n", + " for attempt in range(max_attempts):\n", + " try:\n", + " return func(*args, **kwargs) \n", + " except Exception as err: \n", + " logging.error(err)\n", + " logging.error(traceback.format_exc())\n", + " time.sleep(delay)\n", + " logging.error(f\"Trying attempt {attempt+1} of {max_attempts}\")\n", + " logging.error(f\"func {func.__name__}retry failed\")\n", + " raise Exception(f'Exceed max retry num: {max_attempts} failed')\n", + "\n", + " return wrapper\n", + "\n", + " return decorator" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2023-10-18 00:08:52,201 - ERROR - /var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py - wrapper - 22 -msg: Server is not responding.\n", + "2023-10-18 00:08:52,212 - ERROR - /var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py - wrapper - 23 -msg: Traceback (most recent call last):\n", + " File \"/var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py\", line 20, in wrapper\n", + " return func(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/579690303.py\", line 5, in fetch_data\n", + " raise TimeoutError(\"Server is not responding.\")\n", + "TimeoutError: Server is not responding.\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fetching the data..\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2023-10-18 00:08:54,218 - ERROR - /var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py - wrapper - 25 -msg: Trying attempt 1 of 2\n", + "2023-10-18 00:08:54,219 - ERROR - /var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py - wrapper - 22 -msg: Server is not responding.\n", + "2023-10-18 00:08:54,221 - ERROR - /var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py - wrapper - 23 -msg: Traceback (most recent call last):\n", + " File \"/var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py\", line 20, in wrapper\n", + " return func(*args, **kwargs)\n", + " ^^^^^^^^^^^^^^^^^^^^^\n", + " File \"/var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/579690303.py\", line 5, in fetch_data\n", + " raise TimeoutError(\"Server is not responding.\")\n", + "TimeoutError: Server is not responding.\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Fetching the data..\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "2023-10-18 00:08:56,222 - ERROR - /var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py - wrapper - 25 -msg: Trying attempt 2 of 2\n", + "2023-10-18 00:08:56,223 - ERROR - /var/folders/ww/280v33ws1pdd58c895ntxf4w0000gn/T/ipykernel_48486/3869183515.py - wrapper - 26 -msg: func fetch_dataretry failed\n" + ] + }, + { + "ename": "Exception", + "evalue": "Exceed max retry num: 2 failed", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mException\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m/Users/quannguyen/repos/python/advanced/decorators_tutorial.ipynb Cell 19\u001b[0m line \u001b[0;36m7\n\u001b[1;32m
4\u001b[0m \u001b[39m# raise timeout error to simulate a server not responding..\u001b[39;00m\n\u001b[1;32m 5\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mTimeoutError\u001b[39;00m(\u001b[39m\"\u001b[39m\u001b[39mServer is not responding.\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m----> 7\u001b[0m fetch_data(\u001b[39m\"\u001b[39;49m\u001b[39mhttps://example.com/data\u001b[39;49m\u001b[39m\"\u001b[39;49m)\n", + "\u001b[1;32m/Users/quannguyen/repos/python/advanced/decorators_tutorial.ipynb Cell 19\u001b[0m line \u001b[0;36m2\n\u001b[1;32m 25\u001b[0m logging\u001b[39m.\u001b[39merror(\u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mTrying attempt \u001b[39m\u001b[39m{\u001b[39;00mattempt\u001b[39m+\u001b[39m\u001b[39m1\u001b[39m\u001b[39m}\u001b[39;00m\u001b[39m of \u001b[39m\u001b[39m{\u001b[39;00mmax_attempts\u001b[39m}\u001b[39;00m\u001b[39m\"\u001b[39m)\n\u001b[1;32m 26\u001b[0m logging\u001b[39m.\u001b[39merror(\u001b[39mf\u001b[39m\u001b[39m\"\u001b[39m\u001b[39mfunc \u001b[39m\u001b[39m{\u001b[39;00mfunc\u001b[39m.\u001b[39m\u001b[39m__name__\u001b[39m\u001b[39m}\u001b[39;00m\u001b[39mretry failed\u001b[39m\u001b[39m\"\u001b[39m)\n\u001b[0;32m---> 27\u001b[0m \u001b[39mraise\u001b[39;00m \u001b[39mException\u001b[39;00m(\u001b[39mf\u001b[39m\u001b[39m'\u001b[39m\u001b[39mExceed max retry num: \u001b[39m\u001b[39m{\u001b[39;00mmax_attempts\u001b[39m}\u001b[39;00m\u001b[39m failed\u001b[39m\u001b[39m'\u001b[39m)\n", + "\u001b[0;31mException\u001b[0m: Exceed max retry num: 2 failed" + ] + } + ], + "source": [ + "@retry(max_attempts=2, delay=2)\n", + "def fetch_data(url):\n", + " print(\"Fetching the data..\")\n", + " # raise timeout error to simulate a server not responding..\n", + " raise TimeoutError(\"Server is not responding.\")\n", + "\n", + "fetch_data(\"https://example.com/data\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + }, + "orig_nbformat": 4 + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/advanced/decorators_tutorial.py b/advanced/decorators_tutorial.py deleted file mode 100644 index 62503ff..0000000 --- a/advanced/decorators_tutorial.py +++ /dev/null @@ -1,86 +0,0 @@ -import logging -import time -from functools import lru_cache, wraps - -logging.basicConfig(level=logging.INFO, format="%(levelname)s %(message)s") - - -# Basic Decorators -def logger_decorator(orig_func): - def wrapper_func(*args, **kwargs): - """This is logger_decorator's wrapper func""" - logging.info(f"Function name: {orig_func.__name__}") - return orig_func(*args, **kwargs) - - return wrapper_func - - -def another_decorator(orig_func): - def wrapper_func(*args, **kwargs): - """This is another_decorator's wrapper func""" - logging.info("Inside another decorator func") - return orig_func(*args, **kwargs) - - return wrapper_func - - -# Timeit decorators -def timeit(func): - @wraps(func) - def wrapper(*args, **kwargs): - """This is timeit's wrapper func""" - start = time.perf_counter() - result = func(*args, **kwargs) - end = time.perf_counter() - print(f"{func.__name__} took {end - start:.6f} seconds to complete") - return result - - return wrapper - - -# Call Count -def countcall(func): - @wraps(func) - def wrapper(*args, **kwargs): - wrapper.count += 1 - result = func(*args, **kwargs) - print(f"{func.__name__} has been called {wrapper.count} times") - return result - - wrapper.count = 0 - return wrapper - - -@another_decorator -@logger_decorator -def plus_two_number(a, b): - """This is plus_two_number function""" - return a + b - - -@timeit -@countcall -@lru_cache # LRU Cache -def add_two_number(a, b): - """This is add_two_number function""" - return a + b - - -if __name__ == "__main__": - result = plus_two_number(1, 2) - - # @wraps(orig_func): - print( - plus_two_number.__name__, plus_two_number.__doc__ - ) # wrapper_func instead of plus_two_number - print( - add_two_number.__name__, add_two_number.__doc__ - ) # add_two_number This is add_two_number function since we use @wraps() - - # @lru_cache: When calling the input function, - # it first checks if its arguments are present in the cache. - # If it’s the case, return the result. - # Otherwise, compute it and put it in the cache - add_two_number(1000, 999) # call the 1st time same input - add_two_number(1000, 999) # call the 2nd time same input - add_two_number(1000, 999) # call the 3rd time same input diff --git a/requirements.txt b/requirements.txt index 6954ac5..77005ea 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ attrs +black pydantic pyaml From 3eb538272de684e9c50aeb4116452646f8f90a3b Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Fri, 20 Oct 2023 23:07:33 +0800 Subject: [PATCH 099/150] Update daily_knowledge.md --- daily_knowledge.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 0652a8d..5e4aa5c 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,9 @@ # 2023 ## Day 6 +- Number: `1000000` can be written as `1_000_000` for the ease of visualisation + ```Python + state['Population'] / 1_000_000 + ``` ### Matplotlib - Plot horizontal line: `{plt, ax}.axhline(y=0.5, color='r', linestyle='-')` ### Numpy From 8d3b0c2fb76013aebb9d96ba42ac0c2be0cd0e7c Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 21 Oct 2023 00:02:36 +0800 Subject: [PATCH 100/150] Update daily_knowledge.md --- daily_knowledge.md | 40 +++++++++++++++++++++++++++++++++++++++- 1 file changed, 39 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5e4aa5c..1c5e4bb 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -155,7 +155,23 @@ ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=45, ha='right') - `df.loc[:, "col"] = df["col"].map(mapping)` re-assign the updated value to originial column without any error - `pd.set_option('max_columns', 200)` to view all the columns in the df when `df.head()` #### `groupby` -- create a new column by using the transform `function` of pandas along with `groupby` +- Use the `.agg` function to get multiple statistics on the other columns +```Python +## Example 1: +df.groupby('A').agg(['min', 'max']) # apply same operations on other columns +## Example 2: +df.groupby('A').agg({'B': ['min', 'max'], 'C': 'sum'}) # apply different operations on other columns +## Example 3: +# group by Team & Position, get mean, min, and max value of Age for each value of Team. +grouped_single = df.groupby(['Team', 'Position']).agg({'Age': ['mean', 'min', 'max']}) + +# rename columns +grouped_single.columns = ['age_mean', 'age_min', 'age_max'] + +# reset index to get grouped columns back +grouped_single = grouped_single.reset_index() +``` +- Create a new column by using the `transform` function of pandas along with `groupby` ```Python # Group by col_1, count by col_2, and then count df.groupby(["col_1"])["col_2"].count() @@ -164,6 +180,28 @@ df.groupby(["col_1"])["col_2"].count() # Create a new column with count values by using transform df.groupby(["col_1"])["col_2"].transform("count") ``` +- Group by the first column and get second column as lists in rows using `.apply(list)` +```Python +In [1]: df = pd.DataFrame( {'a':['A','A','B','B','B','C'], 'b':[1,2,5,5,4,6]}) + df + +Out[1]: + a b +0 A 1 +1 A 2 +2 B 5 +3 B 5 +4 B 4 +5 C 6 + +In [2]: df.groupby('a')['b'].apply(list) +Out[2]: +a +A [1, 2] +B [5, 5, 4] +C [6] +Name: b, dtype: object +``` ### Python - `IPython` debug: when executing `main.py` script in the terminal, we still can insert **ipython** checkpoint at the line we want to debug - `from IPython import embed; embed()` From 0c845a2f83c60d34f7d53202472e880d7e121259 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 21 Oct 2023 00:03:46 +0800 Subject: [PATCH 101/150] Update daily_knowledge.md --- daily_knowledge.md | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 1c5e4bb..a899bdb 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -164,22 +164,11 @@ df.groupby('A').agg({'B': ['min', 'max'], 'C': 'sum'}) # apply different operati ## Example 3: # group by Team & Position, get mean, min, and max value of Age for each value of Team. grouped_single = df.groupby(['Team', 'Position']).agg({'Age': ['mean', 'min', 'max']}) - -# rename columns -grouped_single.columns = ['age_mean', 'age_min', 'age_max'] - +grouped_single.columns = ['age_mean', 'age_min', 'age_max'] # rename columns # reset index to get grouped columns back grouped_single = grouped_single.reset_index() ``` -- Create a new column by using the `transform` function of pandas along with `groupby` -```Python -# Group by col_1, count by col_2, and then count -df.groupby(["col_1"])["col_2"].count() -# Group by col_1, count by col_2, and then count -# Create a new column with count values by using transform -df.groupby(["col_1"])["col_2"].transform("count") -``` - Group by the first column and get second column as lists in rows using `.apply(list)` ```Python In [1]: df = pd.DataFrame( {'a':['A','A','B','B','B','C'], 'b':[1,2,5,5,4,6]}) From 858061aebaa08440c84eec202fdb68de078070c6 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Sat, 21 Oct 2023 00:04:13 +0800 Subject: [PATCH 102/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index a899bdb..3896ac5 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -416,7 +416,7 @@ print(next(phones_iter)) ```json # in .vscode settings.json - "python.terminal.activateEnvironment": true +"python.terminal.activateEnvironment": true ``` ## Code Formatter & Linting From 2d1e34fe96c9ea642f144409c78869ae2ac208b3 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Sun, 22 Oct 2023 12:25:07 +0800 Subject: [PATCH 103/150] conda knowledge --- assests/img/conda_miniconda_anaconda.webp | Bin 0 -> 50588 bytes docs/conda.md | 66 ++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 assests/img/conda_miniconda_anaconda.webp create mode 100644 docs/conda.md diff --git a/assests/img/conda_miniconda_anaconda.webp b/assests/img/conda_miniconda_anaconda.webp new file mode 100644 index 0000000000000000000000000000000000000000..591f121525b9dc1ba3a80f2bb75db043a57269ad GIT binary patch literal 50588 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

+ +- **Rule of thumbs**: installing Miniconda which combines Conda with Python 3 + - If needs a particular version of the full Anaconda distribution you can always create an new conda environment with following command + +```shell +conda create --name anaconda-env-202302 anaconda=2023.02 +``` + +### Miniconda and Miniforge + +- `miniforge` is the **community** (`conda-forge`) driven minimalistic conda installer. Subsequent package installations come thus from conda-forge channel. +- `miniconda` is the **Anaconda** (company) driven minimalistic conda installer. Subsequent package installations come from the **anaconda channels** (default or otherwise). +- Summary: Miniforge-installed conda is the same as Miniconda-installed conda, except that it uses the conda-forge channel (and only the conda-forge channel) as the default channel. + +### Conda Channel + +- A **channel** is the location where packages are stored remotely. +- To Check the default channels: `conda config --show channels` +- To Install a Package in Conda Using a Channel Name: `conda install -c conda-forge matplotlib` + - This is to install `matplotlib` via `conda-forge` channel + +## Why should you use Conda ? + +- Conda provides **pre-built** packages or binaries (which generally avoids the need to deal with compiling packages from source). + - TensorFlow is an example of a tool which is difficult to install source (particularly with GPU support), but that can be installed using Conda in a single step. +- Conda is cross platform, with support for Windows, MacOS, GNU/Linux, and support for multiple hardware platforms, such as x86 and Power 8 and 9. +- Where a library or tools is not already packaged for install using conda, Conda allows for using other package management tools (such as pip) inside Conda environments. +- Conda can quickly install commonly used data science libraries and tools, such as R, NumPy, SciPy, Scikit-learn, Dask, TensorFlow, PyTorch, Fast.ai, NVIDIA RAPIDS, and more built using optimized, hardware specific libraries (such as Intel’s MKL or NVIDIA’s CUDA), which provides a speedup without having to change any of your code. From dc56a7903c8bba958ccd9877797871ae0b6f5526 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Sun, 22 Oct 2023 12:49:59 +0800 Subject: [PATCH 104/150] update the conda update --- docs/conda.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/docs/conda.md b/docs/conda.md index 3e13e01..7eb3e86 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -64,3 +64,43 @@ conda create --name anaconda-env-202302 anaconda=2023.02 - Conda is cross platform, with support for Windows, MacOS, GNU/Linux, and support for multiple hardware platforms, such as x86 and Power 8 and 9. - Where a library or tools is not already packaged for install using conda, Conda allows for using other package management tools (such as pip) inside Conda environments. - Conda can quickly install commonly used data science libraries and tools, such as R, NumPy, SciPy, Scikit-learn, Dask, TensorFlow, PyTorch, Fast.ai, NVIDIA RAPIDS, and more built using optimized, hardware specific libraries (such as Intel’s MKL or NVIDIA’s CUDA), which provides a speedup without having to change any of your code. + +## Setup Conda on Macbook M2 + +- Download [Miniforge3 (Conda installer)](https://github.com/conda-forge/miniforge), namely [Miniforge3-MacOSX-arm64.sh](https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-arm64.sh), for macOS arm64 chips (M1, M1 Pro, M1 Max) +- Install Miniforge3 into home directory + - Installation Path: `/users//miniforge3` + - Run `conda init` + - Restart Terminal + +```shell +chmod +x ~/Downloads/Miniforge3-MacOSX-arm64.sh +sh ~/Downloads/Miniforge3-MacOSX-arm64.sh +source ~/miniforge3/bin/activate +``` + +- Verify installation: `conda info` + +## Conda commands + +- List all existing environments: `conda env list` + +### Create environments + +#### Method 1 + +```shell +conda create --name env-name +conda activate env-name +conda deactivate +``` + +- The environments created by Conda is always located in `/users//miniforge3/envs/` + +#### Method 2: custom env location (preferred) + +```shell +conda create --prefix ./venv python=3.8 +conda activate ./venv +conda deactivate +``` From d454884777f39a4d5b8848450675219d66e7196c Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Sun, 22 Oct 2023 18:05:32 +0800 Subject: [PATCH 105/150] update --- docs/conda.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/docs/conda.md b/docs/conda.md index 7eb3e86..650a8e3 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -90,7 +90,7 @@ source ~/miniforge3/bin/activate #### Method 1 ```shell -conda create --name env-name +conda create --name env-name --file environment.yml conda activate env-name conda deactivate ``` @@ -100,7 +100,53 @@ conda deactivate #### Method 2: custom env location (preferred) ```shell -conda create --prefix ./venv python=3.8 +conda create --prefix ./venv python=3.8 --file environment.yml conda activate ./venv conda deactivate ``` + +#### `environment.yml` + +- `tensorflow-deps` will need to be installed by `conda` via `apple` channel +- `scikit-learn` will be installed by `conda` via `conda-forge` channel +- `tensorflow-macos` will need `pip` install via **PyPI** + +```yaml +name: tensorflow +channels: + - apple + - conda-forge +dependencies: + - tensorflow-deps + - scikit-learn + - pip: + - tensorflow-macos + - tensorflow-metal +``` + +#### Tensorflow Setup MacOS M2 + +- Create env: + +```shell +conda create --prefix ./venv python=3.10 +conda activate ./venv +``` + +- Install TensorFlow dependencies from Apple Conda channel + +```shell +conda install -c apple tensorflow-deps +``` + +- Install TensorFlow Base (Apple's fork of TensorFlow is called tensorflow-macos) + +```shell +python -m pip install tensorflow-macos +``` + +- Install Apple's `tensorflow-metal` to leverage Apple Metal (Apple's GPU framework) for M1, M1 Pro, M1 Max GPU acceleration. + +```shell +python -m pip install tensorflow-metal +``` From 8698577d8ad0dc13b93a4f24b29f6990109f50ad Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Tue, 24 Oct 2023 00:07:52 +0800 Subject: [PATCH 106/150] update conda installation summary --- daily_knowledge.md | 136 +++++++++++++++++++++++++++++++++++++++------ docs/conda.md | 12 +++- 2 files changed, 130 insertions(+), 18 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 3896ac5..c6872cf 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,15 +1,56 @@ # 2023 + +## Day 7 + +### Conda + +- Conda is an open source **package** + **environment** manager +- Conda vs Miniconda vs Anaconda: + - Conda + - [Miniconda](https://docs.conda.io/projects/miniconda/en/latest/) = Conda + Python 3 + Base Packages + - Anaconda = Miniconda + High Quality Packages +- Recommended conda installation in PC: Miniconda +- Miniconda and Miniforge: + - **Miniforge**-installed conda is the same as Miniconda-installed conda, except that it uses the conda-forge channel (and only the conda-forge channel) as the default channel. + - **Miniconda**-installed conda is the Anaconda (company) driven minimalistic conda installer, where pacakages installed from the anaconda channels +- Conda channel: A **channel** is the location where packages are stored remotely. + - Example of channels: Anaconda channel, `conda-forge`, Apple + - Install TensorFlow dependencies from Apple Conda channel: `conda install -c apple tensorflow-deps` +- Understanding `environment.yml` in `conda create --prefix ./venv python=3.8 --file environment.yml` + - `tensorflow-deps` will need to be installed by `conda` via `apple` channel + - `scikit-learn` will be installed by `conda` via `conda-forge` channel + - `tensorflow-macos` will need `pip` install via **PyPI** + +```yaml +name: tensorflow +channels: + - apple + - conda-forge +dependencies: + - tensorflow-deps + - scikit-learn + - pip: + - tensorflow-macos + - tensorflow-metal +``` + ## Day 6 + - Number: `1000000` can be written as `1_000_000` for the ease of visualisation ```Python state['Population'] / 1_000_000 ``` + ### Matplotlib + - Plot horizontal line: `{plt, ax}.axhline(y=0.5, color='r', linestyle='-')` + ### Numpy + - Stacking columns/rows - - `np.column_stack` & `np.row_stack` - - `np.hstack` & `np.vstack` + - `np.column_stack` & `np.row_stack` + - `np.hstack` & `np.vstack` + ```Python a = np.array((1,2,3)) b = np.array((2,3,4)) @@ -29,18 +70,28 @@ np.vstack((a,b)) np.hstack((a,b)) # array([1, 2, 3, 2, 3, 4]) ``` + ### Holidays package + - Pandas's holiday package: `pandas.tseries.holiday` - `holidays` package + ### Code Refactor + - Instead of `if '.yml' in file_path or '.yaml' in file_path` we can do as follows: - - Solution: `if any(ext in file_path for ext in ['.yml', '.yaml']` + - Solution: `if any(ext in file_path for ext in ['.yml', '.yaml']` + ## Day 5 + ### Seaborn + - To get color palatte `color_pal = sns.color_palette()` + #### Pairplot + - Pairplot is to use `scatterplot()` for each pairing of the variables and `histplot()` for the marginal plots along the diagonal - Customise with `x_var` and `y_var` and `hue` + ```Python sns.pairplot(df.dropna(), hue='hour', @@ -56,8 +107,8 @@ plt.show()

- ### Python + - `yield` keyword is used in the context of defining generator functions. - When a generator function is called, it doesn't execute the function immediately. - Instead, it returns a generator object that can be used to control the execution of the function. @@ -83,41 +134,55 @@ for value in simple_generator(): print(value) ``` + ### Pandas + ### Select columns based on Dtype + - Numerical columns: `num_cols = df.select_dtypes(include=np.number).columns.tolist()` - Categorical columns: `cat_cols = df.select_dtypes(exclude=np.number).columns.tolist()` -### Time-series + +### Time-series + - Convert the datetime index to a datetime col: `df['date'] = df.index.date` - Slicing using 1 date by including `23:59:59` + ```Python end_train = '1980-01-01 23:59:59' # including 23:59:59 means data_train = df.loc[:end_train] # ends at 1980-01-01 data_test = df.loc[end_train:] # start at 1980-01-02 ``` + #### `df.query` + - Can set multiple condition: `df.query("make == 'bmw' and model == '1_series')` - Can query using a list + ```Python holiday_list = ['2021-01-01', '2022-09-02'] df.query('datetime_col in @holiday_list') ``` + #### Check & Remove Duplicates -- `df.duplicated()` to check if there are any row duplicate. This will return `True` for the 2nd occurence of the duplicate + +- `df.duplicated()` to check if there are any row duplicate. This will return `True` for the 2nd occurence of the duplicate - `df.duplicated(subset=['col_A','col_B','col_C'])` in case there is no entire row duplciate, we can check duplicates for only subsets of columns - `df.query("make == 'bmw' and model == '1_series' and year == 2013 and price == 31500")` using query to identify & view the duplicated rows - Remove the duplicates - `.reset_index(drop=True)` to reset the index after dropping the duplicates - `.copy()` to make the deep copy of the dataframe + ```Python df = df.loc[~df.duplicated(subset=['Coaster_Name','Location','Opening_Date'])] \ - .reset_index(drop=True).copy() + .reset_index(drop=True).copy() ``` + ### Matplotlib - You can set matplotlib object to `ax` variable - You also can continue to plot on the same graph with `ax` variable + ```Python # case 1: get ax from the plot via pandas dataframe ax = df['year'].value_counts() \ @@ -134,7 +199,9 @@ ax.set_ylabel('count') ax = sns.countplot(data=df, x='year') ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=90, ha='center') ``` + - Rotate the xticks label + ```Python # rotate via plt plt.xticks(rotation=90) @@ -142,8 +209,11 @@ plt.xticks(rotation=90) # rotate via ax ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=45, ha='right') ``` + ## Day 4 + ### Numpy + - Numpy 's `np.nan` vs Python 's `None` object - In Numpy, a `np.nan` value is a native floating-point type array. - When you try to do some arithmetic operations will `np.nan`, the result will always be `np.nan`. @@ -151,11 +221,16 @@ ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=45, ha='right') - `None` is a Python Object called **NoneType** - Pandas automatically converts the `None` to a `np.nan` value. - If you try to aggregate over this array, you will get an error because of the NoneType. + ### Pandas + - `df.loc[:, "col"] = df["col"].map(mapping)` re-assign the updated value to originial column without any error - `pd.set_option('max_columns', 200)` to view all the columns in the df when `df.head()` + #### `groupby` + - Use the `.agg` function to get multiple statistics on the other columns + ```Python ## Example 1: df.groupby('A').agg(['min', 'max']) # apply same operations on other columns @@ -170,11 +245,12 @@ grouped_single = grouped_single.reset_index() ``` - Group by the first column and get second column as lists in rows using `.apply(list)` + ```Python In [1]: df = pd.DataFrame( {'a':['A','A','B','B','B','C'], 'b':[1,2,5,5,4,6]}) df -Out[1]: +Out[1]: a b 0 A 1 1 A 2 @@ -184,17 +260,20 @@ Out[1]: 5 C 6 In [2]: df.groupby('a')['b'].apply(list) -Out[2]: +Out[2]: a A [1, 2] B [5, 5, 4] C [6] Name: b, dtype: object ``` + ### Python + - `IPython` debug: when executing `main.py` script in the terminal, we still can insert **ipython** checkpoint at the line we want to debug - `from IPython import embed; embed()` -- Avoid circular imports +- Avoid circular imports + ``` # __init__.py of utils folder from .base_logger import * @@ -205,30 +284,40 @@ Name: b, dtype: object # data_loader.py from utils import load_yaml # this will cause circular import ``` + - Solution: DO NOT `from .data_loader import *` if a data_loader refer to any functions in `utils.__init__.py` + ### `.env` + - Installation: `pip install python-dotenv==1.0.0` - Config file stores in `.env` file + ```shell HUGGINGFACEHUB_API_TOKEN="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" ``` + - Load environmental variables + ```Python import os from dotenv import load_dotenv, find_dotenv -load_dotenv("../config/.env") -# load_dotenv(find_dotenv()) # find_dotenv() is to find the .env +load_dotenv("../config/.env") +# load_dotenv(find_dotenv()) # find_dotenv() is to find the .env os.environ["HUGGINGFACEHUB_API_TOKEN"] = ... # insert your API_TOKEN here ``` ## Day 3 -### Notebook + +### Notebook + - Surpass the warning + ```Python import warnings warnings.filterwarnings('ignore') ``` + - Both `!` and `%` allow you to run shell commands from a Jupyter notebook - Difference: `!` calls out to a shell (in a new process), while `%` affects the process associated with the notebook - `!cd foo`, by itself, has **no lasting effect**, since the process with the changed directory immediately terminates. @@ -285,6 +374,7 @@ model = joblib.load('lgbm_mode.pkl') ## Day 2 ### Pandas + - `df = pd.read_csv('example.csv',index_col=[0], parse_dates=[0])` to set the col loc=0 as the index, and parsed as date time type - `to_csv` to prevent `nnamed: 0` column to be appended along with your original df by set `df.to_csv('result.csv', index=False)` - `.apply` based on the condition of certain columns @@ -352,14 +442,15 @@ x = tf.ones(shape=(2, 2)) x[0, 0] = 0. # ERROR: fail, as a tensor isn’t assignable. ``` -### `sys.path` +### `sys.path` - `sys.path` is a built-in variable within the sys module. It contains a list of directories that the interpreter will search in for the required module. When a module(a module is a python file) is imported within a Python file, the interpreter first searches for the specified module among its built-in modules. If not found it looks through the list of directories(a directory is a folder that contains related modules) defined by sys.path. - To locate the installation path of the module: `print(module_name.__file__)` - Python will locate the module based on the path appears first in `sys.path`, so in order to change prioritise the installation packages, we can do as follow: + ```Python import sys -sys.path.insert(0, '/path/to/site-packages') # location of src +sys.path.insert(0, '/path/to/site-packages') # location of src ``` ### Matplotlib @@ -367,9 +458,12 @@ sys.path.insert(0, '/path/to/site-packages') # location of src - Set params: `plt.rcParams.update({'font.size': 14})` - Set the style of the plot `plt.style.use('fivethirtyeight') # set at the front of the notebook` - Other styles: `seaborn-v0_8-darkgrid` -#### Ax + +#### Ax + - Set vertical axis range: `ax.set_ylim([0,1])` or `plt.gca().set_ylim(0,1) #set vertical range to [0-1]` -- Set horizontal axis range: +- Set horizontal axis range: + #### Subplots - Enable subplots share the same axis with `sharex` or `sharey`: `plt.subplots(nrows=3, sharey=True)` @@ -420,11 +514,14 @@ print(next(phones_iter)) ``` ## Code Formatter & Linting + - The main coding standard for Python is PEP8 (Python Enhancement Proposal 8) - **Linters** such as `flake8` and `pylint` highlight places where your code doesn’t conform with PEP8. - **Automatic formatters** such as `black` that will update your code automatically to conform with coding standards. - **Type Checker** `mypy` is a static type checker for Python. Type checkers help ensure that you're using variables and functions in your code correctly. With mypy, add type hints (PEP 484) to your Python programs, and mypy will warn you when you use those types incorrectly. + ### Setup inside VS Code + - How to install `flack8`: - Step 1: Install `black` in virtual environment: `pip install flake8` - Step 2: Open the Command Palette (`CMD + Shift + P`) → Search the “Python: Select Linter” and press enter. Select the “flake8” @@ -441,8 +538,11 @@ print(next(phones_iter)) "source.organizeImports": true } ``` + ### Setup pre-commit using `git hooks` + This is to ensure the code formatter, linting is running before the commit + - install requirements-dev dependencies ```sh @@ -476,5 +576,7 @@ coverage echo "-------------Type checking with mypy-----------------" mypy $linting_path --ignore-missing-imports ``` + ### Setup pre-commit using `pre-commit` package + - [Reading](https://medium.com/@anton-k./how-to-set-up-pre-commit-hooks-with-python-2b512290436) diff --git a/docs/conda.md b/docs/conda.md index 650a8e3..33b30c1 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -70,9 +70,19 @@ conda create --name anaconda-env-202302 anaconda=2023.02 - Download [Miniforge3 (Conda installer)](https://github.com/conda-forge/miniforge), namely [Miniforge3-MacOSX-arm64.sh](https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-MacOSX-arm64.sh), for macOS arm64 chips (M1, M1 Pro, M1 Max) - Install Miniforge3 into home directory - Installation Path: `/users//miniforge3` - - Run `conda init` + - Run `conda init` (conda init code will be added to .zshrc) - Restart Terminal +### Config + +- Conda config will be stored in `~/.condarc` +- Show env name, instead of the entire path to env: + - `conda config --set env_prompt '({name})'` + - This above command is equivalent to add `env_prompt: '({name})'` to `.condarc` +- **Bug 1**: [environment duplication](https://github.com/microsoft/vscode-python/issues/22233?fbclid=IwAR1RimJUIENwStVLCyxOQLSWXsXdCK3aO5PYgSD9-N9i9ewXMwIIMx-vTtY) when open VS code terminal, conda init will be auto init the base env, and then after that VS code will activate the specific env of the project causing the terminal will have two env, say `(venv) (base) folder` + - _Solution_: disable the auto_activate_base env in `.condarc` with the follow commands + - `conda config --set auto_activate_base False` + ```shell chmod +x ~/Downloads/Miniforge3-MacOSX-arm64.sh sh ~/Downloads/Miniforge3-MacOSX-arm64.sh From 06ba3d2c76e1783c81c2dd8c48fe7761ba81c875 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Tue, 24 Oct 2023 23:56:36 +0800 Subject: [PATCH 107/150] update anaconda --- daily_knowledge.md | 8 ++++---- docs/conda.md | 28 +++++++++++++++++++++++----- 2 files changed, 27 insertions(+), 9 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index c6872cf..b7e7d75 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -5,10 +5,10 @@ ### Conda - Conda is an open source **package** + **environment** manager -- Conda vs Miniconda vs Anaconda: - - Conda - - [Miniconda](https://docs.conda.io/projects/miniconda/en/latest/) = Conda + Python 3 + Base Packages - - Anaconda = Miniconda + High Quality Packages +- Conda vs (Miniconda & Anaconda): + - *Conda* is a **package manager** & *Conda* is tightly coupled to two software distributions: *Anaconda* and *Miniconda*. + - *Anaconda* is a full distribution of the central software in the PyData ecosystem, and includes Python itself along with binaries for several hundred third-party open-source projects. + - *Miniconda* is essentially an installer for an empty conda environment, containing only Conda and its dependencies, so that you can install what you need from scratch. - Recommended conda installation in PC: Miniconda - Miniconda and Miniforge: - **Miniforge**-installed conda is the same as Miniconda-installed conda, except that it uses the conda-forge channel (and only the conda-forge channel) as the default channel. diff --git a/docs/conda.md b/docs/conda.md index 33b30c1..22ad2c4 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -29,12 +29,28 @@ | Require compiled | No | Yes | | Create isolated env | built-in | `virtualenv`, `venv` | | Dependency Check | Yes | No | +### Conda vs Virtualenv +- `virtualenv/venv` are utilites that allow users to create isolated Python environments that work with pip. +- **Conda** has its own built-in environment manager that works seamlessly with both conda and pip, and in fact has several advantages over virtualenv/venv: + - conda environments integrate management of different Python versions, including installation and updating of Python itself. Virtualenvs must be created upon an existing, externally managed Python executable. + - conda environments can track non-python dependencies; for example seamlessly managing dependencies and parallel versions of essential tools like LAPACK or OpenSSL + - Rather than environments built on symlinks – which break the isolation of the virtualenv and can be flimsy at times for non-Python dependencies – conda-envs are true isolated environments within a single executable path. + - While virtualenvs are not compatible with conda packages, conda environments are entirely compatible with pip packages. First conda install pip, and then you can pip install any available package within that environment. You can even explicitly list pip packages in conda environment files, meaning the full software stack is entirely reproducible from a single environment metadata file. +### Conda vs (Miniconda & Anaconda) + +- *Conda* is a **package manager** + - A package manager is a tool that automates the process of installing, updating, and removing packages. + - *Conda* is tightly coupled to two software distributions: *Anaconda* and *Miniconda*. +- *Anaconda* is a **software distribution** created by by Continuum Analytics. Although Conda is packaged with Anaconda, the two are distinct entities with distinct goals. + - A software distribution is a pre-built and pre-configured collection of packages that can be installed and used on a system. + +#### Anaconda vs Miniconda + +- Anaconda is a full distribution of the central software in the PyData ecosystem, and includes Python itself along with binaries for several hundred third-party open-source projects. +- Miniconda is essentially an installer for an empty conda environment, containing only Conda and its dependencies, so that you can install what you need from scratch. + -### Conda vs Miniconda vs Anaconda -- Conda -- [Miniconda](https://docs.conda.io/projects/miniconda/en/latest/) = Conda + Python 3 + Base Packages -- Anaconda = Miniconda + High Quality Packages

- **Rule of thumbs**: installing Miniconda which combines Conda with Python 3 @@ -56,7 +72,9 @@ conda create --name anaconda-env-202302 anaconda=2023.02 - To Check the default channels: `conda config --show channels` - To Install a Package in Conda Using a Channel Name: `conda install -c conda-forge matplotlib` - This is to install `matplotlib` via `conda-forge` channel - +#### `conda-forge` channel +- There is a **community-led** effort (Conda-Forge) to make conda packaging & distribution entirely open. +- `conda-forge` that contains tools for the creation of community-driven builds for any package. Packages are maintained in the open via github, with binaries automatically built using free CI tools like TravisCI for Mac OSX builds, AppVeyor for Windows builds, and CircleCI for Linux builds. All the metadata for each package lives in a Github repository, and package updates are accomplished through merging a Github pull request (here is an example of what a package update looks like in conda-forge). ## Why should you use Conda ? - Conda provides **pre-built** packages or binaries (which generally avoids the need to deal with compiling packages from source). From 973ffe1f4756433c92b7c4995a6ae6c68ff3b428 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Wed, 25 Oct 2023 06:30:22 +0800 Subject: [PATCH 108/150] add more info for conda --- docs/conda.md | 34 ++++++++++++++++++---------------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/docs/conda.md b/docs/conda.md index 22ad2c4..a331bc4 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -114,30 +114,29 @@ source ~/miniforge3/bin/activate - List all existing environments: `conda env list` ### Create environments +- `conda create` + - `--name` or `-n` name of the env. + - If not specify `--prefix`, the new environment will be created by Conda at `/users//miniforge3/envs/` + ```shell + conda create --name env-name --file environment.yml + conda activate env-name + conda deactivate + ``` -#### Method 1 - -```shell -conda create --name env-name --file environment.yml -conda activate env-name -conda deactivate -``` - -- The environments created by Conda is always located in `/users//miniforge3/envs/` - -#### Method 2: custom env location (preferred) +- `--prefix` custom env location (preferred) ```shell conda create --prefix ./venv python=3.8 --file environment.yml conda activate ./venv conda deactivate ``` - +- `--file` to specify the `environment.yml` #### `environment.yml` - -- `tensorflow-deps` will need to be installed by `conda` via `apple` channel -- `scikit-learn` will be installed by `conda` via `conda-forge` channel -- `tensorflow-macos` will need `pip` install via **PyPI** +- duplicate your environment using **YAML file** `conda env export > my_environment.yml` +- to recreate the environment now use `conda create -f environment.yml` + - `tensorflow-deps` will need to be installed by `conda` via `apple` channel + - `scikit-learn` will be installed by `conda` via `conda-forge` channel + - `tensorflow-macos` will need `pip` install via **PyPI** ```yaml name: tensorflow @@ -178,3 +177,6 @@ python -m pip install tensorflow-macos ```shell python -m pip install tensorflow-metal ``` + +## References +- [Conda: Myths and Misconceptions](https://jakevdp.github.io/blog/2016/08/25/conda-myths-and-misconceptions/) \ No newline at end of file From c0f5055aa5f53886505e32f67106cfd2fdb5f421 Mon Sep 17 00:00:00 2001 From: CodeXploreRePo Date: Wed, 25 Oct 2023 20:28:22 +0800 Subject: [PATCH 109/150] conda update --- docs/conda.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/conda.md b/docs/conda.md index a331bc4..854ca4c 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -9,7 +9,8 @@ ### Pip vs Conda -- **Pip** is the Python Packaging Authority’s recommended tool for installing packages from the Python Package Index (PyPI). +- **Pip**, which stands for **P**ip **I**nstalls **P**ackages, is Python's officially-sanctioned package manager, and is most commonly used to install packages published on the Python Package Index (PyPI). + - Both **pip** and **PyPI** are governed and supported by the Python Packaging Authority (PyPA). - Pip installs Python software packaged as _wheels_ or _source_ distributions. #### Difference between Conda and Pip @@ -64,7 +65,7 @@ conda create --name anaconda-env-202302 anaconda=2023.02 - `miniforge` is the **community** (`conda-forge`) driven minimalistic conda installer. Subsequent package installations come thus from conda-forge channel. - `miniconda` is the **Anaconda** (company) driven minimalistic conda installer. Subsequent package installations come from the **anaconda channels** (default or otherwise). -- Summary: Miniforge-installed conda is the same as Miniconda-installed conda, except that it uses the conda-forge channel (and only the conda-forge channel) as the default channel. +- Summary: Both Miniforge and Miniconda are minimalistic conda installers, except that Miniforge uses the conda-forge channel (and only the conda-forge channel) as the default channel. ### Conda Channel From 48faaf74e6497eb32136b0bc27fd1daa4a2aa757 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Thu, 26 Oct 2023 22:33:01 +0800 Subject: [PATCH 110/150] update conda commands --- .../img/conda_miniconda_anaconda.webp | Bin daily_knowledge.md | 15 +++++++++++++ docs/conda.md | 21 ++++++++++++++++++ 3 files changed, 36 insertions(+) rename {assests => assets}/img/conda_miniconda_anaconda.webp (100%) diff --git a/assests/img/conda_miniconda_anaconda.webp b/assets/img/conda_miniconda_anaconda.webp similarity index 100% rename from assests/img/conda_miniconda_anaconda.webp rename to assets/img/conda_miniconda_anaconda.webp diff --git a/daily_knowledge.md b/daily_knowledge.md index c6872cf..ea512c5 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -34,6 +34,21 @@ dependencies: - tensorflow-metal ``` +- Conda env starts: + +```shell +# create env +conda create --prefix ./venv python=3.8 --file environment.yml +conda activate ./venv +conda deactivate + +# install package from requirements.txt +conda install --file requirements.txt +# export to requirements.txt so that can install via pip in virtualenv/venv environment + +pip list --format=freeze > requirements.txt +``` + ## Day 6 - Number: `1000000` can be written as `1_000_000` for the ease of visualisation diff --git a/docs/conda.md b/docs/conda.md index 33b30c1..abfc51a 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -94,6 +94,7 @@ source ~/miniforge3/bin/activate ## Conda commands - List all existing environments: `conda env list` +- `conda list` gives you list of packages used for the environment ### Create environments @@ -115,6 +116,26 @@ conda activate ./venv conda deactivate ``` +#### Install from `requirements.txt` + +- `conda install --file requirements.txt` + +#### Export enviroment to `requirements.txt` for `pip` + +```shell +conda activate +conda install pip # only install if pip in conda env is not avail, can check which pip +pip list --format=freeze > requirements.txt +``` + +- Then use the resulting `requirements.txt` to create a `pip` virtual environment: + +```shell +python3 -m venv env +source env/bin/activate +pip install -r requirements.txt +``` + #### `environment.yml` - `tensorflow-deps` will need to be installed by `conda` via `apple` channel From 20f230aa35d4f375e3eea0ed95aa10b299b416ad Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Sun, 29 Oct 2023 18:35:47 +0800 Subject: [PATCH 111/150] update list dk --- daily_knowledge.md | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 51a8943..87406df 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,14 +1,25 @@ # 2023 +## Day 8 + +### List + +- Copy a list: `copied_list = a_list[:]` + - Leverage on `copy` module + ```Python + import copy + copied_list = copy.deepcopy(a_list) + ``` + ## Day 7 ### Conda - Conda is an open source **package** + **environment** manager - Conda vs (Miniconda & Anaconda): - - *Conda* is a **package manager** & *Conda* is tightly coupled to two software distributions: *Anaconda* and *Miniconda*. - - *Anaconda* is a full distribution of the central software in the PyData ecosystem, and includes Python itself along with binaries for several hundred third-party open-source projects. - - *Miniconda* is essentially an installer for an empty conda environment, containing only Conda and its dependencies, so that you can install what you need from scratch. + - _Conda_ is a **package manager** & _Conda_ is tightly coupled to two software distributions: _Anaconda_ and _Miniconda_. + - _Anaconda_ is a full distribution of the central software in the PyData ecosystem, and includes Python itself along with binaries for several hundred third-party open-source projects. + - _Miniconda_ is essentially an installer for an empty conda environment, containing only Conda and its dependencies, so that you can install what you need from scratch. - Recommended conda installation in PC: Miniconda - Miniconda and Miniforge: - **Miniforge**-installed conda is the same as Miniconda-installed conda, except that it uses the conda-forge channel (and only the conda-forge channel) as the default channel. @@ -240,7 +251,7 @@ ax.set_xticks(ax.get_xticks(), ax.get_xticklabels(), rotation=45, ha='right') ### Pandas - `df.loc[:, "col"] = df["col"].map(mapping)` re-assign the updated value to originial column without any error -- `pd.set_option('max_columns', 200)` to view all the columns in the df when `df.head()` +- `pd.options.display.max_columns` to view all the columns in the df when `df.head()` #### `groupby` From 5c0e131edcb476a63d03381e90bd48ac737b6735 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Mon, 30 Oct 2023 22:16:22 +0800 Subject: [PATCH 112/150] add remove venv to conda.md --- docs/conda.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/conda.md b/docs/conda.md index 1602997..823d9d1 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -210,6 +210,11 @@ python -m pip install tensorflow-macos python -m pip install tensorflow-metal ``` +### Remove environments + +- `conda remove -n ENV_NAME --all` +- `conda remove -p /path/to/venv` + ## References - [Conda: Myths and Misconceptions](https://jakevdp.github.io/blog/2016/08/25/conda-myths-and-misconceptions/) From 8da230209b27ec9918e0691a63aa36d7de44787b Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Mon, 30 Oct 2023 22:42:49 +0800 Subject: [PATCH 113/150] update conda env creation --- daily_knowledge.md | 10 ++++++++-- docs/conda.md | 24 +++++++++++++++--------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 87406df..73f49db 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -45,11 +45,11 @@ dependencies: - tensorflow-metal ``` -- Conda env starts: +#### Conda env creation: ```shell # create env -conda create --prefix ./venv python=3.8 --file environment.yml +conda create --prefix ./venv python=3.8 --file requirements.txt conda activate ./venv conda deactivate @@ -60,6 +60,12 @@ conda install --file requirements.txt pip list --format=freeze > requirements.txt ``` +#### `conda create --file requirements.txt` vs `conda env create --file environment.yml` + +- `conda create --file` expects a `requirements.txt`, not an `environment.yml`, each line in the given file is treated as a package-reference +- `conda env create` to create an environment from a given `environment.yml` + - Command: `conda env create --name tensorflow --file environment.yml` + ## Day 6 - Number: `1000000` can be written as `1_000_000` for the ease of visualisation diff --git a/docs/conda.md b/docs/conda.md index 823d9d1..00473c3 100644 --- a/docs/conda.md +++ b/docs/conda.md @@ -121,25 +121,31 @@ source ~/miniforge3/bin/activate ### Create environments -- `conda create` +#### `conda create` - - `--name` or `-n` name of the env. - - If not specify `--prefix`, the new environment will be created by Conda at `/users//miniforge3/envs/` +- `--name` or `-n` name of the env. + - If not specify `--prefix`, the new environment will be created by Conda at `/users//miniforge3/envs/` - ```shell - conda create --name env-name --file environment.yml - conda activate env-name - conda deactivate - ``` +```shell +conda create --name env-name --file requirements.txt +conda activate env-name +conda deactivate +``` - `--prefix` custom env location (preferred) ```shell -conda create --prefix ./venv python=3.8 --file environment.yml +conda create --prefix ./venv python=3.8 --file requirements.txt conda activate ./venv conda deactivate ``` +#### `conda env create` + +- `conda create --file` expects a `requirements.txt`, not an `environment.yml`, each line in the given file is treated as a package-reference +- `conda env create` to create an environment from a given `environment.yml` + - Command: `conda env create --name tensorflow --file environment.yml` + #### Install from `requirements.txt` - `conda install --file requirements.txt` From 0cf16d02f2aa47fba7a15de5327defb943371986 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 31 Oct 2023 21:03:04 +0800 Subject: [PATCH 114/150] Update daily_knowledge.md --- daily_knowledge.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 73f49db..6de84bc 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -2,8 +2,11 @@ ## Day 8 -### List +### `os.path` + +- To read the path separator of the env: `os.path.sep` +### List - Copy a list: `copied_list = a_list[:]` - Leverage on `copy` module ```Python From 5d917636ed6368b54220dd57849c572bb8a0f0ba Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Tue, 31 Oct 2023 21:03:31 +0800 Subject: [PATCH 115/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 6de84bc..58d183d 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -4,7 +4,7 @@ ### `os.path` -- To read the path separator of the env: `os.path.sep` +- To read the path separator of the env `os.path.sep # return '/' if using Linux` ### List - Copy a list: `copied_list = a_list[:]` From fefbd58caceace31b367add269985b46d9d739c5 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Wed, 1 Nov 2023 17:47:04 +0800 Subject: [PATCH 116/150] update the args --- basics/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/basics/README.md b/basics/README.md index fb31af8..93e414d 100644 --- a/basics/README.md +++ b/basics/README.md @@ -25,6 +25,11 @@ parser.add_argument('-n', '--name', metavar='user_name', args = parser.parse_args() print('Hello, ' + args.name + '!') + +# use var() to make args as the dict +args = var(parser.parse_args()) +print('Hello, ' + args['name'] + '!') + ``` | Type | Example | Required | Default | From 562d793a22d852deddd554323f60803a19f9043f Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Fri, 10 Nov 2023 00:39:35 +0700 Subject: [PATCH 117/150] update python subprocess --- daily_knowledge.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 58d183d..5615967 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -2,11 +2,25 @@ ## Day 8 +- `bytes("yes", "utf-8")` convert string to binary objects: + +### `subprocess.Popen` to send Linux command + +```Python +from subprocess import Popen, Pipe + +execute = Popen("scp -i /location_in_machine_A/to/private/key -v -P 64022 file_path machineB@ip_address:/path/to/store/inB/".split(), stdout=PIPE, stdin=PIPE, stderr=PIPE) +execute.stdin.write(bytes("yes", "utf-8")) # to send the "yes" command +execute.communicate()[0] + +``` + ### `os.path` -- To read the path separator of the env `os.path.sep # return '/' if using Linux` +- To read the path separator of the env `os.path.sep # return '/' if using Linux` ### List + - Copy a list: `copied_list = a_list[:]` - Leverage on `copy` module ```Python From 85a23325da07f27721c67f82464f4aaffe8f83ef Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Fri, 10 Nov 2023 23:13:36 +0700 Subject: [PATCH 118/150] update daily knowledge --- daily_knowledge.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5615967..5fe76fc 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -4,6 +4,16 @@ - `bytes("yes", "utf-8")` convert string to binary objects: +### Relative import + +``` +# example.py +from .abstract import ExampleClass +# if we run this script directly like python src/abc/example.py, we will encounter the issue +``` + +- Soluton: `python -m src.abc.example` or call the `example.py` script outside the `src` + ### `subprocess.Popen` to send Linux command ```Python From 2f3fe249b95a0595bf7a1cc7a7b13a12150ba128 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Wed, 15 Nov 2023 15:15:59 +0700 Subject: [PATCH 119/150] update pathlib --- basics/pathlib_tutorial.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/basics/pathlib_tutorial.py b/basics/pathlib_tutorial.py index e8cbca2..befc817 100644 --- a/basics/pathlib_tutorial.py +++ b/basics/pathlib_tutorial.py @@ -8,7 +8,23 @@ data_path_str = data_path.as_posix() # to create a folder if it is not exist -folder_path = Path('/this/is/the/new/folder') +folder_path = Path("/this/is/the/new/folder") # parents=True -> will create if parent folder is not existed # exist_ok=True -> to ignore the warning if the parent folder is already existed folder_path.mkdir(parents=True, exist_ok=True) + +# glob +""" +data +└── ml-class + └── cnn-audio + ├── bed: *.wav + ├── cat: *.wav + └── happy: *.wav +""" + +data_path = ( + Path("__file__").resolve().parents[1] / "data" / "ml-class" / "cnn-audio" +) +# to loop through all the folder inside "cnn-audio" +audio_files = data_path.glob("*/*.wav") From 6cdc17b4731ed76607fa20ca07b58e7cf06de078 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 6 Dec 2023 22:07:14 +0800 Subject: [PATCH 120/150] Update dotvenv.md --- basics/dotvenv.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/basics/dotvenv.md b/basics/dotvenv.md index aef373e..1a47edf 100644 --- a/basics/dotvenv.md +++ b/basics/dotvenv.md @@ -2,7 +2,7 @@ - Installation: `pip install python-dotenv==1.0.0` - Config file stores in `.env` file ```shell -HUGGINGFACEHUB_API_TOKEN="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" +HUGGINGFACEHUB_API_TOKEN="" ``` - Load environmental variables ```Python From e63299243504cd4e4d682f25f05b24192a9bcf71 Mon Sep 17 00:00:00 2001 From: CodeXplore Date: Wed, 6 Dec 2023 22:07:52 +0800 Subject: [PATCH 121/150] Update daily_knowledge.md --- daily_knowledge.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5fe76fc..a38db8c 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -352,7 +352,7 @@ Name: b, dtype: object - Config file stores in `.env` file ```shell -HUGGINGFACEHUB_API_TOKEN="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" +HUGGINGFACEHUB_API_TOKEN="" ``` - Load environmental variables From 4c1d6d33ffaf78ac8048804d99c1b71974ea615d Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Wed, 20 Dec 2023 16:43:23 +0700 Subject: [PATCH 122/150] update the color map for matplotlib --- daily_knowledge.md | 27 +++++++++++++++++++++++++++ requirements.txt | 3 +++ 2 files changed, 30 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 5fe76fc..b9fd305 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -4,6 +4,33 @@ - `bytes("yes", "utf-8")` convert string to binary objects: +### Matplotlib + +- Color Map + +```Python +cmap = plt.get_cmap("viridis") +fig = plt.figure(figsize=(8, 6)) +m1 = plt.scatter(X_train, y_train, color=cmap(0.9), s=10) +m2 = plt.scatter(X_test, y_test, color=cmap(0.5), s=10) +``` + +- Plot 2 charts on the same figure with share x-axis + +```Python +fig, ax1 = plt.subplots() + +ax1.hist(housing["housing_median_age"], bins=50) + +ax2 = ax1.twinx() # key: create a twin axis that shares the same x-axis +color = "blue" +ax2.plot(ages, rbf1, color=color, label="gamma = 0.10") +ax2.tick_params(axis='y', labelcolor=color) +ax2.set_ylabel("Age similarity", color=color) # second y-axis's measurement + +plt.show() +``` + ### Relative import ``` diff --git a/requirements.txt b/requirements.txt index 77005ea..ff786b3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -2,3 +2,6 @@ attrs black pydantic pyaml +tqdm +librosa +wandb From 0a65f1ef6e79dd09e98ccf19ab43799b07eddae9 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Sat, 13 Jan 2024 17:24:45 +0800 Subject: [PATCH 123/150] update dk for sys module --- daily_knowledge.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 44e425e..9e11b4d 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,33 @@ # 2023 +## Day 9 + +### `sys` module + +- The kernel knows to execute this script with a **python** interpreter with the shebang `#!/usr/bin/env python` +- `sys.argv[0]` return name of the script +- `sys.argv[1:]` return the arguments parsed to the script + +```Python +############################# +# in the python_script.py # +############################# +#!/usr/bin/env python +import sys +for arg in reversed(sys.argv[1:]): + print(arg) + +############################# +# in the interactive shell # +############################# +bash-5.2$ chmod +x python_script.py +bash-5.2$ ./python_script.py a b c +# Running: ./python_script.py +# c +# b +# a +``` + ## Day 8 - `bytes("yes", "utf-8")` convert string to binary objects: From c90f19a148d895f81e0d5624a820401c919f5a00 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Tue, 6 Feb 2024 18:19:17 +0700 Subject: [PATCH 124/150] update subprocess --- basics/README.md | 4 +- .../google_colab_tutorial.ipynb | 0 basics/notebooks/subprocess.ipynb | 277 ++++++++++++++++++ basics/subprocess_tutorial.py | 1 - daily_knowledge.md | 40 +++ 5 files changed, 319 insertions(+), 3 deletions(-) rename basics/{ => notebooks}/google_colab_tutorial.ipynb (100%) create mode 100644 basics/notebooks/subprocess.ipynb delete mode 100644 basics/subprocess_tutorial.py diff --git a/basics/README.md b/basics/README.md index 93e414d..0bf6f8a 100644 --- a/basics/README.md +++ b/basics/README.md @@ -3,9 +3,9 @@ ## Topics - [`*args` and `**kwargs`](./args_kwargs_tutorial.py) -- [Google Colab](./google_colab_tutorial.ipynb) +- [Google Colab](./notebooks/google_colab_tutorial.ipynb) - [Pathlib](./pathlib_tutorial.py) -- [Subprocess](./subprocess_tutorial.py) +- [Subprocess](./notebooks/subprocess.ipynb) - [YAML](./yaml/README.md) ## Argument Parser diff --git a/basics/google_colab_tutorial.ipynb b/basics/notebooks/google_colab_tutorial.ipynb similarity index 100% rename from basics/google_colab_tutorial.ipynb rename to basics/notebooks/google_colab_tutorial.ipynb diff --git a/basics/notebooks/subprocess.ipynb b/basics/notebooks/subprocess.ipynb new file mode 100644 index 0000000..180151e --- /dev/null +++ b/basics/notebooks/subprocess.ipynb @@ -0,0 +1,277 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Subprocess\n", + "- `subprocess.run` is a higher-level wrapper around Popen that is intended to be more convenient to use.\n", + " - Usage: to run a command and capture its output\n", + "- `subprocess.call` \n", + " - Usage: to run a command and check the return code, but do not need to capture the output.\n", + "- `subprocess.Popen` is a lower-level interface to running subprocesses\n", + " - Usage: if you need more control over the process, such as interacting with its input and output streams." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## subprocess.run()\n", + "- `subprocess.run()` method is a convenient way to run a subprocess and wait for it to complete.\n", + " - Once the subprocess is started, the `run()` method blocks until the subprocess completes and returns a `CompletedProcess` object\n", + "- `subprocess.run()`'s input arguments:\n", + " - `args`: The command to run and its arguments, passed as a **list of strings**.\n", + " - `capture_output`: When set to True, will capture the standard output and standard error.\n", + " - `text`: when set to True, will return the stdout and stderr as string, otherwise as bytes `b'/Users/codexplore/Developer/repos/`.\n", + " - `check`: \n", + " - when check is set to True, the function will check the return code of the command and raise a `CalledProcessError` exception if the return code is non-zero. \n", + " - when check is set to False (default), the function will not check the return code and will not raise an exception, even if the command fails.\n", + " - `timeout`: A value in seconds that specifies how long to wait for the subprocess to complete before timing out.\n", + "- `subprocess.run()`` method also returns a `CompletedProcess` object, which contains the following attributes:\n", + " - `args`: The command and arguments that were run.\n", + " - `returncode`: The return code of the subprocess.\n", + " - `stdout`: The standard output of the subprocess, as a bytes object.\n", + " - `stderr`: The standard error of the subprocess, as a bytes object.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import subprocess" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "total 40\n", + "drwxr-xr-x 4 codexplore staff 128 Feb 6 17:32 \u001b[1m\u001b[36m.\u001b[m\u001b[m\n", + "drwxr-xr-x@ 8 codexplore staff 256 Feb 6 17:32 \u001b[1m\u001b[36m..\u001b[m\u001b[m\n", + "-rw-r--r--@ 1 codexplore staff 18414 Oct 22 10:29 google_colab_tutorial.ipynb\n", + "-rw-r--r-- 1 codexplore staff 0 Feb 6 17:32 subprocess.ipynb\n" + ] + }, + { + "data": { + "text/plain": [ + "CompletedProcess(args=['ls', '-la'], returncode=0)" + ] + }, + "execution_count": 4, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "subprocess.run([\"ls\", \"-la\"])" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": {}, + "outputs": [], + "source": [ + "result = subprocess.run([\"pwd\"], capture_output=True, text=True)" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "('/Users/codexplore/Developer/repos/python/basics/notebooks\\n', '')" + ] + }, + "execution_count": 33, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result.stdout, result.stderr" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0" + ] + }, + "execution_count": 34, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "result.returncode" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## subprocess.call()" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Python 3.9.6\n", + "Command executed successfully.\n" + ] + } + ], + "source": [ + "return_code = subprocess.call([\"python3\", \"--version\"])\n", + "\n", + "if return_code == 0:\n", + " print(\"Command executed successfully.\")\n", + "else:\n", + " print(\"Command failed with return code\", return_code)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## subprocess.Popen()\n", + "- `Popen` allows you to start a new process and interact with its standard input, output, and error streams. It returns a handle to the running process that can be used to wait for the process to complete, check its return code, or terminate it.\n", + "- The Popen class has several methods that allow you to interact with the process, such as `communicate(`), `poll()`, `wait()`, `terminate()`, and `kill()`." + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Python 3.9.6\n", + "\n" + ] + } + ], + "source": [ + "import subprocess\n", + "\n", + "p = subprocess.Popen([\"python3\", \"--version\"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True)\n", + "\n", + "output, errors = p.communicate()\n", + "\n", + "print(output)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Subprocess `PIPE`\n", + "- A `PIPE` is a unidirectional communication channel that connects one process's standard output to another's standard input. " + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ouptut:\n", + "google_colab_tutorial.ipynb\n", + "subprocess.ipynb\n", + "\n", + "Error : None\n" + ] + } + ], + "source": [ + "# creates a pipe that connects the output of the `ls` command to the input of the `grep` command,\n", + "ls_process = subprocess.Popen([\"ls\"], stdout=subprocess.PIPE, text=True)\n", + "\n", + "grep_process = subprocess.Popen([\"grep\", \".ipynb\"], stdin=ls_process.stdout, stdout=subprocess.PIPE, text=True)\n", + "\n", + "output, error = grep_process.communicate()\n", + "\n", + "print(f\"Ouptut:\\n{output}\")\n", + "print(f\"Error : {error}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "google_colab_tutorial.ipynb\n", + "subprocess.ipynb\n", + "\n" + ] + } + ], + "source": [ + "result = subprocess.run([\"ls\"], stdout=subprocess.PIPE)\n", + "\n", + "print(result.stdout.decode()) # decode() to convert from bytes to strings\n" + ] + }, + { + "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.9.6" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/basics/subprocess_tutorial.py b/basics/subprocess_tutorial.py deleted file mode 100644 index 54d5ee6..0000000 --- a/basics/subprocess_tutorial.py +++ /dev/null @@ -1 +0,0 @@ -# Link: https://www.simplilearn.com/tutorials/python-tutorial/subprocess-in-python \ No newline at end of file diff --git a/daily_knowledge.md b/daily_knowledge.md index 9e11b4d..30492eb 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -2,6 +2,46 @@ ## Day 9 +### `subprocess` module + +- `subprocess.run` is a higher-level wrapper around Popen that is intended to be more convenient to use. + - Usage: to run a command and capture its output +- `subprocess.call` + - Usage: to run a command and check the return code, but do not need to capture the output. +- `subprocess.Popen` is a lower-level interface to running subprocesses + + - Usage: if you need more control over the process, such as interacting with its input and output streams. + +- A `PIPE` is a unidirectional communication channel that connects one process's standard output to another's standard input. + +```Python +# creates a pipe that connects the output of the `ls` command to the input of the `grep` command, +ls_process = subprocess.Popen(["ls"], stdout=subprocess.PIPE, text=True) + +grep_process = subprocess.Popen(["grep", ".ipynb"], stdin=ls_process.stdout, stdout=subprocess.PIPE, text=True) + +output, error = grep_process.communicate() + +print(f"Ouptut:\n{output}") +print(f"Error : {error}") + +# Ouptut: +# google_colab_tutorial.ipynb +# subprocess.ipynb +# +# Error : None +result = subprocess.run(["ls"], stdout=subprocess.PIPE) + +print(result.stdout.decode()) # decode() to convert from bytes to strings +# google_colab_tutorial.ipynb +# subprocess.ipynb +``` + +#### `subprocess` vs `os.system` + +- `subprocess.run` is generally more flexible than `os.system` (you can get the stdout, stderr, the "real" status code, better error handling, etc.) +- Even the [documentation for `os.system`](https://docs.python.org/3/library/os.html#os.system) recommends using subprocess instead. + ### `sys` module - The kernel knows to execute this script with a **python** interpreter with the shebang `#!/usr/bin/env python` From 6c249b42ab9f6837dc505516fa678522e882a143 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Thu, 22 Feb 2024 21:45:33 +0800 Subject: [PATCH 125/150] update the typing Annotated, and float decimal conversion --- daily_knowledge.md | 55 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/daily_knowledge.md b/daily_knowledge.md index 30492eb..97653a0 100644 --- a/daily_knowledge.md +++ b/daily_knowledge.md @@ -1,5 +1,60 @@ # 2023 +## Day 10 + +### Pandas + +#### `.read_csv()` by chunk + +- If the csv file is large, can consider to read by chunk + +```Python +df_iter = pd.read_csv(file_path, iterator=True, chunksize=100000) +df = next(df_iter) +``` + +### Python + +#### typing `Annotated` + +- `Annotated` in python allows developers to declare the type of a reference and provide additional information related to it. + +```Python +from typing_extensions import Annotated +# This tells that "name" is of type "str" and that "name[0]" is a capital letter. +name = Annotated[str, "first letter is capital"] +``` + +- Fast API examples: + ```Python + from fastapi import Query + def read_items(q: Annotated[str, Query(max_length=50)]) + ``` + - The parameter `q` is of type `str` with a maximum length of 50. + +#### Float to Decimal conversion + +- Convert `float` directly to `Decimal` constructor introduces a rounding error. + +```Python +from decimal import Decimal +x = 0.1234 +Decimal(x) +# Decimal('0.12339999999999999580335696691690827719867229461669921875') +``` + +- **Solution**: to convert a float to a string before passing it to the constructor. + - You also can round the float before converting it to string + +```Python +Decimal(str(x)) +# Decimal('0.1234') +Decimal(str(round(x,2))) +# Decimal('0.12') +``` + +- + ## Day 9 ### `subprocess` module From 65c070c92bf4b46dc5648ad266ddf3bb76e12ab2 Mon Sep 17 00:00:00 2001 From: CodexploreRepo Date: Thu, 22 Feb 2024 21:50:16 +0800 Subject: [PATCH 126/150] update lru cache --- assets/img/lru_cache_example.png | Bin 0 -> 53745 bytes daily_knowledge.md | 12 ++++++++++++ 2 files changed, 12 insertions(+) create mode 100644 assets/img/lru_cache_example.png diff --git a/assets/img/lru_cache_example.png b/assets/img/lru_cache_example.png new file mode 100644 index 0000000000000000000000000000000000000000..e09c4e221fd48b4ecd85b93ccdc6a62f0f990b9a GIT binary patch literal 53745 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