From b51226fbacd46c1e285b2290529446b760fe0f2c Mon Sep 17 00:00:00 2001 From: <> Date: Wed, 3 Jan 2024 10:50:27 +0000 Subject: [PATCH] Deployed fbf3c72 with MkDocs version: 1.5.3 --- .nojekyll | 0 01_Introduction/01_Introduction.md | 346 + 01_Introduction/index.html | 1852 +++++ .../02_variables_builtin_functions.md | 268 + 02_variables_builtin_functions/index.html | 1545 ++++ 03_operators/03_operators.md | 274 + 03_operators/index.html | 1500 ++++ 04_strings/04_strings.md | 574 ++ 04_strings/index.html | 1960 +++++ 05_lists/05_lists.md | 579 ++ 05_lists/index.html | 2117 ++++++ 06_tuples/06_tuples.md | 221 + 06_tuples/index.html | 1543 ++++ 07_sets/07_sets.md | 383 + 07_sets/index.html | 1788 +++++ 08_dictionaries/08_dictionaries.md | 301 + 08_dictionaries/index.html | 1644 ++++ 09_conditionals/09_conditionals.md | 250 + 09_conditionals/index.html | 1566 ++++ 10_loops/10_loops.md | 424 ++ 10_loops/index.html | 1731 +++++ 11_functions/11_functions.md | 419 + 11_functions/index.html | 1800 +++++ 12_modules/12_modules.md | 305 + 12_modules/index.html | 1706 +++++ .../13_list_comprehension.md | 209 + 13_list_comprehension/index.html | 1405 ++++ .../14_higher_order_functions.md | 370 + 14_higher_order_functions/index.html | 1772 +++++ .../15_python_type_errors.md | 361 + 15_python_type_errors/index.html | 1646 ++++ 16_python_datetime/16_python_datetime.md | 208 + 16_python_datetime/index.html | 1473 ++++ .../17_exception_handling.md | 306 + 17_exception_handling/index.html | 1614 ++++ .../18_regular_expressions.md | 459 ++ 18_regular_expressions/index.html | 1930 +++++ 19_file_handling/19_file_handling.md | 517 ++ 19_file_handling/index.html | 1894 +++++ .../20_python_package_manager.md | 459 ++ 20_python_package_manager/index.html | 1754 +++++ .../21_classes_and_objects.md | 370 + 21_classes_and_objects/index.html | 1693 +++++ 22_web_scraping/22_web_scraping.md | 108 + 22_web_scraping/index.html | 1286 ++++ .../23_virtual_environment.md | 114 + 23_virtual_environment/index.html | 1247 +++ 24_statistics/24_statistics.md | 1237 +++ 24_statistics/index.html | 2075 +++++ 25_pandas/25_pandas.md | 1216 +++ 25_pandas/index.html | 2636 +++++++ 26_python_web/26_python_web.md | 576 ++ 26_python_web/index.html | 1947 +++++ .../27_python_with_mongodb.md | 659 ++ 27_python_with_mongodb/index.html | 1615 ++++ 28_API/28_API.md | 162 + 28_API/index.html | 1228 +++ 29_building_API/29_building_API.md | 502 ++ 29_building_API/index.html | 1759 +++++ 30_conclusions/30_conclusions.md | 40 + 30_conclusions/index.html | 1186 +++ 404.html | 974 +++ assets/favicon.jpg | Bin 0 -> 715300 bytes assets/images/favicon.png | Bin 0 -> 1870 bytes assets/javascripts/bundle.d7c377c4.min.js | 29 + assets/javascripts/bundle.d7c377c4.min.js.map | 7 + assets/javascripts/lunr/min/lunr.ar.min.js | 1 + assets/javascripts/lunr/min/lunr.da.min.js | 18 + assets/javascripts/lunr/min/lunr.de.min.js | 18 + assets/javascripts/lunr/min/lunr.du.min.js | 18 + assets/javascripts/lunr/min/lunr.el.min.js | 1 + assets/javascripts/lunr/min/lunr.es.min.js | 18 + assets/javascripts/lunr/min/lunr.fi.min.js | 18 + assets/javascripts/lunr/min/lunr.fr.min.js | 18 + assets/javascripts/lunr/min/lunr.he.min.js | 1 + assets/javascripts/lunr/min/lunr.hi.min.js | 1 + assets/javascripts/lunr/min/lunr.hu.min.js | 18 + assets/javascripts/lunr/min/lunr.hy.min.js | 1 + assets/javascripts/lunr/min/lunr.it.min.js | 18 + assets/javascripts/lunr/min/lunr.ja.min.js | 1 + assets/javascripts/lunr/min/lunr.jp.min.js | 1 + assets/javascripts/lunr/min/lunr.kn.min.js | 1 + assets/javascripts/lunr/min/lunr.ko.min.js | 1 + assets/javascripts/lunr/min/lunr.multi.min.js | 1 + assets/javascripts/lunr/min/lunr.nl.min.js | 18 + assets/javascripts/lunr/min/lunr.no.min.js | 18 + assets/javascripts/lunr/min/lunr.pt.min.js | 18 + assets/javascripts/lunr/min/lunr.ro.min.js | 18 + assets/javascripts/lunr/min/lunr.ru.min.js | 18 + assets/javascripts/lunr/min/lunr.sa.min.js | 1 + .../lunr/min/lunr.stemmer.support.min.js | 1 + assets/javascripts/lunr/min/lunr.sv.min.js | 18 + assets/javascripts/lunr/min/lunr.ta.min.js | 1 + assets/javascripts/lunr/min/lunr.te.min.js | 1 + assets/javascripts/lunr/min/lunr.th.min.js | 1 + assets/javascripts/lunr/min/lunr.tr.min.js | 18 + assets/javascripts/lunr/min/lunr.vi.min.js | 1 + assets/javascripts/lunr/min/lunr.zh.min.js | 1 + assets/javascripts/lunr/tinyseg.js | 206 + assets/javascripts/lunr/wordcut.js | 6708 +++++++++++++++++ .../workers/search.f886a092.min.js | 42 + .../workers/search.f886a092.min.js.map | 7 + assets/logo.jpg | Bin 0 -> 715300 bytes assets/stylesheets/main.50c56a3b.min.css | 1 + assets/stylesheets/main.50c56a3b.min.css.map | 1 + assets/stylesheets/palette.06af60db.min.css | 1 + .../stylesheets/palette.06af60db.min.css.map | 1 + images/30DaysOfPython_banner3@2x.png | Bin 0 -> 708642 bytes images/adding_on_python_shell.png | Bin 0 -> 55573 bytes images/arithmetic_operators.png | Bin 0 -> 43349 bytes images/assignment_operators.png | Bin 0 -> 52829 bytes images/assignmet_operators.png | Bin 0 -> 60389 bytes images/become_patreon.png | Bin 0 -> 5560 bytes images/builtin-functional-final.png | Bin 0 -> 90806 bytes images/builtin-functions.png | Bin 0 -> 69881 bytes images/builtin-functions_practice.png | Bin 0 -> 122193 bytes images/checking_data_types.png | Bin 0 -> 118913 bytes images/closing_opened_project.png | Bin 0 -> 193301 bytes images/comparison_operators.png | Bin 0 -> 39661 bytes images/exit_from_shell.png | Bin 0 -> 61396 bytes images/fixing_syntax_error.png | Bin 0 -> 71685 bytes images/get_on_browser.png | Bin 0 -> 110900 bytes images/get_on_postman.png | Bin 0 -> 160727 bytes images/helloworld.png | Bin 0 -> 129029 bytes images/help_and_dir_builtin.png | Bin 0 -> 176723 bytes images/how_to_open_project_on_vscode.png | Bin 0 -> 283301 bytes images/http_request_response_cycle.png | Bin 0 -> 28878 bytes images/identity_operators.png | Bin 0 -> 33339 bytes images/indentation.png | Bin 0 -> 87543 bytes images/installing_on_macOS.png | Bin 0 -> 192154 bytes images/installing_on_windows.png | Bin 0 -> 90780 bytes images/invalid_syntax_error.png | Bin 0 -> 60671 bytes images/list_index.png | Bin 0 -> 12849 bytes images/list_negative_indexing.png | Bin 0 -> 12478 bytes images/logical_operators.png | Bin 0 -> 44739 bytes images/maths_on_python_shell.png | Bin 0 -> 129933 bytes images/mongoDB/mongodb-add-user.png | Bin 0 -> 182105 bytes images/mongoDB/mongodb-allow-ip-access.png | Bin 0 -> 171820 bytes images/mongoDB/mongodb-cluster-name.png | Bin 0 -> 183351 bytes images/mongoDB/mongodb-create-uri.png | Bin 0 -> 237085 bytes images/mongoDB/mongodb-creating_database.png | Bin 0 -> 226350 bytes images/mongoDB/mongodb-free.png | Bin 0 -> 217296 bytes images/mongoDB/mongodb-python-driver.png | Bin 0 -> 227240 bytes images/mongoDB/mongodb-register.png | Bin 0 -> 82527 bytes images/mongoDB/mongodb-sandbox.png | Bin 0 -> 239915 bytes images/mongoDB/mongodb-signup-page.png | Bin 0 -> 372722 bytes images/mongoDB/sql-vs-nosql.png | Bin 0 -> 46442 bytes images/opening_project.png | Bin 0 -> 274224 bytes images/opening_python_shell.png | Bin 0 -> 54087 bytes images/pandas-dataframe-1.png | Bin 0 -> 26145 bytes images/pandas-dataframe-2.png | Bin 0 -> 37717 bytes images/pandas-series-1.png | Bin 0 -> 11024 bytes images/pandas-series-2.png | Bin 0 -> 10922 bytes images/pandas-series-3.png | Bin 0 -> 11541 bytes images/paypal_lg.png | Bin 0 -> 4942 bytes images/postman.png | Bin 0 -> 127522 bytes images/python_versio.png | Bin 0 -> 59010 bytes images/regex.png | Bin 0 -> 85172 bytes images/request_response_header.png | Bin 0 -> 256552 bytes images/running_python_script.png | Bin 0 -> 227565 bytes images/strftime.png | Bin 0 -> 124509 bytes images/string_index.png | Bin 0 -> 10542 bytes images/try_except.png | Bin 0 -> 108686 bytes images/tuple_negative_indexing.png | Bin 0 -> 12250 bytes images/tuples_index.png | Bin 0 -> 12753 bytes images/vscode.png | Bin 0 -> 290943 bytes images/vscode_ui.png | Bin 0 -> 248301 bytes images/writing_string_on_shell.png | Bin 0 -> 151112 bytes index.html | 1077 +++ index.md | 10 + search/search_index.json | 1 + sitemap.xml | 158 + sitemap.xml.gz | Bin 0 -> 550 bytes 173 files changed, 72639 insertions(+) create mode 100644 .nojekyll create mode 100644 01_Introduction/01_Introduction.md create mode 100644 01_Introduction/index.html create mode 100644 02_variables_builtin_functions/02_variables_builtin_functions.md create mode 100644 02_variables_builtin_functions/index.html create mode 100644 03_operators/03_operators.md create mode 100644 03_operators/index.html create mode 100644 04_strings/04_strings.md create mode 100644 04_strings/index.html create mode 100644 05_lists/05_lists.md create mode 100644 05_lists/index.html create mode 100644 06_tuples/06_tuples.md create mode 100644 06_tuples/index.html create mode 100644 07_sets/07_sets.md create mode 100644 07_sets/index.html create mode 100644 08_dictionaries/08_dictionaries.md create mode 100644 08_dictionaries/index.html create mode 100644 09_conditionals/09_conditionals.md create mode 100644 09_conditionals/index.html create mode 100644 10_loops/10_loops.md create mode 100644 10_loops/index.html create mode 100644 11_functions/11_functions.md create mode 100644 11_functions/index.html create mode 100644 12_modules/12_modules.md create mode 100644 12_modules/index.html create mode 100644 13_list_comprehension/13_list_comprehension.md create mode 100644 13_list_comprehension/index.html create mode 100644 14_higher_order_functions/14_higher_order_functions.md create mode 100644 14_higher_order_functions/index.html create mode 100644 15_python_type_errors/15_python_type_errors.md create mode 100644 15_python_type_errors/index.html create mode 100644 16_python_datetime/16_python_datetime.md create mode 100644 16_python_datetime/index.html create mode 100644 17_exception_handling/17_exception_handling.md create mode 100644 17_exception_handling/index.html create mode 100644 18_regular_expressions/18_regular_expressions.md create mode 100644 18_regular_expressions/index.html create mode 100644 19_file_handling/19_file_handling.md create mode 100644 19_file_handling/index.html create mode 100644 20_python_package_manager/20_python_package_manager.md create mode 100644 20_python_package_manager/index.html create mode 100644 21_classes_and_objects/21_classes_and_objects.md create mode 100644 21_classes_and_objects/index.html create mode 100644 22_web_scraping/22_web_scraping.md create mode 100644 22_web_scraping/index.html create mode 100644 23_virtual_environment/23_virtual_environment.md create mode 100644 23_virtual_environment/index.html create mode 100644 24_statistics/24_statistics.md create mode 100644 24_statistics/index.html create mode 100644 25_pandas/25_pandas.md create mode 100644 25_pandas/index.html create mode 100644 26_python_web/26_python_web.md create mode 100644 26_python_web/index.html create mode 100644 27_python_with_mongodb/27_python_with_mongodb.md create mode 100644 27_python_with_mongodb/index.html create mode 100644 28_API/28_API.md create mode 100644 28_API/index.html create mode 100644 29_building_API/29_building_API.md create mode 100644 29_building_API/index.html create mode 100644 30_conclusions/30_conclusions.md create mode 100644 30_conclusions/index.html create mode 100644 404.html create mode 100644 assets/favicon.jpg create mode 100644 assets/images/favicon.png create mode 100644 assets/javascripts/bundle.d7c377c4.min.js create mode 100644 assets/javascripts/bundle.d7c377c4.min.js.map create mode 100644 assets/javascripts/lunr/min/lunr.ar.min.js create mode 100644 assets/javascripts/lunr/min/lunr.da.min.js create mode 100644 assets/javascripts/lunr/min/lunr.de.min.js create mode 100644 assets/javascripts/lunr/min/lunr.du.min.js create mode 100644 assets/javascripts/lunr/min/lunr.el.min.js create mode 100644 assets/javascripts/lunr/min/lunr.es.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.fr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.he.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hu.min.js create mode 100644 assets/javascripts/lunr/min/lunr.hy.min.js create mode 100644 assets/javascripts/lunr/min/lunr.it.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ja.min.js create mode 100644 assets/javascripts/lunr/min/lunr.jp.min.js create mode 100644 assets/javascripts/lunr/min/lunr.kn.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ko.min.js create mode 100644 assets/javascripts/lunr/min/lunr.multi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.nl.min.js create mode 100644 assets/javascripts/lunr/min/lunr.no.min.js create mode 100644 assets/javascripts/lunr/min/lunr.pt.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ro.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ru.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sa.min.js create mode 100644 assets/javascripts/lunr/min/lunr.stemmer.support.min.js create mode 100644 assets/javascripts/lunr/min/lunr.sv.min.js create mode 100644 assets/javascripts/lunr/min/lunr.ta.min.js create mode 100644 assets/javascripts/lunr/min/lunr.te.min.js create mode 100644 assets/javascripts/lunr/min/lunr.th.min.js create mode 100644 assets/javascripts/lunr/min/lunr.tr.min.js create mode 100644 assets/javascripts/lunr/min/lunr.vi.min.js create mode 100644 assets/javascripts/lunr/min/lunr.zh.min.js create mode 100644 assets/javascripts/lunr/tinyseg.js create mode 100644 assets/javascripts/lunr/wordcut.js create mode 100644 assets/javascripts/workers/search.f886a092.min.js create mode 100644 assets/javascripts/workers/search.f886a092.min.js.map create mode 100644 assets/logo.jpg create mode 100644 assets/stylesheets/main.50c56a3b.min.css create mode 100644 assets/stylesheets/main.50c56a3b.min.css.map create mode 100644 assets/stylesheets/palette.06af60db.min.css create mode 100644 assets/stylesheets/palette.06af60db.min.css.map create mode 100644 images/30DaysOfPython_banner3@2x.png create mode 100644 images/adding_on_python_shell.png create mode 100644 images/arithmetic_operators.png create mode 100644 images/assignment_operators.png create mode 100644 images/assignmet_operators.png create mode 100644 images/become_patreon.png create mode 100644 images/builtin-functional-final.png create mode 100644 images/builtin-functions.png create mode 100644 images/builtin-functions_practice.png create mode 100644 images/checking_data_types.png create mode 100644 images/closing_opened_project.png create mode 100644 images/comparison_operators.png create mode 100644 images/exit_from_shell.png create mode 100644 images/fixing_syntax_error.png create mode 100644 images/get_on_browser.png create mode 100644 images/get_on_postman.png create mode 100644 images/helloworld.png create mode 100644 images/help_and_dir_builtin.png create mode 100644 images/how_to_open_project_on_vscode.png create mode 100644 images/http_request_response_cycle.png create mode 100644 images/identity_operators.png create mode 100644 images/indentation.png create mode 100644 images/installing_on_macOS.png create mode 100644 images/installing_on_windows.png create mode 100644 images/invalid_syntax_error.png create mode 100644 images/list_index.png create mode 100644 images/list_negative_indexing.png create mode 100644 images/logical_operators.png create mode 100644 images/maths_on_python_shell.png create mode 100644 images/mongoDB/mongodb-add-user.png create mode 100644 images/mongoDB/mongodb-allow-ip-access.png create mode 100644 images/mongoDB/mongodb-cluster-name.png create mode 100644 images/mongoDB/mongodb-create-uri.png create mode 100644 images/mongoDB/mongodb-creating_database.png create mode 100644 images/mongoDB/mongodb-free.png create mode 100644 images/mongoDB/mongodb-python-driver.png create mode 100644 images/mongoDB/mongodb-register.png create mode 100644 images/mongoDB/mongodb-sandbox.png create mode 100644 images/mongoDB/mongodb-signup-page.png create mode 100644 images/mongoDB/sql-vs-nosql.png create mode 100644 images/opening_project.png create mode 100644 images/opening_python_shell.png create mode 100644 images/pandas-dataframe-1.png create mode 100644 images/pandas-dataframe-2.png create mode 100644 images/pandas-series-1.png create mode 100644 images/pandas-series-2.png create mode 100644 images/pandas-series-3.png create mode 100644 images/paypal_lg.png create mode 100644 images/postman.png create mode 100644 images/python_versio.png create mode 100644 images/regex.png create mode 100644 images/request_response_header.png create mode 100644 images/running_python_script.png create mode 100644 images/strftime.png create mode 100644 images/string_index.png create mode 100644 images/try_except.png create mode 100644 images/tuple_negative_indexing.png create mode 100644 images/tuples_index.png create mode 100644 images/vscode.png create mode 100644 images/vscode_ui.png create mode 100644 images/writing_string_on_shell.png create mode 100644 index.html create mode 100644 index.md create mode 100644 search/search_index.json create mode 100644 sitemap.xml create mode 100644 sitemap.xml.gz diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 0000000..e69de29 diff --git a/01_Introduction/01_Introduction.md b/01_Introduction/01_Introduction.md new file mode 100644 index 0000000..39bbd8d --- /dev/null +++ b/01_Introduction/01_Introduction.md @@ -0,0 +1,346 @@ +# 01 介绍 + +Python 是一种用于通用编程的高级编程语言。它是一种开源、解释型、面向对象的编程语言。Python 是由荷兰程序员Guido van Rossum创建的。Python编程语言的名称取自英国的一个喜剧系列,_Monty Python's Flying Circus_。第一个版本于1991年2月20日发布。 + +## 为什么选择Python? + +它是一种非常接近人类语言的编程语言,因此易于学习和使用。 +Python被各个行业和公司(包括Google)使用。它已经被用于开发Web应用程序、桌面应用程序、系统管理和机器学习库。Python在数据科学和机器学习社区中得到了高度的接受。我希望这足以说服您开始学习Python。Python正在吞噬这个世界,您可以在它吞噬您之前击败它。 + +## 环境设置 + +### 安装Python + +要运行Python脚本,您需要安装Python。让我们[下载](https://www.python.org/) Python。 +如果您是Windows用户,请点击红色圈中的按钮。 + +[![installing on Windows](./images/installing_on_windows.png)](https://www.python.org/) + +如果您是macOS用户。请点击红色圈中的按钮。 + +[![installing on Windows](./images/installing_on_macOS.png)](https://www.python.org/) + +要检查Python是否已安装,请在您的设备终端上编写以下命令。 + +```shell +python --version +``` + +![Python版本](./images/python_versio.png) + +从终端中可以看到,我目前使用的是 _Python 3.7.5_ 版本。您的Python版本可能与我的不同,但应为3.6或更高版本。如果您能看到Python版本,那么恭喜您,Python已经安装在您的计算机上。继续下一节。 + +### Python Shell + +Python是一种解释型脚本语言,因此不需要编译。这意味着它逐行执行代码。Python附带了一个名为 _Python Shell(Python交互式Shell)_ 的工具。它用于执行单个Python命令并获取结果。 + +Python Shell 等待来自用户的Python代码。当您输入代码时,它会解释代码并在下一行显示结果。 +打开您的终端或命令提示符(cmd)并键入: + +```shell +python +``` + +![Python脚本Shell](./images/opening_python_shell.png) + +Python交互式shell已经打开,并等待您编写Python代码(Python脚本)。您将在此符号 >>> 旁边编写您的Python脚本,然后点击Enter。 +让我们在Python脚本Shell上编写我们的第一个脚本。 + +![Python脚本在Python Shell上](./images/adding_on_python_shell.png) + +干得好,您在Python交互式Shell上编写了您的第一个Python脚本。我们如何关闭Python交互式Shell? +要关闭Shell,在此符号 >> 旁边写入 **exit()** 命令并按Enter。 + +![从Python Shell退出](./images/exit_from_shell.png) + +现在,您知道如何打开Python交互式Shell以及如何退出。 + +只要您编写Python能理解的脚本,Python就会给您返回结果,否则它会返回错误。让我们故意犯一个错误,看看Python会返回什么。 + +![无效的语法错误](./images/invalid_syntax_error.png) + +从返回的错误中,您可以看到Python非常聪明,它知道我们犯了错误,即 _Syntax Error: invalid syntax_,因为在Python中,将 x 用作乘法是语法错误,因为(x)在Python中不是有效的语法。代替 (**x**),我们使用星号 (*) 进行乘法。返回的错误清楚地显示了要修复的内容。 + +从程序中识别并删除错误的过程称为 _调试_。让我们通过将 * 放在 **x** 的位置来调试它。 + +![修复语法错误](./images/fixing_syntax_error.png) + +我们的错误已经被修复,代码运行并返回了我们期望的结果。作为程序员,您将每天看到这种类型的错误。了解如何调试是很好的。要善于调试,您应该了解您面临的错误类型。您可能会遇到的一些Python错误包括 _SyntaxError_、_IndexError_、_NameError_、_ModuleNotFoundError_、_KeyError_、_ImportError_、_AttributeError_、_TypeError_、_ValueError_、_ZeroDivisionError_ 等。我们将在后续部分更详细地了解不同的Python **错误类型**。 + +让我们继续练习如何使用Python交互式Shell。前往您的终端或命令提示符并键入单词 **python**。 + +![Python脚本Shell](./images/opening_python_shell.png) + +Python交互式Shell已打开。在进入下一节之前,让我们在Python交互式Shell上进行更多练习。通过在Shell上写 _exit()_ 来关闭已打开的Shell,然后再次打开它,让我们练习如何在Python Shell上编写文本。 + +![在Python Shell上写字符串](./images/writing_string_on_shell.png) + +### 安装Visual Studio Code + +Python交互式Shell适用于尝试和测试小型脚本代码,但不适用于大型项目。在实际工作环境中,开发人员使用不同的代码编辑器来编写代码。在这30天的Python编程挑战中,我们将使用Visual Studio Code。Visual Studio Code是一个非常流行的开源文本编辑器。我是vscode的粉丝,我建议[下载](https://code.visualstudio.com/)Visual Studio Code,但如果您更喜欢其他编辑器,请随意使用您拥有的编辑器。 + +[![Visual Studio Code](./images/vscode.png)](https://code.visualstudio.com/) + +如果您已安装Visual Studio Code,让我们看看如何使用它。 + +#### 如何使用Visual Studio Code + +通过双击Visual Studio图标打开Visual Studio Code。当您打开它时,您将获得这种类型的界面。尝试与标记的图标进行交互。 + +![Visual Studio Code](./images/vscode_ui.png) + +在桌面上创建一个名为30DaysOfPython的文件夹。然后使用Visual Studio Code打开它。 + +![在Visual Studio上打开项目](./images/how_to_open_project_on_vscode.png) + +![打开一个项目](./images/opening_project.png) + +打开后,您将看到创建30DaysOfPython项目目录内文件和文件夹的快捷方式。如下图所示,我已创建了第一个文件,helloworld.py。您可以做同样的事情。 + +![创建一个Python文件](./images/helloworld.png) + +在长时间编码之后,您想要关闭代码编辑器,对吗?这是如何关闭已打开项目的方法。 + +![关闭项目](./images/closing_opened_project.png) + +恭喜,您已经完成了设置开发环境的工作。让我们开始编码。 + +## 基本Python + +### Python语法 + +Python脚本可以在Python交互式shell或代码编辑器中编写。Python文件的扩展名是.py。 + +### Python缩进 + +缩进是文本中的空白。在许多语言中,缩进用于增加代码的可读性,但是Python使用缩进来创建代码块。在其他编程语言中,大括号用于创建代码块,而不是缩进。编写Python代码时的常见错误之一是错误的缩进。 + +![缩进错误](./images/indentation.png) + +### 注释 + +注释对于使代码更具可读性并在我们的代码中留下备注非常重要。Python不运行我们代码中的注释部分。 +在Python中,以井号(#)开头的任何文本都是注释。 + +**示例:单行注释** + +```shell + # 这是第一个注释 + # 这是第二个注释 + # Python正在吞噬世界 +``` + +**示例:多行注释** + +如果多行注释没有分配给变量,可以使用三重引号。 + +```shell +"""这是多行注释 +多行注释占据多行。 +Python正在吞噬世界 +""" +``` + +### 数据类型 + +在Python中有多种数据类型。让我们从最常见的数据类型开始。其他部分将详细介绍不同的数据类型。目前,让我们只浏览不同的数据类型并熟悉它们。您现在不必完全了解它们。 + +#### 数字 + +- 整数:整数(负数、零和正数) + 示例: + ... -3, -2, -1, 0, 1, 2, 3 ... +- 浮点数:十进制数 + 示例: + ... -3.5, -2.25, -1.0, 0.0, 1.1, 2.2, 3.5 ... +- 复数 + 示例: + 1 + j, 2 + 4j + +#### 字符串 + +在单引号或双引号下的一个或多个字符的集合。如果一个字符串超过一句,则使用三引号。 + +**示例:** + +```py +'Asabeneh' +'Finland' +'Python' +'I love teaching' +'I hope you are enjoying the first day of 30DaysOfPython Challenge' +``` + +>在Python中,如果一个字符串包含多个句子,使用三引号('''或""")表示一个多行字符串文本块,也称为多行字符串字面值。这样的字符串可以跨越多行,包括换行符,而不需要使用转义字符或多个单行字符串来表示。 +> +>例如: +> +>```python +>multiline_string = ''' +>这是一个多行字符串。 +>它可以包含多个句子和换行符。 +>''' +>``` +> +>或者使用双引号: +> +>```python +>multiline_string = """ +>这也是一个多行字符串。 +>使用双引号也可以创建多行字符串。 +>""" +>``` +> +>多行字符串通常用于文档字符串(docstrings)、长文本、SQL查询、HTML代码等需要跨越多行的情况。它们提供了一种方便的方式来包含大块文本而不需要在每行都添加换行符。 + +#### 布尔值 + +布尔数据类型要么是True,要么是False。T和F应始终大写。 + +**示例:** + +```python +True # 灯亮了吗?如果亮了,值为True +False # 灯亮了吗?如果熄灭了,值为False +``` + +#### 列表 + +Python列表是一个有序的集合,允许存储不同数据类型的项目。列表类似于JavaScript中的数组。 + +**示例:** + +```py +[0, 1, 2, 3, 4, 5] # 全部是相同数据类型 - 数字列表 +['Banana', 'Orange', 'Mango', 'Avocado'] # 全部是相同数据类型 - 字符串列表(水果) +['Finland','Estonia', 'Sweden','Norway'] # 全部是相同数据类型 - 字符串列表(国家) +['Banana', 10, False, 9.81] # 列表中的不同数据类型 - 字符串、整数、布尔值和浮点数 +``` + +#### 字典 + +Python字典对象是一个无序的数据集合,采用键值对格式。 + +**示例:** + +```py +{ +'first_name':'Asabeneh', +'last_name':'Yetayeh', +'country':'Finland', +'age':250, +'is_married':True, +'skills':['JS', 'React', 'Node', 'Python'] +} +``` + +#### 元组 + +元组是一个有序的集合,与列表类似,但一旦创建,元组就无法修改。它们是不可变的。 + +**示例:** + +```py +('Asabeneh', 'Pawel', 'Brook', 'Abraham', 'Lidiya') # 姓名 +``` + +```py +('Earth', 'Jupiter', 'Neptune', 'Mars', 'Venus', 'Saturn', 'Uranus', 'Mercury') # 行星 +``` + +#### 集合 + +集合是一种类似于列表和元组的数据类型。与列表和元组不同,集合不是有序的项目集合。就像在数学中一样,Python中的集合只存储唯一的项目。 + +在后 + +续部分中,我们将详细讨论每种Python数据类型。 + +**示例:** + +```py +{2, 4, 3, 5} +{3.14, 9.81, 2.7} # 集合中的顺序不重要 +``` + +### 检查数据类型 + +要检查某个数据/变量的数据类型,我们使用 **type** 函数。在下面的终端中,您将看到不同的Python数据类型: + +![检查数据类型](./images/checking_data_types.png) + +### Python文件 + +首先打开您的项目文件夹,30DaysOfPython。如果您没有这个文件夹,请创建一个名为30DaysOfPython的文件夹。在此文件夹内创建一个名为helloworld.py的文件。现在,让我们在Visual Studio Code上进行Python交互式shell上做的事情。 + +Python交互式shell在不使用 **print** 的情况下进行打印,但是在Visual Studio Code上,为了查看我们的结果,我们应该使用内置函数 _print()_。 _print()_ 内置函数接受一个或多个参数,如下所示: _print('arument1', 'argument2', 'argument3')_。请查看下面的示例。 + +**示例:** + +文件名为helloworld.py + +```py +# 第1天 - 30天的Python挑战 + +print(2 + 3) # 加法(+) +print(3 - 1) # 减法(-) +print(2 * 3) # 乘法(*) +print(3 / 2) # 除法(/) +print(3 ** 2) # 指数(**) +print(3 % 2) # 模数(%) +print(3 // 2) # 地板除法运算符(//) + +# 检查数据类型 +print(type(10)) # 整数 +print(type(3.14)) # 浮点数 +print(type(1 + 3j)) # 复数 +print(type('Asabeneh')) # 字符串 +print(type([1, 2, 3])) # 列表 +print(type({'name':'Asabeneh'})) # 字典 +print(type({9.8, 3.14, 2.7})) # 集合 +print(type((9.8, 3.14, 2.7))) # 元组 +``` + +要运行Python文件,请查看下面的图像。您可以通过在Visual Studio Code上运行绿色按钮,或在终端中键入 _python helloworld.py_ 来运行Python文件。 + +![](./images/running_python_script.png) + +🌕 您很棒。您刚刚完成了第1天的挑战,并正朝着伟大的方向前进。现在为您的大脑和肌肉做一些练习。 + +## 💻 练习 + +### 练习:Level 1 + +1. 检查您正在使用的Python版本。 +2. 打开Python交互式shell,并执行以下操作。操作数为3和4。 + - 加法(+) + - 减法(-) + - 乘法(\*) + - 模数(%) + - 除法(/) + - 指数(\*\*) + - 地板除法运算符(//) +3. 在Python交互式shell上编写字符串。字符串如下: + - 您的名字 + - 您的姓氏 + - 您的国家 + - 我喜欢教学 + - 我希望您在30DaysOfPython挑战的第一天过得愉快 +4. 检查以下数据的数据类型: + - 10 + - 9.8 + - 3.14 + - 4 - 4j + - ['Asabeneh', 'Python', '芬兰'] + - 您的名字 + - 您的姓氏 + - 您的国家 + +### 练习:Level 2 + +1. 在30DaysOfPython文件夹内创建一个名为day_1的文件夹。在day_1文件夹内,创建一个名为helloworld.py的Python文件,并重复问题1、2、3和4。请记住在Python文件上工作时使用 _print()_。导航到您保存文件的目录,并运行它。 + +### 练习:Level 3 + +1. 为不同的Python数据类型编写示例,如数字(整数、浮点数、复数)、字符串、布尔值、列表、元组、集合和字典。 +2. 找到(2, 3)和(10, 8)之间的[欧几里得距离](https://upimg.baike.so.com/doc/2949437-3111768.html)。 diff --git a/01_Introduction/index.html b/01_Introduction/index.html new file mode 100644 index 0000000..9ddf8fb --- /dev/null +++ b/01_Introduction/index.html @@ -0,0 +1,1852 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 01 介绍 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

01 介绍⚓︎

+

Python 是一种用于通用编程的高级编程语言。它是一种开源、解释型、面向对象的编程语言。Python 是由荷兰程序员Guido van Rossum创建的。Python编程语言的名称取自英国的一个喜剧系列,Monty Python's Flying Circus。第一个版本于1991年2月20日发布。

+

为什么选择Python?⚓︎

+

它是一种非常接近人类语言的编程语言,因此易于学习和使用。 +Python被各个行业和公司(包括Google)使用。它已经被用于开发Web应用程序、桌面应用程序、系统管理和机器学习库。Python在数据科学和机器学习社区中得到了高度的接受。我希望这足以说服您开始学习Python。Python正在吞噬这个世界,您可以在它吞噬您之前击败它。

+

环境设置⚓︎

+

安装Python⚓︎

+

要运行Python脚本,您需要安装Python。让我们下载 Python。 +如果您是Windows用户,请点击红色圈中的按钮。

+

installing on Windows

+

如果您是macOS用户。请点击红色圈中的按钮。

+

installing on Windows

+

要检查Python是否已安装,请在您的设备终端上编写以下命令。

+
python --version
+
+

Python版本

+

从终端中可以看到,我目前使用的是 Python 3.7.5 版本。您的Python版本可能与我的不同,但应为3.6或更高版本。如果您能看到Python版本,那么恭喜您,Python已经安装在您的计算机上。继续下一节。

+

Python Shell⚓︎

+

Python是一种解释型脚本语言,因此不需要编译。这意味着它逐行执行代码。Python附带了一个名为 Python Shell(Python交互式Shell) 的工具。它用于执行单个Python命令并获取结果。

+

Python Shell 等待来自用户的Python代码。当您输入代码时,它会解释代码并在下一行显示结果。 +打开您的终端或命令提示符(cmd)并键入:

+
python
+
+

Python脚本Shell

+

Python交互式shell已经打开,并等待您编写Python代码(Python脚本)。您将在此符号 >>> 旁边编写您的Python脚本,然后点击Enter。 +让我们在Python脚本Shell上编写我们的第一个脚本。

+

Python脚本在Python Shell上

+

干得好,您在Python交互式Shell上编写了您的第一个Python脚本。我们如何关闭Python交互式Shell? +要关闭Shell,在此符号 >> 旁边写入 exit() 命令并按Enter。

+

从Python Shell退出

+

现在,您知道如何打开Python交互式Shell以及如何退出。

+

只要您编写Python能理解的脚本,Python就会给您返回结果,否则它会返回错误。让我们故意犯一个错误,看看Python会返回什么。

+

无效的语法错误

+

从返回的错误中,您可以看到Python非常聪明,它知道我们犯了错误,即 Syntax Error: invalid syntax,因为在Python中,将 x 用作乘法是语法错误,因为(x)在Python中不是有效的语法。代替 (x),我们使用星号 (*) 进行乘法。返回的错误清楚地显示了要修复的内容。

+

从程序中识别并删除错误的过程称为 调试。让我们通过将 * 放在 x 的位置来调试它。

+

修复语法错误

+

我们的错误已经被修复,代码运行并返回了我们期望的结果。作为程序员,您将每天看到这种类型的错误。了解如何调试是很好的。要善于调试,您应该了解您面临的错误类型。您可能会遇到的一些Python错误包括 SyntaxErrorIndexErrorNameErrorModuleNotFoundErrorKeyErrorImportErrorAttributeErrorTypeErrorValueErrorZeroDivisionError 等。我们将在后续部分更详细地了解不同的Python 错误类型

+

让我们继续练习如何使用Python交互式Shell。前往您的终端或命令提示符并键入单词 python

+

Python脚本Shell

+

Python交互式Shell已打开。在进入下一节之前,让我们在Python交互式Shell上进行更多练习。通过在Shell上写 exit() 来关闭已打开的Shell,然后再次打开它,让我们练习如何在Python Shell上编写文本。

+

在Python Shell上写字符串

+

安装Visual Studio Code⚓︎

+

Python交互式Shell适用于尝试和测试小型脚本代码,但不适用于大型项目。在实际工作环境中,开发人员使用不同的代码编辑器来编写代码。在这30天的Python编程挑战中,我们将使用Visual Studio Code。Visual Studio Code是一个非常流行的开源文本编辑器。我是vscode的粉丝,我建议下载Visual Studio Code,但如果您更喜欢其他编辑器,请随意使用您拥有的编辑器。

+

Visual Studio Code

+

如果您已安装Visual Studio Code,让我们看看如何使用它。

+

如何使用Visual Studio Code⚓︎

+

通过双击Visual Studio图标打开Visual Studio Code。当您打开它时,您将获得这种类型的界面。尝试与标记的图标进行交互。

+

Visual Studio Code

+

在桌面上创建一个名为30DaysOfPython的文件夹。然后使用Visual Studio Code打开它。

+

在Visual Studio上打开项目

+

打开一个项目

+

打开后,您将看到创建30DaysOfPython项目目录内文件和文件夹的快捷方式。如下图所示,我已创建了第一个文件,helloworld.py。您可以做同样的事情。

+

创建一个Python文件

+

在长时间编码之后,您想要关闭代码编辑器,对吗?这是如何关闭已打开项目的方法。

+

关闭项目

+

恭喜,您已经完成了设置开发环境的工作。让我们开始编码。

+

基本Python⚓︎

+

Python语法⚓︎

+

Python脚本可以在Python交互式shell或代码编辑器中编写。Python文件的扩展名是.py。

+

Python缩进⚓︎

+

缩进是文本中的空白。在许多语言中,缩进用于增加代码的可读性,但是Python使用缩进来创建代码块。在其他编程语言中,大括号用于创建代码块,而不是缩进。编写Python代码时的常见错误之一是错误的缩进。

+

缩进错误

+

注释⚓︎

+

注释对于使代码更具可读性并在我们的代码中留下备注非常重要。Python不运行我们代码中的注释部分。 +在Python中,以井号(#)开头的任何文本都是注释。

+

示例:单行注释

+
    # 这是第一个注释
+    # 这是第二个注释
+    # Python正在吞噬世界
+
+

示例:多行注释

+

如果多行注释没有分配给变量,可以使用三重引号。

+
"""这是多行注释
+多行注释占据多行。
+Python正在吞噬世界
+"""
+
+

数据类型⚓︎

+

在Python中有多种数据类型。让我们从最常见的数据类型开始。其他部分将详细介绍不同的数据类型。目前,让我们只浏览不同的数据类型并熟悉它们。您现在不必完全了解它们。

+

数字⚓︎

+
    +
  • 整数:整数(负数、零和正数) + 示例: + ... -3, -2, -1, 0, 1, 2, 3 ...
  • +
  • 浮点数:十进制数 + 示例: + ... -3.5, -2.25, -1.0, 0.0, 1.1, 2.2, 3.5 ...
  • +
  • 复数 + 示例: + 1 + j, 2 + 4j
  • +
+

字符串⚓︎

+

在单引号或双引号下的一个或多个字符的集合。如果一个字符串超过一句,则使用三引号。

+

示例:

+
'Asabeneh'
+'Finland'
+'Python'
+'I love teaching'
+'I hope you are enjoying the first day of 30DaysOfPython Challenge'
+
+
+

在Python中,如果一个字符串包含多个句子,使用三引号('''或""")表示一个多行字符串文本块,也称为多行字符串字面值。这样的字符串可以跨越多行,包括换行符,而不需要使用转义字符或多个单行字符串来表示。

+

例如:

+
multiline_string = '''
+这是一个多行字符串。
+它可以包含多个句子和换行符。
+'''
+
+

或者使用双引号:

+
multiline_string = """
+这也是一个多行字符串。
+使用双引号也可以创建多行字符串。
+"""
+
+

多行字符串通常用于文档字符串(docstrings)、长文本、SQL查询、HTML代码等需要跨越多行的情况。它们提供了一种方便的方式来包含大块文本而不需要在每行都添加换行符。

+
+

布尔值⚓︎

+

布尔数据类型要么是True,要么是False。T和F应始终大写。

+

示例:

+
True  #  灯亮了吗?如果亮了,值为True
+False # 灯亮了吗?如果熄灭了,值为False
+
+

列表⚓︎

+

Python列表是一个有序的集合,允许存储不同数据类型的项目。列表类似于JavaScript中的数组。

+

示例:

+
[0, 1, 2, 3, 4, 5]  # 全部是相同数据类型 - 数字列表
+['Banana', 'Orange', 'Mango', 'Avocado'] # 全部是相同数据类型 - 字符串列表(水果)
+['Finland','Estonia', 'Sweden','Norway'] # 全部是相同数据类型 - 字符串列表(国家)
+['Banana', 10, False, 9.81] # 列表中的不同数据类型 - 字符串、整数、布尔值和浮点数
+
+

字典⚓︎

+

Python字典对象是一个无序的数据集合,采用键值对格式。

+

示例:

+
{
+'first_name':'Asabeneh',
+'last_name':'Yetayeh',
+'country':'Finland', 
+'age':250, 
+'is_married':True,
+'skills':['JS', 'React', 'Node', 'Python']
+}
+
+

元组⚓︎

+

元组是一个有序的集合,与列表类似,但一旦创建,元组就无法修改。它们是不可变的。

+

示例:

+
('Asabeneh', 'Pawel', 'Brook', 'Abraham', 'Lidiya') # 姓名
+
+
('Earth', 'Jupiter', 'Neptune', 'Mars', 'Venus', 'Saturn', 'Uranus', 'Mercury') # 行星
+
+

集合⚓︎

+

集合是一种类似于列表和元组的数据类型。与列表和元组不同,集合不是有序的项目集合。就像在数学中一样,Python中的集合只存储唯一的项目。

+

在后

+

续部分中,我们将详细讨论每种Python数据类型。

+

示例:

+
{2, 4, 3, 5}
+{3.14, 9.81, 2.7} # 集合中的顺序不重要
+
+

检查数据类型⚓︎

+

要检查某个数据/变量的数据类型,我们使用 type 函数。在下面的终端中,您将看到不同的Python数据类型:

+

检查数据类型

+

Python文件⚓︎

+

首先打开您的项目文件夹,30DaysOfPython。如果您没有这个文件夹,请创建一个名为30DaysOfPython的文件夹。在此文件夹内创建一个名为helloworld.py的文件。现在,让我们在Visual Studio Code上进行Python交互式shell上做的事情。

+

Python交互式shell在不使用 print 的情况下进行打印,但是在Visual Studio Code上,为了查看我们的结果,我们应该使用内置函数 print()print() 内置函数接受一个或多个参数,如下所示: print('arument1', 'argument2', 'argument3')。请查看下面的示例。

+

示例:

+

文件名为helloworld.py

+
# 第1天 - 30天的Python挑战
+
+print(2 + 3)             # 加法(+)
+print(3 - 1)             # 减法(-)
+print(2 * 3)             # 乘法(*)
+print(3 / 2)             # 除法(/)
+print(3 ** 2)            # 指数(**)
+print(3 % 2)             # 模数(%)
+print(3 // 2)            # 地板除法运算符(//)
+
+# 检查数据类型
+print(type(10))          # 整数
+print(type(3.14))        # 浮点数
+print(type(1 + 3j))      # 复数
+print(type('Asabeneh'))  # 字符串
+print(type([1, 2, 3]))   # 列表
+print(type({'name':'Asabeneh'})) # 字典
+print(type({9.8, 3.14, 2.7}))    # 集合
+print(type((9.8, 3.14, 2.7)))    # 元组
+
+

要运行Python文件,请查看下面的图像。您可以通过在Visual Studio Code上运行绿色按钮,或在终端中键入 python helloworld.py 来运行Python文件。

+

+

🌕 您很棒。您刚刚完成了第1天的挑战,并正朝着伟大的方向前进。现在为您的大脑和肌肉做一些练习。

+

💻 练习⚓︎

+

练习:Level 1⚓︎

+
    +
  1. 检查您正在使用的Python版本。
  2. +
  3. 打开Python交互式shell,并执行以下操作。操作数为3和4。
  4. +
  5. 加法(+)
  6. +
  7. 减法(-)
  8. +
  9. 乘法(*)
  10. +
  11. 模数(%)
  12. +
  13. 除法(/)
  14. +
  15. 指数(**)
  16. +
  17. 地板除法运算符(//)
  18. +
  19. 在Python交互式shell上编写字符串。字符串如下:
  20. +
  21. 您的名字
  22. +
  23. 您的姓氏
  24. +
  25. 您的国家
  26. +
  27. 我喜欢教学
  28. +
  29. 我希望您在30DaysOfPython挑战的第一天过得愉快
  30. +
  31. 检查以下数据的数据类型:
  32. +
  33. 10
  34. +
  35. 9.8
  36. +
  37. 3.14
  38. +
  39. 4 - 4j
  40. +
  41. ['Asabeneh', 'Python', '芬兰']
  42. +
  43. 您的名字
  44. +
  45. 您的姓氏
  46. +
  47. 您的国家
  48. +
+

练习:Level 2⚓︎

+
    +
  1. 在30DaysOfPython文件夹内创建一个名为day_1的文件夹。在day_1文件夹内,创建一个名为helloworld.py的Python文件,并重复问题1、2、3和4。请记住在Python文件上工作时使用 print()。导航到您保存文件的目录,并运行它。
  2. +
+

练习:Level 3⚓︎

+
    +
  1. 为不同的Python数据类型编写示例,如数字(整数、浮点数、复数)、字符串、布尔值、列表、元组、集合和字典。
  2. +
  3. 找到(2, 3)和(10, 8)之间的欧几里得距离
  4. +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/02_variables_builtin_functions/02_variables_builtin_functions.md b/02_variables_builtin_functions/02_variables_builtin_functions.md new file mode 100644 index 0000000..e034287 --- /dev/null +++ b/02_variables_builtin_functions/02_variables_builtin_functions.md @@ -0,0 +1,268 @@ +# 02 变量,内置函数 + +## 内置函数 + +在Python中,我们有许多内置函数。内置函数是全局可用的,这意味着您可以在不导入或配置的情况下使用内置函数。以下是一些最常用的Python内置函数:_print()_、_len()_、_type()_、_int()_、_float()_、_str()_、_input()_、_list()_、_dict()_、_min()_、_max()_、_sum()_、_sorted()_、_open()_、_file()_、_help()_ 和 _dir()_。在下表中,您将看到来自[Python文档](https://docs.python.org/3.9/library/functions.html)的Python内置函数的详尽列表。 + +![内置函数](./images/builtin-functions.png) + +让我们打开Python shell并开始使用一些最常见的内置函数。 + +![内置函数](./images/builtin-functions_practice.png) + +让我们通过使用不同的内置函数进行更多练习。 + +![内置函数Help和Dir](./images/help_and_dir_builtin.png) + +正如您从上面的终端中看到的,Python有保留字reserved words。我们不使用保留字来声明变量或函数。我们将在下一节中介绍变量。 + +我相信,到目前为止,您已经熟悉了内置函数。让我们再练习一下内置函数,然后我们将进入下一节。 + +![Min Max Sum](./images/builtin-functional-final.png) + +## 变量 + +变量在计算机内存中存储数据。建议在许多编程语言中使用助记符变量。助记符变量是一个易于记忆和关联的变量名称。变量指的是存储数据的内存地址。 +在命名变量时不允许在变量名中以数字、特殊字符或连字符开头。变量可以具有短名称(如x、y、z),但强烈建议使用更具描述性的名称(firstname、lastname、age、country)。 + +Python变量名称规则 + +- 变量名必须以字母或下划线字符开头 +- 变量名不能以数字开头 +- 变量名只能包含字母数字字符和下划线(A-z、0-9和\_) +- 变量名区分大小写(firstname、Firstname、FirstName和FIRSTNAME是不同的变量) + +以下是一些有效变量名称的示例: + +```shell +firstname +lastname +age +country +city +first_name +last_name +capital_city +_if # 如果要将保留字用作变量 +year_2021 +year2021 +current_year_2021 +birth_year +num1 +num2 +``` + +无效的变量名称 + +```shell +first-name +first@name +first$name +num-1 +1num +``` + +我们将使用许多Python开发人员采用的标准Python变量命名样式。Python开发人员使用(snake_case)变量命名约定。对于包含多个单词的变量,我们在每个单词之后使用下划线字符(例如,first_name、last_name、engine_rotation_speed)。下面的示例是变量的标准命名示例,变量名包含多个单词时需要使用下划线。 + +>Python 也推荐使用驼峰式命名(camelCase),那是在类名、Type 变量、异常 exception 名这些情况。而在**包名、模块名、方法名和普通变量名**等情况,则是推荐用蛇形命名 + +当我们将某种数据类型分配给变量时,称之为变量声明。例如,在下面的示例中,我的名字被分配给了变量first_name。等号是一个赋值运算符。分配意味着将数据存储在变量中。在Python中,等号不等同于数学中的等号。 + +_示例:_ + +```py +# Python中的变量 +first_name = 'Asabeneh' +last_name = 'Yetayeh' +country = 'Finland' +city = 'Helsinki' +age = 250 +is_married = True +skills = ['HTML', 'CSS', 'JS', 'React', 'Python'] +person_info = { + 'firstname':'Asabeneh', + 'lastname':'Yetayeh', + 'country':'Finland', + 'city':'Helsinki' + } +``` + +让我们使用内置函数 _print()_ 和 _len()_。打印函数接受无限数量的参数。参数是可以传递或放入函数括号内的值,参见下面的示例。 + +**示例:** + +```py +print('Hello, World!') # 文本Hello, World!是一个参数 +print('Hello',',', 'World','!') # 它可以接受多个参数,已传递了四个参数 +print(len('Hello, World!')) # 它只接受一个参数 +``` + +让我们打印并查找在顶部声明的变量的长度: + +**示例:** + +```py +# 打印存储在变量中的值 + +print('First name:', first_name) +print('First name length:', len(first_name)) +print('Last name: ', last_name) +print('Last name length: ', len(last_name)) +print('Country: ', country) +print('City: ', city) +print('Age: ', age) +print('Married: ', is_married) +print('Skills: ', skills) +print('Person information: ', person_info) +``` + +### 在一行中声明多个变量 + +多个变量也可以在一行中声明: + +**示例:** + +```py +first_name, last_name, country, age, is_married = 'Asabeneh', 'Yetayeh', 'Helsink', 250, True + +print(first_name, last_name, country, age, is_married) +print('First name:', first_name) +print('Last name: ', last_name) +print('Country: ', country) +print('Age: ', age) +print('Married: ', is_married) +``` + +使用内置的_input()_函数获取用户输入。让我们将从用户那里获取的数据分配给first_name和age变量。 +**示例:** + +```py +first_name = input('What is your name: ') +age = input('How old are you? ') + +print(first_name) +print(age) +``` + +## 数据类型 + +Python中有几种数据类型。要识别数据类型,我们使用_type_内置函数。我想请您专注于很好地理解不同的数据类型。在编程方面,一切都与数据类型有关。我在最初引入了数据类型,因为每个主题都与数据类型相关。我们将在各自的章节中更详细地介绍数据类型。 + +## 检查数据类型和强制类型转换 + +- 检查数据类型:要检查某个数据/变量的数据类型,我们使用_type_ + **示例:** + +```py +# 不同的Python数据类型 +# 让我们声明具有各种数据类型的变量 + +first_name = 'Asabeneh' # str +last_name = 'Yetayeh' # str +country = 'Finland' # str +city= 'Helsinki' # str +age = 250 # int + +# 打印类型 +print(type('Asabeneh')) # str +print(type(first_name)) # str +print(type(10)) # int +print(type(3.14)) # float +print(type(1 + 1j)) # complex +print(type(True)) # bool +print(type([1, 2, 3, 4])) # list +print(type({'name':'Asabeneh','age':250, 'is_married':250})) # dict +print(type((1,2))) # tuple +print(type(zip([1,2],[3,4]))) # set +``` + +- 强制类型转换:将一种数据类型转换为另一种数据类型。我们使用_int()_、_float()_、_str()_、_list_、_set_ + 当我们执行字符串数字的算术运算时,应首先将字符串数字转换为int或float,否则会返回错误。如果我们将数字与字符串连接,那么数字应首先转换为字符串。我们将在字符串部分讨论连接。 + + **示例:** + +```py +# int to float +num_int = 10 +print('num_int',num_int) # 10 +num_float = float(num_int) +print('num_float:', num_float) # 10.0 + +# float to int +gravity = 9.81 +print(int(gravity)) # 9 + +# int to str +num_int = 10 +print(num_int) # 10 +num_str = str(num_int) +print(num_str) # '10' + +# str to int or float +num_str = '10.6' +print('num_int', int(num_str)) # 10 +print('num_float', float(num_str)) # 10.6 + +# str to list +first_name = 'Asabeneh' +print(first_name) # 'Asabeneh' +first_name_to_list = list(first_name) +print(first_name_to_list) # ['A', 's', 'a', 'b', 'e', 'n', 'e', 'h'] +``` + +## 数字 + +Python中的数字数据类型: + +1. 整数:整数(负数、零和正数) + 示例: + ... -3, -2, -1, 0, 1, 2, 3 ... + +2. 浮点数(小数) + 示例: + ... -3.5, -2.25, -1.0, 0.0, 1.1, 2.2, 3.5 ... + +3. 复数 + 示例: + 1 + j, 2 + 4j, 1 - 1j + +🌕 你很棒。您刚刚完成了第2天的挑战,距离伟大还有两步。现在为您的大脑和肌肉做一些练习。 + +## 💻 练习 + +### 练习:Level 1 + +1. 在30DaysOfPython中创建一个名为day_2的文件夹。在此文件夹内创建一个名为variables.py的文件。 +2. 编写一个Python注释,写上'Day 2: 30 Days of Python programming'。 +3. 声明一个名为first_name的变量,并为其赋一个值。 +4. 声明一个名为last_name的变量,并为其赋一个值。 +5. 声明一个名为full_name的变量,并为其赋一个值。 +6. 声明一个名为country的变量,并为其赋一个值。 +7. 声明一个名为city的变量,并为其赋一个值。 +8. 声明一个名为age的变量,并为其赋一个值。 +9. 声明一个名为year的变量,并为其赋一个值。 +10. 声明一个名为is_married的变量,并为其赋一个值。 +11. 声明一个名为is_true的变量,并为其赋一个值。 +12. 声明一个名为is_light_on的变量,并为其赋一个值。 +13. 在一行中声明多个变量。 + +### 练习:Level 2 + +1. 使用type()内置函数检查所有变量的数据类型。 +2. 使用_len()_内置函数,查找您的名字的长度。 +3. 比较您的名字的长度和您的姓氏的长度。 +4. 将5分别声明为num_one,4为num_two。 + 1. 将num_one和num_two相加,并将值赋给一个名为total的变量。 + 2. 从num_one中减去num_two,并将值赋给一个名为diff的变量。 + 3. 将num_two和num_one相乘,并将值赋给一个名为product的变量。 + 4. 将num_one除以num_two,并将值赋给一个名为division的变量。 + 5. 使用模运算找到num_two除以num_one的值,并将其赋给一个名为remainder的变量。 + 6. 计算num_one的num_two次方,并将值赋给一个名为exp的变量。 + 7. 找到num_one除以num_two的地板除法,并将值赋给一个名为floor_division的变量。 +5. 一个圆的半径是30米。 + 1. 计算圆的面积并将该值分配给变量名为 _area_of_circle_ + 2. 计算圆的周长并将该值分配给变量名为 _circum_of_circle_ + 3. 接受用户输入的半径并计算面积。 +6. 使用内置的 input 函数从用户那里获取名字、姓氏、国家和年龄,并将这些值存储到相应的变量名中。 +7. 在Python shell或您的文件中运行 help('keywords') 来检查Python的保留字或关键字。 + diff --git a/02_variables_builtin_functions/index.html b/02_variables_builtin_functions/index.html new file mode 100644 index 0000000..87db35d --- /dev/null +++ b/02_variables_builtin_functions/index.html @@ -0,0 +1,1545 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 02 变量,内置函数 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+ +
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +

02 变量,内置函数⚓︎

+

内置函数⚓︎

+

在Python中,我们有许多内置函数。内置函数是全局可用的,这意味着您可以在不导入或配置的情况下使用内置函数。以下是一些最常用的Python内置函数:print()len()type()int()float()str()input()list()dict()min()max()sum()sorted()open()file()help()dir()。在下表中,您将看到来自Python文档的Python内置函数的详尽列表。

+

内置函数

+

让我们打开Python shell并开始使用一些最常见的内置函数。

+

内置函数

+

让我们通过使用不同的内置函数进行更多练习。

+

内置函数Help和Dir

+

正如您从上面的终端中看到的,Python有保留字reserved words。我们不使用保留字来声明变量或函数。我们将在下一节中介绍变量。

+

我相信,到目前为止,您已经熟悉了内置函数。让我们再练习一下内置函数,然后我们将进入下一节。

+

Min Max Sum

+

变量⚓︎

+

变量在计算机内存中存储数据。建议在许多编程语言中使用助记符变量。助记符变量是一个易于记忆和关联的变量名称。变量指的是存储数据的内存地址。 +在命名变量时不允许在变量名中以数字、特殊字符或连字符开头。变量可以具有短名称(如x、y、z),但强烈建议使用更具描述性的名称(firstname、lastname、age、country)。

+

Python变量名称规则

+
    +
  • 变量名必须以字母或下划线字符开头
  • +
  • 变量名不能以数字开头
  • +
  • 变量名只能包含字母数字字符和下划线(A-z、0-9和_)
  • +
  • 变量名区分大小写(firstname、Firstname、FirstName和FIRSTNAME是不同的变量)
  • +
+

以下是一些有效变量名称的示例:

+
firstname
+lastname
+age
+country
+city
+first_name
+last_name
+capital_city
+_if # 如果要将保留字用作变量
+year_2021
+year2021
+current_year_2021
+birth_year
+num1
+num2
+
+

无效的变量名称

+
first-name
+first@name
+first$name
+num-1
+1num
+
+

我们将使用许多Python开发人员采用的标准Python变量命名样式。Python开发人员使用(snake_case)变量命名约定。对于包含多个单词的变量,我们在每个单词之后使用下划线字符(例如,first_name、last_name、engine_rotation_speed)。下面的示例是变量的标准命名示例,变量名包含多个单词时需要使用下划线。

+
+

Python 也推荐使用驼峰式命名(camelCase),那是在类名、Type 变量、异常 exception 名这些情况。而在包名、模块名、方法名和普通变量名等情况,则是推荐用蛇形命名

+
+

当我们将某种数据类型分配给变量时,称之为变量声明。例如,在下面的示例中,我的名字被分配给了变量first_name。等号是一个赋值运算符。分配意味着将数据存储在变量中。在Python中,等号不等同于数学中的等号。

+

示例:

+
# Python中的变量
+first_name = 'Asabeneh'
+last_name = 'Yetayeh'
+country = 'Finland'
+city = 'Helsinki'
+age = 250
+is_married = True
+skills = ['HTML', 'CSS', 'JS', 'React', 'Python']
+person_info = {
+   'firstname':'Asabeneh',
+   'lastname':'Yetayeh',
+   'country':'Finland',
+   'city':'Helsinki'
+   }
+
+

让我们使用内置函数 print()len()。打印函数接受无限数量的参数。参数是可以传递或放入函数括号内的值,参见下面的示例。

+

示例:

+
print('Hello, World!') # 文本Hello, World!是一个参数
+print('Hello',',', 'World','!') # 它可以接受多个参数,已传递了四个参数
+print(len('Hello, World!')) # 它只接受一个参数
+
+

让我们打印并查找在顶部声明的变量的长度:

+

示例:

+
# 打印存储在变量中的值
+
+print('First name:', first_name)
+print('First name length:', len(first_name))
+print('Last name: ', last_name)
+print('Last name length: ', len(last_name))
+print('Country: ', country)
+print('City: ', city)
+print('Age: ', age)
+print('Married: ', is_married)
+print('Skills: ', skills)
+print('Person information: ', person_info)
+
+

在一行中声明多个变量⚓︎

+

多个变量也可以在一行中声明:

+

示例:

+
first_name, last_name, country, age, is_married = 'Asabeneh', 'Yetayeh', 'Helsink', 250, True
+
+print(first_name, last_name, country, age, is_married)
+print('First name:', first_name)
+print('Last name: ', last_name)
+print('Country: ', country)
+print('Age: ', age)
+print('Married: ', is_married)
+
+

使用内置的_input()_函数获取用户输入。让我们将从用户那里获取的数据分配给first_name和age变量。 +示例:

+
first_name = input('What is your name: ')
+age = input('How old are you? ')
+
+print(first_name)
+print(age)
+
+

数据类型⚓︎

+

Python中有几种数据类型。要识别数据类型,我们使用_type_内置函数。我想请您专注于很好地理解不同的数据类型。在编程方面,一切都与数据类型有关。我在最初引入了数据类型,因为每个主题都与数据类型相关。我们将在各自的章节中更详细地介绍数据类型。

+

检查数据类型和强制类型转换⚓︎

+
    +
  • 检查数据类型:要检查某个数据/变量的数据类型,我们使用_type_ + 示例:
  • +
+
# 不同的Python数据类型
+# 让我们声明具有各种数据类型的变量
+
+first_name = 'Asabeneh'     # str
+last_name = 'Yetayeh'       # str
+country = 'Finland'         # str
+city= 'Helsinki'            # str
+age = 250                   # int
+
+# 打印类型
+print(type('Asabeneh'))     # str
+print(type(first_name))     # str
+print(type(10))             # int
+print(type(3.14))           # float
+print(type(1 + 1j))         # complex
+print(type(True))           # bool
+print(type([1, 2, 3, 4]))     # list
+print(type({'name':'Asabeneh','age':250, 'is_married':250}))    # dict
+print(type((1,2)))                                              # tuple
+print(type(zip([1,2],[3,4])))                                   # set
+
+
    +
  • 强制类型转换:将一种数据类型转换为另一种数据类型。我们使用_int()、_float()str()listset + 当我们执行字符串数字的算术运算时,应首先将字符串数字转换为int或float,否则会返回错误。如果我们将数字与字符串连接,那么数字应首先转换为字符串。我们将在字符串部分讨论连接。
  • +
+

示例:

+
# int to float
+num_int = 10
+print('num_int',num_int)         # 10
+num_float = float(num_int)
+print('num_float:', num_float)   # 10.0
+
+# float to int
+gravity = 9.81
+print(int(gravity))             # 9
+
+# int to str
+num_int = 10
+print(num_int)                  # 10
+num_str = str(num_int)
+print(num_str)                  # '10'
+
+# str to int or float
+num_str = '10.6'
+print('num_int', int(num_str))      # 10
+print('num_float', float(num_str))  # 10.6
+
+# str to list
+first_name = 'Asabeneh'
+print(first_name)               # 'Asabeneh'
+first_name_to_list = list(first_name)
+print(first_name_to_list)            # ['A', 's', 'a', 'b', 'e', 'n', 'e', 'h']
+
+

数字⚓︎

+

Python中的数字数据类型:

+
    +
  1. +

    整数:整数(负数、零和正数) + 示例: + ... -3, -2, -1, 0, 1, 2, 3 ...

    +
  2. +
  3. +

    浮点数(小数) + 示例: + ... -3.5, -2.25, -1.0, 0.0, 1.1, 2.2, 3.5 ...

    +
  4. +
  5. +

    复数 + 示例: + 1 + j, 2 + 4j, 1 - 1j

    +
  6. +
+

🌕 你很棒。您刚刚完成了第2天的挑战,距离伟大还有两步。现在为您的大脑和肌肉做一些练习。

+

💻 练习⚓︎

+

练习:Level 1⚓︎

+
    +
  1. 在30DaysOfPython中创建一个名为day_2的文件夹。在此文件夹内创建一个名为variables.py的文件。
  2. +
  3. 编写一个Python注释,写上'Day 2: 30 Days of Python programming'。
  4. +
  5. 声明一个名为first_name的变量,并为其赋一个值。
  6. +
  7. 声明一个名为last_name的变量,并为其赋一个值。
  8. +
  9. 声明一个名为full_name的变量,并为其赋一个值。
  10. +
  11. 声明一个名为country的变量,并为其赋一个值。
  12. +
  13. 声明一个名为city的变量,并为其赋一个值。
  14. +
  15. 声明一个名为age的变量,并为其赋一个值。
  16. +
  17. 声明一个名为year的变量,并为其赋一个值。
  18. +
  19. 声明一个名为is_married的变量,并为其赋一个值。
  20. +
  21. 声明一个名为is_true的变量,并为其赋一个值。
  22. +
  23. 声明一个名为is_light_on的变量,并为其赋一个值。
  24. +
  25. 在一行中声明多个变量。
  26. +
+

练习:Level 2⚓︎

+
    +
  1. 使用type()内置函数检查所有变量的数据类型。
  2. +
  3. 使用_len()_内置函数,查找您的名字的长度。
  4. +
  5. 比较您的名字的长度和您的姓氏的长度。
  6. +
  7. 将5分别声明为num_one,4为num_two。
  8. +
  9. 将num_one和num_two相加,并将值赋给一个名为total的变量。
  10. +
  11. 从num_one中减去num_two,并将值赋给一个名为diff的变量。
  12. +
  13. 将num_two和num_one相乘,并将值赋给一个名为product的变量。
  14. +
  15. 将num_one除以num_two,并将值赋给一个名为division的变量。
  16. +
  17. 使用模运算找到num_two除以num_one的值,并将其赋给一个名为remainder的变量。
  18. +
  19. 计算num_one的num_two次方,并将值赋给一个名为exp的变量。
  20. +
  21. 找到num_one除以num_two的地板除法,并将值赋给一个名为floor_division的变量。
  22. +
  23. 一个圆的半径是30米。
  24. +
  25. 计算圆的面积并将该值分配给变量名为 area_of_circle
  26. +
  27. 计算圆的周长并将该值分配给变量名为 circum_of_circle
  28. +
  29. 接受用户输入的半径并计算面积。
  30. +
  31. 使用内置的 input 函数从用户那里获取名字、姓氏、国家和年龄,并将这些值存储到相应的变量名中。
  32. +
  33. 在Python shell或您的文件中运行 help('keywords') 来检查Python的保留字或关键字。
  34. +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/03_operators/03_operators.md b/03_operators/03_operators.md new file mode 100644 index 0000000..ecc38b3 --- /dev/null +++ b/03_operators/03_operators.md @@ -0,0 +1,274 @@ +# 03 运算符 + +## 布尔类型 + +布尔数据类型代表两个值中的一个:_True_ 或 _False_。当我们开始使用比较运算符时,这些数据类型的用途就会变得明确。**T**(表示True)和 **F**(表示False)的首字母应与JavaScript不同,大写。 +**示例:布尔值** + +```py +print(True) +print(False) +``` + +## 运算符 + +Python语言支持多种类型的运算符。在本节中,我们将重点介绍其中的一些。 + +### 赋值运算符 + +赋值运算符用于将值赋给变量。以 = 为例。等号在数学中表示两个值相等,但在Python中,它意味着我们将一个值存储在某个变量中,我们称之为赋值或向变量赋值。下表显示了Python赋值运算符的不同类型,摘自 [w3school](https://www.w3schools.com/python/python_operators.asp)。 + +![赋值运算符](./images/assignment_operators.png) + +### 算术运算符 + +- 加法(+): a + b +- 减法(-): a - b +- 乘法(*): a * b +- 除法(/): a / b +- 取模(%): a % b +- 向下取整除法(//): a // b +- 幂运算(**): a ** b + +![算术运算符](./images/arithmetic_operators.png) + +**示例:整数** + +```py +# Python中的算术运算 +# 整数 + +print('Addition: ', 1 + 2) # 3 +print('Subtraction: ', 2 - 1) # 1 +print('Multiplication: ', 2 * 3) # 6 +print ('Division: ', 4 / 2) # 2.0 Python中的除法产生浮点数 +print('Division: ', 6 / 2) # 3.0 +print('Division: ', 7 / 2) # 3.5 +print('Division without the remainder: ', 7 // 2) # 3, 不产生浮点数或余数 +print ('Division without the remainder: ',7 // 3) # 2 +print('Modulus: ', 3 % 2) # 1, 产生余数 +print('Exponentiation: ', 2 ** 3) # 9 意味着 2 * 2 * 2 +``` + +**示例:浮点数** + +```py +# 浮点数 +print('Floating Point Number, PI', 3.14) +print('Floating Point Number, gravity', 9.81) +``` + +**示例:复数** + +```py +# 复数 +print('Complex number: ', 1 + 1j) +print('Multiplying complex numbers: ',(1 + 1j) * (1 - 1j)) +``` + +让我们声明一个变量并赋予一个数字数据类型。我将使用单个字符变量,但请记住不要养成声明此类变量的习惯。变量名称应始终具有助记性。 + +**示例** + +```python +# 在最顶部首先声明变量 + +a = 3 # a是一个变量名,3是整数数据类型 +b = 2 # b是一个变量名,2是整数数据类型 + +# 算术运算并将结果分配给变量 +total = a + b +diff = a - b +product = a * b +division = a / b +remainder = a % b +floor_division = a // b +exponential = a ** b + +# 我应该使用sum而不是total,但sum是一个内置函数 - 尽量避免覆盖内置函数 +print(total) # 如果您不使用某个字符串标记打印,您永远不知道结果来自哪里 +print('a + b =', total) +print('a - b =', diff) +print('a * b =', product) +print('a / b =', division) +print('a % b =', remainder) +print('a // b =', floor_division) +print('a ** b =', exponentiation) +``` + +**示例:** + +```python +print('== 加法,减法,乘法,除法,取模 ==') + +# 声明值并将它们组织在一起 +num_one = 3 +num_two = 4 + +# 算术操作 +total = num_one + num_two +diff = num_two - num_one +product = num_one * num_two +div = num_two / num_one +remainder = num_two % num_one + +# 使用标签打印值 +print('total:', total) +print('difference:', diff) +print('product:', product) +print('division:', div) +print('remainder:', remainder) +``` + +让我们开始连接各种知识点,开始使用我们已经了解的知识来计算(面积、体积、密度、重量、周长、距离、力)。 + +```python +# 计算圆的面积 +radius = 10 # 圆的半径 +area_of_circle = 3.14 * radius ** 2 # 两个*表示指数或幂 +print('圆的面积:', area_of_circle) + +# 计算矩形的面积 +length = 10 +width = 20 +area_of_rectangle = length * width +print('矩形的面积:', area_of_rectangle) + +# 计算物体的重量 +mass = 75 +gravity = 9.81 +weight = mass * gravity +print(weight, 'N') # 添加重量单位 + +# 计算液体的密度 +mass = 75 # 千克 +volume = 0.075 # 立方米 +density = mass / volume # 1000千克/立方米 +``` + +### 比较运算符 + +在编程中,我们比较值,使用比较运算符来比较两个值。我们检查一个值是否大于、小于或等于另一个值。以下表格显示了Python比较运算符,摘自[w3shool](https://www.w3schools.com/python/python_operators.asp)。 + +![Comparison Operators](./images/comparison_operators.png) + +```python +print(3 > 2) # True,因为3大于2 +print(3 >= 2) # True,因为3大于2 +print(3 < 2) # False,因为3小于2 +print(2 < 3) # True,因为2小于3 +print(2 <= 3) # True,因为2小于3 +print(3 == 2) # False,因为3不等于2 +print(3 != 2) # True,因为3不等于2 +print(len('mango') == len('avocado')) # False +print(len('mango') != len('avocado')) # True +print(len('mango') < len('avocado')) # True +print(len('milk') != len('meat')) # False +print(len('milk') == len('meat')) # True +print(len('tomato') == len('potato')) # True +print(len('python') > len('dragon')) # False + +# 比较会产生True或False + +print('True == True: ', True == True) +print('True == False: ', True == False) +print('False == False:', False == False) +``` + +除了上述的比较运算符之外,Python还使用: + +- _is_:如果两个变量是相同的对象,则返回true(x is y) +- _is not_:如果两个变量不是相同的对象,则返回true(x is not y) +- _in_:如果查询的列表包含某个项目,则返回True(x in y) +- _not in_:如果查询的列表中不包含某个项目,则返回True(x in y) + +```python +print('1 is 1', 1 is 1) # True - 因为数据值相同 +print('1 is not 2', 1 is not 2) # True - 因为1不等于2 +print('A in Asabeneh', 'A' in 'Asabeneh') # True - A在字符串中找到 +print('B in Asabeneh', 'B' in 'Asabeneh') # False - 没有大写B +print('coding' in 'coding for all') # True - 因为coding for all包含单词coding +print('a in an:', 'a' in 'an') # True +print('4 is 2 ** 2:', 4 is 2 ** 2) # True +``` + +### 逻辑运算符 + +与其他编程语言不同,Python使用关键字`and`、`or`和`not`来表示逻辑运算符。逻辑运算符用于组合条件语句: + +![Logical Operators](./images/logical_operators.png) + +```python +print(3 > 2 and 4 > 3) # True - 因为两个语句都为真 +print(3 > 2 and 4 < 3) # False - 因为第二个语句为假 +print(3 < 2 and 4 < 3) # False - 因为两个语句都为假 +print('True and True: ', True and True) +print(3 > + +2 or 4 > 3) # True - 因为两个语句都为真 +print(3 > 2 or 4 < 3) # True - 因为其中一个语句为真 +print(3 < 2 or 4 < 3) # False - 因为两个语句都为假 +print('True or False:', True or False) +print(not 3 > 2) # False - 因为3 > 2为真,然后not True返回False +print(not True) # False - 否定,not运算符将True变为False +print(not False) # True +print(not not True) # True +print(not not False) # False +``` + +🌕 你有无穷无尽的能量。 你已经完成了第3天的挑战,你在通往伟大之路上已经走了三步。 现在锻炼一下大脑和肌肉,做一些练习吧。 + +## 💻 练习 + +1. 将您的年龄声明为整数变量。 +2. 将您的身高声明为浮点变量。 +3. 声明一个变量,存储一个复数。 +4. 编写一个脚本,提示用户输入三角形的底边和高度,并计算这个三角形的面积(面积 = 0.5 x b x h)。 + +```python + 输入底边:20 + 输入高度:10 + 三角形的面积是100 +``` + +5. 编写一个脚本,提示用户输入三角形的边a、边b和边c。计算三角形的周长(周长= a + b + c)。 + +```python +输入边a:5 +输入边b:4 +输入边c:3 +三角形的周长是12 +``` + +6. 使用提示获取矩形的长度和宽度。计算它的面积(面积=长度 x 宽度)和周长(周长= 2 x (长度 + 宽度))。 +7. 使用提示获取圆的半径。计算面积(面积=π x r x r)和周长(c = 2 x π x r),其中π = 3.14。 +8. 计算y = 2x -2的斜率、x截距和y截距。 +9. 斜率是(m = y2-y1/x2-x1)。计算斜率和点(2, 2)和点(6,10)之间的[欧几里德距离](https://en.wikipedia.org/wiki/Euclidean_distance#:~:text=In%20mathematics%2C%20the%20Euclidean%20distance,being%20called%20the%20Pythagorean%20distance.)。 +10. 比较任务8和任务9中的斜率。 +11. 计算y(y = x^2 + 6x + 9)的值。尝试使用不同的x值,找出y将在哪个x值为0。 +12. 查找'tomato'和'dragon'的长度,并创建一个虚假的比较语句。 +13. 使用_and_运算符检查'python'和'dragon'中是否都有'on'。 +14. _我希望这门课程不会充满术语。_ 使用_in_运算符检查句子中是否有_术语_。 +15. 在'龙'和'python'中都没有'on'。 +16. 查找文本_python_的长度,并将该值转换为浮点数,然后将其转换为字符串。 +17. 偶数可以被2整除,余数为零。如何使用Python检查一个数字是否为偶数或奇数? +18. 检查7除以3的地板除法是否等于2.7的int转换值。 +19. 检查'type('10')'是否等于'type(10)'。 +20. 检查int('9.8')是否等于10。 +21. 写一个脚本,提示用户输入小时数和每小时的费率。计算这个人的工资? + +```python +输入小时数:40 +输入每小时的费率:28 +您的每周收入为1120 +``` + +22. 写一个Python脚本,显示以下表格 + +```python +1 1 1 1 1 +2 1 2 4 8 +3 1 3 9 27 +4 1 4 16 64 +5 1 5 25 125 +``` diff --git a/03_operators/index.html b/03_operators/index.html new file mode 100644 index 0000000..8dd21e8 --- /dev/null +++ b/03_operators/index.html @@ -0,0 +1,1500 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 03 运算符 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +

03 运算符⚓︎

+

布尔类型⚓︎

+

布尔数据类型代表两个值中的一个:TrueFalse。当我们开始使用比较运算符时,这些数据类型的用途就会变得明确。T(表示True)和 F(表示False)的首字母应与JavaScript不同,大写。 +示例:布尔值

+
print(True)
+print(False)
+
+

运算符⚓︎

+

Python语言支持多种类型的运算符。在本节中,我们将重点介绍其中的一些。

+

赋值运算符⚓︎

+

赋值运算符用于将值赋给变量。以 = 为例。等号在数学中表示两个值相等,但在Python中,它意味着我们将一个值存储在某个变量中,我们称之为赋值或向变量赋值。下表显示了Python赋值运算符的不同类型,摘自 w3school

+

赋值运算符

+

算术运算符⚓︎

+
    +
  • 加法(+): a + b
  • +
  • 减法(-): a - b
  • +
  • 乘法(*): a * b
  • +
  • 除法(/): a / b
  • +
  • 取模(%): a % b
  • +
  • 向下取整除法(//): a // b
  • +
  • 幂运算(**): a ** b
  • +
+

算术运算符

+

示例:整数

+
# Python中的算术运算
+# 整数
+
+print('Addition: ', 1 + 2)        # 3
+print('Subtraction: ', 2 - 1)     # 1
+print('Multiplication: ', 2 * 3)  # 6
+print ('Division: ', 4 / 2)       # 2.0  Python中的除法产生浮点数
+print('Division: ', 6 / 2)        # 3.0         
+print('Division: ', 7 / 2)        # 3.5
+print('Division without the remainder: ', 7 // 2)   # 3,  不产生浮点数或余数
+print ('Division without the remainder: ',7 // 3)   # 2
+print('Modulus: ', 3 % 2)         # 1, 产生余数
+print('Exponentiation: ', 2 ** 3) # 9 意味着 2 * 2 * 2
+
+

示例:浮点数

+
# 浮点数
+print('Floating Point Number, PI', 3.14)
+print('Floating Point Number, gravity', 9.81)
+
+

示例:复数

+
# 复数
+print('Complex number: ', 1 + 1j)
+print('Multiplying complex numbers: ',(1 + 1j) * (1 - 1j))
+
+

让我们声明一个变量并赋予一个数字数据类型。我将使用单个字符变量,但请记住不要养成声明此类变量的习惯。变量名称应始终具有助记性。

+

示例

+
# 在最顶部首先声明变量
+
+a = 3  # a是一个变量名,3是整数数据类型
+b = 2  # b是一个变量名,2是整数数据类型
+
+# 算术运算并将结果分配给变量
+total = a + b
+diff = a - b
+product = a * b
+division = a / b
+remainder = a % b
+floor_division = a // b
+exponential = a ** b
+
+# 我应该使用sum而不是total,但sum是一个内置函数 - 尽量避免覆盖内置函数
+print(total)  # 如果您不使用某个字符串标记打印,您永远不知道结果来自哪里
+print('a + b =', total)
+print('a - b =', diff)
+print('a * b =', product)
+print('a / b =', division)
+print('a % b =', remainder)
+print('a // b =', floor_division)
+print('a ** b =', exponentiation)
+
+

示例:

+
print('== 加法,减法,乘法,除法,取模 ==')
+
+# 声明值并将它们组织在一起
+num_one = 3
+num_two = 4
+
+# 算术操作
+total = num_one + num_two
+diff = num_two - num_one
+product = num_one * num_two
+div = num_two / num_one
+remainder = num_two % num_one
+
+# 使用标签打印值
+print('total:', total)
+print('difference:', diff)
+print('product:', product)
+print('division:', div)
+print('remainder:', remainder)
+
+

让我们开始连接各种知识点,开始使用我们已经了解的知识来计算(面积、体积、密度、重量、周长、距离、力)。

+
# 计算圆的面积
+radius = 10  # 圆的半径
+area_of_circle = 3.14 * radius ** 2  # 两个*表示指数或幂
+print('圆的面积:', area_of_circle)
+
+# 计算矩形的面积
+length = 10
+width = 20
+area_of_rectangle = length * width
+print('矩形的面积:', area_of_rectangle)
+
+# 计算物体的重量
+mass = 75
+gravity = 9.81
+weight = mass * gravity
+print(weight, 'N')  # 添加重量单位
+
+# 计算液体的密度
+mass = 75  # 千克
+volume = 0.075  # 立方米
+density = mass / volume  # 1000千克/立方米
+
+

比较运算符⚓︎

+

在编程中,我们比较值,使用比较运算符来比较两个值。我们检查一个值是否大于、小于或等于另一个值。以下表格显示了Python比较运算符,摘自w3shool

+

Comparison Operators

+
print(3 > 2)  # True,因为3大于2
+print(3 >= 2)  # True,因为3大于2
+print(3 < 2)  # False,因为3小于2
+print(2 < 3)  # True,因为2小于3
+print(2 <= 3)  # True,因为2小于3
+print(3 == 2)  # False,因为3不等于2
+print(3 != 2)  # True,因为3不等于2
+print(len('mango') == len('avocado'))  # False
+print(len('mango') != len('avocado'))  # True
+print(len('mango') < len('avocado'))  # True
+print(len('milk') != len('meat'))  # False
+print(len('milk') == len('meat'))  # True
+print(len('tomato') == len('potato'))  # True
+print(len('python') > len('dragon'))  # False
+
+# 比较会产生True或False
+
+print('True == True: ', True == True)
+print('True == False: ', True == False)
+print('False == False:', False == False)
+
+

除了上述的比较运算符之外,Python还使用:

+
    +
  • is:如果两个变量是相同的对象,则返回true(x is y)
  • +
  • is not:如果两个变量不是相同的对象,则返回true(x is not y)
  • +
  • in:如果查询的列表包含某个项目,则返回True(x in y)
  • +
  • not in:如果查询的列表中不包含某个项目,则返回True(x in y)
  • +
+
print('1 is 1', 1 is 1)  # True - 因为数据值相同
+print('1 is not 2', 1 is not 2)  # True - 因为1不等于2
+print('A in Asabeneh', 'A' in 'Asabeneh')  # True - A在字符串中找到
+print('B in Asabeneh', 'B' in 'Asabeneh')  # False - 没有大写B
+print('coding' in 'coding for all')  # True - 因为coding for all包含单词coding
+print('a in an:', 'a' in 'an')  # True
+print('4 is 2 ** 2:', 4 is 2 ** 2)  # True
+
+

逻辑运算符⚓︎

+

与其他编程语言不同,Python使用关键字andornot来表示逻辑运算符。逻辑运算符用于组合条件语句:

+

Logical Operators

+
print(3 > 2 and 4 > 3)  # True - 因为两个语句都为真
+print(3 > 2 and 4 < 3)  # False - 因为第二个语句为假
+print(3 < 2 and 4 < 3)  # False - 因为两个语句都为假
+print('True and True: ', True and True)
+print(3 > 
+
+2 or 4 > 3)  # True - 因为两个语句都为真
+print(3 > 2 or 4 < 3)  # True - 因为其中一个语句为真
+print(3 < 2 or 4 < 3)  # False - 因为两个语句都为假
+print('True or False:', True or False)
+print(not 3 > 2)  # False - 因为3 > 2为真,然后not True返回False
+print(not True)  # False - 否定,not运算符将True变为False
+print(not False)  # True
+print(not not True)  # True
+print(not not False)  # False
+
+

🌕 你有无穷无尽的能量。 你已经完成了第3天的挑战,你在通往伟大之路上已经走了三步。 现在锻炼一下大脑和肌肉,做一些练习吧。

+

💻 练习⚓︎

+
    +
  1. 将您的年龄声明为整数变量。
  2. +
  3. 将您的身高声明为浮点变量。
  4. +
  5. 声明一个变量,存储一个复数。
  6. +
  7. 编写一个脚本,提示用户输入三角形的底边和高度,并计算这个三角形的面积(面积 = 0.5 x b x h)。
  8. +
+
    输入底边20
+    输入高度10
+    三角形的面积是100
+
+
    +
  1. 编写一个脚本,提示用户输入三角形的边a、边b和边c。计算三角形的周长(周长= a + b + c)。
  2. +
+
输入边a5
+输入边b4
+输入边c3
+三角形的周长是12
+
+
    +
  1. 使用提示获取矩形的长度和宽度。计算它的面积(面积=长度 x 宽度)和周长(周长= 2 x (长度 + 宽度))。
  2. +
  3. 使用提示获取圆的半径。计算面积(面积=π x r x r)和周长(c = 2 x π x r),其中π = 3.14。
  4. +
  5. 计算y = 2x -2的斜率、x截距和y截距。
  6. +
  7. 斜率是(m = y2-y1/x2-x1)。计算斜率和点(2, 2)和点(6,10)之间的欧几里德距离
  8. +
  9. 比较任务8和任务9中的斜率。
  10. +
  11. 计算y(y = x^2 + 6x + 9)的值。尝试使用不同的x值,找出y将在哪个x值为0。
  12. +
  13. 查找'tomato'和'dragon'的长度,并创建一个虚假的比较语句。
  14. +
  15. 使用_and_运算符检查'python'和'dragon'中是否都有'on'。
  16. +
  17. 我希望这门课程不会充满术语。 使用_in_运算符检查句子中是否有_术语_。
  18. +
  19. 在'龙'和'python'中都没有'on'。
  20. +
  21. 查找文本_python_的长度,并将该值转换为浮点数,然后将其转换为字符串。
  22. +
  23. 偶数可以被2整除,余数为零。如何使用Python检查一个数字是否为偶数或奇数?
  24. +
  25. 检查7除以3的地板除法是否等于2.7的int转换值。
  26. +
  27. 检查'type('10')'是否等于'type(10)'。
  28. +
  29. 检查int('9.8')是否等于10。
  30. +
  31. 写一个脚本,提示用户输入小时数和每小时的费率。计算这个人的工资?
  32. +
+
输入小时数40
+输入每小时的费率28
+您的每周收入为1120
+
+
    +
  1. 写一个Python脚本,显示以下表格
  2. +
+
1 1 1 1 1
+2 1 2 4 8
+3 1 3 9 27
+4 1 4 16 64
+5 1 5 25 125
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/04_strings/04_strings.md b/04_strings/04_strings.md new file mode 100644 index 0000000..127f8de --- /dev/null +++ b/04_strings/04_strings.md @@ -0,0 +1,574 @@ +# 04 字符串 + +文本是一种字符串数据类型。任何以文本形式编写的数据类型都是字符串。任何在单引号、双引号或三重引号下的数据都是字符串。有不同的字符串方法和内置函数来处理字符串数据类型。要检查字符串的长度,请使用`len()`方法。 + +## 创建字符串 + +```python +letter = 'P' # 一个字符串可以是一个单字符或一堆文本 +print(letter) # P +print(len(letter)) # 1 +greeting = 'Hello, World!' # 字符串可以使用单引号或双引号创建,"Hello, World!" +print(greeting) # Hello, World! +print(len(greeting)) # 13 +sentence = "I hope you are enjoying 30 days of Python Challenge" +print(sentence) +``` + +多行字符串可以使用三重单引号`''''`或三重双引号`""""`创建。请参考以下示例。 + +```python +multiline_string = '''I am a teacher and enjoy teaching. +I didn't find anything as rewarding as empowering people. +That is why I created 30 days of python.''' +print(multiline_string) + +# 还有另一种做同样事情的方法 +multiline_string = """I am a teacher and enjoy teaching. +I didn't find anything as rewarding as empowering people. +That is why I created 30 days of python.""" +print(multiline_string) +``` + +## 字符串连接 + +我们可以将字符串连接在一起。合并或连接字符串称为字符串连接。请参考以下示例: + +```python +first_name = 'Asabeneh' +last_name = 'Yetayeh' +space = ' ' +full_name = first_name + space + last_name +print(full_name) # Asabeneh Yetayeh +# 使用len()内置函数检查字符串的长度 +print(len(first_name)) # 8 +print(len(last_name)) # 7 +print(len(first_name) > len(last_name)) # True +print(len(full_name)) # 16 +``` + +## 字符串中的转义序列 + +在Python和其他编程语言中,`\`后面跟着一个字符是转义序列。让我们看看最常见的转义字符: + +- `\n`:换行 +- `\t`:制表符(相当于8个空格) +- `\`:反斜杠 +- `\'`:单引号`’` +- `\\"`:双引号`"` + +现在,让我们使用示例来了解上述转义序列的用法。 + +```python +print('I hope everyone is enjoying the Python Challenge.\nAre you ?') # 换行 +print('Days\tTopics\tExercises') # 添加制表符或4个空格 +print('Day 1\t5\t5') +print('Day 2\t6\t20') +print('Day 3\t5\t23') +print('Day 4\t1\t35') +print('This is a backslash symbol (\\)') # 写一个反斜杠 +print('In every programming language it starts with \"Hello, World!\"') # 在单引号内写双引号 + +# 输出 +I hope every one is enjoying the Python Challenge. +Are you ? +Days Topics Exercises +Day 1 5 5 +Day 2 6 20 +Day 3 5 23 +Day 4 1 35 +This is a backslash symbol (\) +In every programming language it starts with "Hello, World!" +``` + +## 字符串格式化 + +### 旧式字符串格式化(%运算符) + +在Python中,有许多格式化字符串的方式。在本节中,我们将介绍其中一些。 +`%`运算符用于格式化一组变量,这些变量包含在一个“元组”(固定大小的列表)中,与格式化字符串一起使用,格式化字符串中包含常规文本和“参数说明符”等特殊符号,如`%s`,`%d`,`%f`,`%.<小数位数> f`。 + +- `%s` - 字符串(或具有字符串表示的任何对象,如数字) +- `%d` - 整数 +- `%f` - 浮点数 +- `%.<小数位数>f` - 具有固定精度的浮点数 + +```python +# 仅包含字符串 +first_name = 'Asabeneh' +last_name = 'Yetayeh' +language = 'Python' +formated_string = 'I am %s %s. I teach %s' %(first_name, last_name, language) +print(formated_string) + +# 包含字符串和数字 +radius = 10 +pi = 3.14 +area = pi * radius ** 2 +formated_string = 'The area of circle with a radius %d is %.2f.' %(radius, area) # 2表示小数点后的2个有效数字 +python_libraries = ['Django', 'Flask', 'NumPy', 'Matplotlib','Pandas'] +formated_string = 'The following are python libraries:%s' % (python_libraries) +print(formated_string) # "The following are python libraries:['Django', 'Flask', 'NumPy', 'Matplotlib','Pandas']" +``` + +### 新式字符串格式化(str.format) + +这种格式化是在Python 3版中引入的。 + +```python +first_name = 'Asabeneh' +last_name = 'Yetayeh' +language = 'Python' +formated_string = 'I am {} {}. I teach {}'.format(first_name, last_name, language) +print(formated_string) +a = 4 +b = 3 +print('{} + {} = {}'.format(a, b, a + b)) +print('{} - {} = {}'.format(a, b, a - b)) +print('{} * {} = {}'.format(a, b, a * b)) +print('{} / {} = {:.2f}'.format(a, b, a / b)) # 限制小数点后两位 +print('{} % {} = {}'.format(a, b, a % b)) +print('{} // {} = {}'.format(a, b, a // b)) +print('{} ** {} = {}'.format(a, b, a ** b)) + +# 输出 +4 + 3 = 7 +4 - 3 = 1 +4 * 3 = 12 +4 / 3 = 1.33 +4 % 3 = 1 +4 // 3 = 1 +4 ** 3 = 64 + +# 字符串和数字 +radius = 10 +pi = 3.14 +area = pi * radius ** 2 +formated_string = 'The area of a circle with a radius {} is {:.2f}.'.format(radius, area) # 2位 + +小数 +print(formated_string) +``` + +### 字符串插值 / f-Strings(Python 3.6+) + +另一种新的字符串格式化是字符串插值,即f-字符串。字符串以f开头,我们可以在相应的位置注入数据。 + +```python +a = 4 +b = 3 +print(f'{a} + {b} = {a +b}') +print(f'{a} - {b} = {a - b}') +print(f'{a} * {b} = {a * b}') +print(f'{a} / {b} = {a / b:.2f}') +print(f'{a} % {b} = {a % b}') +print(f'{a} // {b} = {a // b}') +print(f'{a} ** {b} = {a ** b}') +``` + +## Python字符串作为字符序列 + +Python字符串是字符序列,与其他Python有序对象的基本访问方法相同——列表和元组。从字符串中提取单个字符的最简单方法(以及从任何序列中提取单个成员)是将它们解包到相应的变量中。 + +### 解包字符 + +```python +language = 'Python' +a,b,c,d,e,f = language # 解包序列字符到变量 +print(a) # P +print(b) # y +print(c) # t +print(d) # h +print(e) # o +print(f) # n +``` + +### 通过索引访问字符串中的字符 + +在编程中,从零开始计数。因此,字符串的第一个字母位于零索引处,字符串的最后一个字母是字符串长度减1。 + +### 切片Python字符串 + +在python中,我们可以将字符串切片成子字符串。 + +```python +language = 'Python' +first_three = language[0:3] # 从零索引开始,直到3,但不包括3 +print(first_three) #Pyt +last_three = language[3:6] +print(last_three) # hon +# 另一种方法 +last_three = language[-3:] +print(last_three) # hon +last_three = language[3:] +print(last_three) # hon +``` + +### 反转字符串 + +我们可以轻松地反转字符串。 + +```python +greeting = 'Hello, World!' +print(greeting[::-1]) # !dlroW ,olleH +``` + +### 在切片时跳过字符 + +在切片时,可以通过将步骤参数传递给切片方法来跳过字符。 + +```python +language = 'Python' +pto = language[0:6:2] # +print(pto) # Pto +``` + +## 字符串方法 + +有许多字符串方法允许我们格式化字符串。请参考以下示例中的一些字符串方法: + +- `capitalize()`: 将字符串的第一个字符转换为大写字母 + +```python +challenge = 'thirty days of python' +print(challenge.capitalize()) # 'Thirty days of python' +``` + +- `count()`: 返回字符串中子字符串的出现次数,`count(substring, start=.., end=..)`。`start`是计数的起始索引,`end`是计数的最后一个索引。 + +```python +challenge = 'thirty days of python' +print(challenge.count('y')) # 3 +print(challenge.count('y', 7, 14)) # 1 +print(challenge.count('th')) # 2 +``` + +- `endswith()`: 检查字符串是否以指定的后缀结束 + +```python +challenge = 'thirty days of python' +print(challenge.endswith('on')) # True +print(challenge.endswith('tion')) # False +``` + +- `expandtabs()`: 用空格替换制表符字符,默认制表符大小为8。它接受制表符大小参数。 + +```python +challenge = 'thirty\tdays\tof\tpython' +print(challenge.expandtabs()) # 'thirty days of python' +print(challenge.expandtabs(10)) # 'thirty days of python' +``` + +- `find()`: 返回子字符串的第一次出现的索引,如果未找到则返回-1 + +```python +challenge = 'thirty days of python' +print(challenge.find('y')) # 5 +print(challenge.find('th')) # 0 +``` + +- `rfind()`: 返回子字符串的最后一次出现的索引,如果未找到则返回-1 + +```python +challenge = 'thirty days of python' +print(challenge.rfind('y')) # 16 +print(challenge.rfind('th')) # 17 +``` + +- `format()`: 将字符串格式化为更好的输出。 + 有关字符串格式化的更多信息,请查看[此链接](https://www.programiz.com/python-programming/methods/string/format) + +```python +first_name = 'Asabeneh' +last_name = 'Yetayeh' +age = 250 +job = 'teacher' +country = 'Finland' +sentence = 'I am {} {}. I am a {}. I am {} years old. I live in {}.'.format(first_name, last_name, age, job, country) +print(sentence) # I am Asabeneh Yetayeh. I am 250 years old. I am a teacher. I live in Finland. + +radius = 10 +pi = 3.14 +area = pi * radius ** 2 +result = 'The area of a circle with radius {} is {}'.format(str(radius), str(area)) +print(result) # The area of a circle with radius 10 is 314 +``` + +- `index()`: 返回子字符串的最低索引,附加参数指示开始和结束索引(默认为0和字符串长度-1)。如果未找到子字符串,则引发ValueError。 + +```python +challenge = 'thirty days of python' +sub_string = 'da' +print(challenge.index(sub_string)) # 7 +print(challenge.index(sub_string, 9)) # 错误 +``` + +- `rindex()`: 返回子字符串的最高索引,附加参数指示开始和结束索引(默认为0和字符串长度-1)。 + +```python +challenge = 'thirty days of python' +sub_string = 'da' +print(challenge.rindex(sub_string)) # 8 +print(challenge.rindex(sub_string, 9)) # 错误 +``` + +- `isalnum()`: 检查是否为字母数字字符 + +```python +challenge = 'ThirtyDaysPython' +print(challenge.isalnum()) # True + +challenge = '30DaysPython' +print(challenge.isalnum()) # True + +challenge = 'thirty days of python' +print(challenge.isalnum()) # False,空格不是字母数字字符 + +challenge = 'thirty days of python 2019' +print(challenge.isalnum()) # False +``` + +- `isalpha()`: 检查字符串中的所有元素是否都是字母字符(a-z和A-Z) + +```python +challenge = 'thirty days of python' +print(challenge.isalpha()) # False,空格再次被排除 +challenge = 'ThirtyDaysPython' +print(challenge.isalpha()) # True +num = '123' +print(num.isalpha()) # False +``` + +- `isdecimal()`: 检查字符串中的所有字符是否都是十进制数字(0-9) + +```python +challenge = 'thirty days of python' +print(challenge.isdecimal()) # False +challenge = '123' +print(challenge.isdecimal()) # True +challenge = '\u00B2' +print(challenge.isdigit()) # False +challenge = '12 3' +print(challenge.isdecimal()) # False,不允许空格 +``` + +- `isdigit()`: 检查字符串中的所有字符是否都是数字(0-9和一些其他用于表示数字的Unicode字符) + +```python +challenge = 'Thirty' +print(challenge.isdigit()) # False +challenge = '30' +print(challenge.isdigit()) # True +challenge = '\u00B2' +print(challenge.isdigit()) # True +``` + +- `isnumeric()`: 检查字符串中的所有字符是否都是数字或与数字有关(与`isdigit()`相似,只接受更多的符号,如½) + +```python +num = '10' +print(num.isnumeric()) # True +num = '\u00BD' # ½ +print(num.isnumeric()) # True +num = '10.5' +print(num.isnumeric()) # False +``` + +- `isidentifier()`: 检查是否为有效标识符 - 它检查字符串是否为有效的变量名 + +```python +challenge = '30DaysOfPython' +print(challenge.isidentifier()) # False,因为以数字开头 +challenge = 'thirty_days_of_python' +print(challenge.isidentifier()) # True +``` + +- `islower()`: 检查字符串中的所有字母字符是否都是小写 + +```python +challenge = 'thirty days of python' +print(challenge.islower()) # True +challenge = 'Thirty days of python' +print(challenge.islower()) # False +``` + +- `isupper()`: 检查字符串中的所有字母字符是否都是大写 + +```python +challenge = 'thirty days of python' +print(challenge.isupper()) # False +challenge = 'THIRTY DAYS OF PYTHON' +print(challenge.isupper()) # True +``` + +- `join()`: 返回连接的字符串 + +```python +web_tech = ['HTML', 'CSS', 'JavaScript', 'React'] +result = ' '.join(web_tech) +print(result) # 'HTML CSS JavaScript React' +``` + +```python +web_tech = ['HTML', 'CSS', 'JavaScript', 'React'] +result = '# '.join(web_tech) +print(result) # 'HTML# CSS# JavaScript# React' +``` + +- `strip()`: 从字符串的开头和结尾删除所有给定的字符 + +> 注意是满足条件的单个字符,不是字符串 + +```python +challenge = 'thirty days of pythoonnn' +print(challenge.strip('noth')) # 'irty days of py' +``` + +- `replace()`: 用给定的字符串替换子字符串 + +```python +challenge = 'thirty days of python' +print(challenge.replace('python', 'coding')) # 'thirty days of coding' +``` + +- `split()`: 使用给定的字符串或空格作为分隔符拆分字符串 + +```python +challenge = 'thirty days of python' +print(challenge.split()) # ['thirty', 'days', 'of', 'python'] +challenge = 'thirty, days, of, python' +print(challenge.split(', ')) # ['thirty', 'days', 'of', 'python'] +``` + +- `title()`: 返回以标题格式的字符串 + +```python +challenge = 'thirty days of python' +print(challenge.title()) # Thirty Days Of Python +``` + +- `swapcase()`: 将所有大写字符转换为小写字符,将所有小写字符转换为大写字符 + +```python +challenge = 'thirty days of python' +print(challenge.swapcase()) # THIRTY DAYS OF PYTHON +challenge = 'Thirty Days Of Python' +print(challenge.swapcase()) # tHIRTY dAYS oF pYTHON +``` + +- `startswith()`: 检查字符串是否以指定的字符串开头 + +```python +challenge = 'thirty days of python' +print(challenge.startswith('thirty')) # True + +challenge = '30 days of python' +print(challenge.startswith('thirty')) # False +``` + +🌕 你是一个非凡的人,拥有卓越的潜力。 你刚刚完成了第4天的挑战,你已经走在了伟大之路上的四步。 现在,为你的大脑和肌肉做一些练习。 + +## 💻 练习 + +1. 将字符串 'Thirty', 'Days', 'Of', 'Python' 连接为一个单一的字符串 'Thirty Days Of Python'。 + +2. 将字符串 'Coding', 'For', 'All' 连接为一个单一的字符串 'Coding For All'。 + +3. 声明一个名为 `company` 的变量,并将其初始值设置为 "Coding For All"。 + +4. 使用 `print()` 打印变量 `company`。 + +5. 使用 `len()` 方法打印字符串 `company` 的长度,并使用 `print()` 打印结果。 + +6. 使用 `upper()` 方法将所有字符更改为大写字母。 + +7. 使用 `lower()` 方法将所有字符更改为小写字母。 + +8. 使用 `capitalize()`、`title()` 和 `swapcase()` 方法格式化字符串值 "Coding For All"。 + +9. 切割出 "Coding For All" 字符串的第一个单词。 + +10. 检查 "Coding For All" 字符串是否包含单词 "Coding",使用 `index()`、`find()` 或其他方法。 + +11. 将字符串 "Coding For All" 中的单词 "Coding" 替换为 "Python"。 + +12. 使用替换方法或其他方法将 "Python for Everyone" 更改为 + + "Python for All"。 + +13. 使用空格作为分隔符(`split()`)拆分字符串 "Coding For All"。 + +14. 请将字符串 "Facebook, Google, Microsoft, Apple, IBM, Oracle, Amazon" 以逗号分隔拆分。 + +15. 字符串 "Coding For All" 中索引为0的字符是什么? + +16. 字符串 "Coding For All" 中的最后一个索引是什么? + +17. 在字符串 "Coding For All" 中的索引10处是什么字符? + +18. 为名称 'Python For Everyone' 创建一个首字母缩写或简称。 + +19. 为名称 'Coding For All' 创建一个首字母缩写或简称。 + +20. 使用 `index()` 确定字符串 "Coding For All" 中C的第一次出现的位置。 + +21. 使用 `index()` 确定字符串 "Coding For All" 中F的第一次出现的位置。 + +22. 使用 `rfind()` 确定字符串 "Coding For All People" 中l的最后一次出现的位置。 + +23. 使用 `index()` 或 `find()` 查找以下句子中单词 'because' 的第一次出现位置:'You cannot end a sentence with because because because is a conjunction'。 + +24. 使用 `rindex()` 查找以下句子中单词 'because' 的最后一次出现位置:'You cannot end a sentence with because because because is a conjunction'。 + +25. 在以下句子中切割出短语 'because because because':'You cannot end a sentence with because because because is a conjunction'。 + +26. 在以下句子中找到单词 'because' 的第一次出现的位置:'You cannot end a sentence with because because because is a conjunction'。 + +27. 在以下句子中切割出短语 'because because because':'You cannot end a sentence with because because because is a conjunction'。 + +28. 字符串 '\Coding For All' 是否以子串 'Coding' 开头? + +29. 字符串 'Coding For All' 是否以子串 'coding' 结尾? + +30. '   Coding For All      '  ,移除给定字符串的左侧和右侧的空格。 + +31. 以下哪个变量在使用 `isidentifier()` 方法时返回 True: + + - 30DaysOfPython + - thirty_days_of_python + +32. 以下列表包含一些Python库的名称:['Django', 'Flask', 'Bottle', 'Pyramid', 'Falcon']。使用空格字符串作为分隔符,将列表连接起来。 + +33. 使用新行转义序列分隔以下句子。 + + ```python + I am enjoying this challenge. + I just wonder what is next. + ``` + +34. 使用制表符转义序列编写以下行。 + + ```python + Name Age Country City + Asabeneh 250 Finland Helsinki + ``` + +35. 使用字符串格式化方法显示以下内容: + +```sh +radius = 10 +area = 3.14 * radius ** 2 +The area of a circle with radius 10 is 314 meters square. +``` + +36. 使用字符串格式化方法制作以下内容: + +```sh +8 + 6 = 14 +8 - 6 = 2 +8 * 6 = 48 +8 / 6 = 1.33 +8 % 6 = 2 +8 // 6 = 1 +8 ** 6 = 262144 +``` diff --git a/04_strings/index.html b/04_strings/index.html new file mode 100644 index 0000000..927bc62 --- /dev/null +++ b/04_strings/index.html @@ -0,0 +1,1960 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 04 字符串 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

04 字符串⚓︎

+

文本是一种字符串数据类型。任何以文本形式编写的数据类型都是字符串。任何在单引号、双引号或三重引号下的数据都是字符串。有不同的字符串方法和内置函数来处理字符串数据类型。要检查字符串的长度,请使用len()方法。

+

创建字符串⚓︎

+
letter = 'P'                # 一个字符串可以是一个单字符或一堆文本
+print(letter)               # P
+print(len(letter))          # 1
+greeting = 'Hello, World!'  # 字符串可以使用单引号或双引号创建,"Hello, World!"
+print(greeting)             # Hello, World!
+print(len(greeting))        # 13
+sentence = "I hope you are enjoying 30 days of Python Challenge"
+print(sentence)
+
+

多行字符串可以使用三重单引号''''或三重双引号""""创建。请参考以下示例。

+
multiline_string = '''I am a teacher and enjoy teaching.
+I didn't find anything as rewarding as empowering people.
+That is why I created 30 days of python.'''
+print(multiline_string)
+
+# 还有另一种做同样事情的方法
+multiline_string = """I am a teacher and enjoy teaching.
+I didn't find anything as rewarding as empowering people.
+That is why I created 30 days of python."""
+print(multiline_string)
+
+

字符串连接⚓︎

+

我们可以将字符串连接在一起。合并或连接字符串称为字符串连接。请参考以下示例:

+
first_name = 'Asabeneh'
+last_name = 'Yetayeh'
+space = ' '
+full_name = first_name  +  space + last_name
+print(full_name) # Asabeneh Yetayeh
+# 使用len()内置函数检查字符串的长度
+print(len(first_name))  # 8
+print(len(last_name))   # 7
+print(len(first_name) > len(last_name)) # True
+print(len(full_name)) # 16
+
+

字符串中的转义序列⚓︎

+

在Python和其他编程语言中,\后面跟着一个字符是转义序列。让我们看看最常见的转义字符:

+
    +
  • \n:换行
  • +
  • \t:制表符(相当于8个空格)
  • +
  • \:反斜杠
  • +
  • \':单引号
  • +
  • \\":双引号"
  • +
+

现在,让我们使用示例来了解上述转义序列的用法。

+
print('I hope everyone is enjoying the Python Challenge.\nAre you ?') # 换行
+print('Days\tTopics\tExercises') # 添加制表符或4个空格
+print('Day 1\t5\t5')
+print('Day 2\t6\t20')
+print('Day 3\t5\t23')
+print('Day 4\t1\t35')
+print('This is a backslash  symbol (\\)') # 写一个反斜杠
+print('In every programming language it starts with \"Hello, World!\"') # 在单引号内写双引号
+
+# 输出
+I hope every one is enjoying the Python Challenge.
+Are you ?
+Days    Topics  Exercises
+Day 1   5       5
+Day 2   6       20
+Day 3   5       23
+Day 4   1       35
+This is a backslash  symbol (\)
+In every programming language it starts with "Hello, World!"
+
+

字符串格式化⚓︎

+

旧式字符串格式化(%运算符)⚓︎

+

在Python中,有许多格式化字符串的方式。在本节中,我们将介绍其中一些。 +%运算符用于格式化一组变量,这些变量包含在一个“元组”(固定大小的列表)中,与格式化字符串一起使用,格式化字符串中包含常规文本和“参数说明符”等特殊符号,如%s%d%f%.<小数位数> f

+
    +
  • %s - 字符串(或具有字符串表示的任何对象,如数字)
  • +
  • %d - 整数
  • +
  • %f - 浮点数
  • +
  • %.<小数位数>f - 具有固定精度的浮点数
  • +
+
# 仅包含字符串
+first_name = 'Asabeneh'
+last_name = 'Yetayeh'
+language = 'Python'
+formated_string = 'I am %s %s. I teach %s' %(first_name, last_name, language)
+print(formated_string)
+
+# 包含字符串和数字
+radius = 10
+pi = 3.14
+area = pi * radius ** 2
+formated_string = 'The area of circle with a radius %d is %.2f.' %(radius, area) # 2表示小数点后的2个有效数字
+python_libraries = ['Django', 'Flask', 'NumPy', 'Matplotlib','Pandas']
+formated_string = 'The following are python libraries:%s' % (python_libraries)
+print(formated_string) # "The following are python libraries:['Django', 'Flask', 'NumPy', 'Matplotlib','Pandas']"
+
+

新式字符串格式化(str.format)⚓︎

+

这种格式化是在Python 3版中引入的。

+
first_name = 'Asabeneh'
+last_name = 'Yetayeh'
+language = 'Python'
+formated_string = 'I am {} {}. I teach {}'.format(first_name, last_name, language)
+print(formated_string)
+a = 4
+b = 3
+print('{} + {} = {}'.format(a, b, a + b))
+print('{} - {} = {}'.format(a, b, a - b))
+print('{} * {} = {}'.format(a, b, a * b))
+print('{} / {} = {:.2f}'.format(a, b, a / b)) # 限制小数点后两位
+print('{} % {} = {}'.format(a, b, a % b))
+print('{} // {} = {}'.format(a, b, a // b))
+print('{} ** {} = {}'.format(a, b, a ** b))
+
+# 输出
+4 + 3 = 7
+4 - 3 = 1
+4 * 3 = 12
+4 / 3 = 1.33
+4 % 3 = 1
+4 // 3 = 1
+4 ** 3 = 64
+
+# 字符串和数字
+radius = 10
+pi = 3.14
+area = pi * radius ** 2
+formated_string = 'The area of a circle with a radius {} is {:.2f}.'.format(radius, area) # 2位
+
+小数
+print(formated_string)
+
+

字符串插值 / f-Strings(Python 3.6+)⚓︎

+

另一种新的字符串格式化是字符串插值,即f-字符串。字符串以f开头,我们可以在相应的位置注入数据。

+
a = 4
+b = 3
+print(f'{a} + {b} = {a +b}')
+print(f'{a} - {b} = {a - b}')
+print(f'{a} * {b} = {a * b}')
+print(f'{a} / {b} = {a / b:.2f}')
+print(f'{a} % {b} = {a % b}')
+print(f'{a} // {b} = {a // b}')
+print(f'{a} ** {b} = {a ** b}')
+
+

Python字符串作为字符序列⚓︎

+

Python字符串是字符序列,与其他Python有序对象的基本访问方法相同——列表和元组。从字符串中提取单个字符的最简单方法(以及从任何序列中提取单个成员)是将它们解包到相应的变量中。

+

解包字符⚓︎

+
language = 'Python'
+a,b,c,d,e,f = language # 解包序列字符到变量
+print(a) # P
+print(b) # y
+print(c) # t
+print(d) # h
+print(e) # o
+print(f) # n
+
+

通过索引访问字符串中的字符⚓︎

+

在编程中,从零开始计数。因此,字符串的第一个字母位于零索引处,字符串的最后一个字母是字符串长度减1。

+

切片Python字符串⚓︎

+

在python中,我们可以将字符串切片成子字符串。

+
language = 'Python'
+first_three = language[0:3] # 从零索引开始,直到3,但不包括3
+print(first_three) #Pyt
+last_three = language[3:6]
+print(last_three) # hon
+# 另一种方法
+last_three = language[-3:]
+print(last_three)   # hon
+last_three = language[3:]
+print(last_three)   # hon
+
+

反转字符串⚓︎

+

我们可以轻松地反转字符串。

+
greeting = 'Hello, World!'
+print(greeting[::-1]) # !dlroW ,olleH
+
+

在切片时跳过字符⚓︎

+

在切片时,可以通过将步骤参数传递给切片方法来跳过字符。

+
language = 'Python'
+pto = language[0:6:2] #
+print(pto) # Pto
+
+

字符串方法⚓︎

+

有许多字符串方法允许我们格式化字符串。请参考以下示例中的一些字符串方法:

+
    +
  • capitalize(): 将字符串的第一个字符转换为大写字母
  • +
+
challenge = 'thirty days of python'
+print(challenge.capitalize()) # 'Thirty days of python'
+
+
    +
  • count(): 返回字符串中子字符串的出现次数,count(substring, start=.., end=..)start是计数的起始索引,end是计数的最后一个索引。
  • +
+
challenge = 'thirty days of python'
+print(challenge.count('y')) # 3
+print(challenge.count('y', 7, 14)) # 1
+print(challenge.count('th')) # 2
+
+
    +
  • endswith(): 检查字符串是否以指定的后缀结束
  • +
+
challenge = 'thirty days of python'
+print(challenge.endswith('on'))   # True
+print(challenge.endswith('tion')) # False
+
+
    +
  • expandtabs(): 用空格替换制表符字符,默认制表符大小为8。它接受制表符大小参数。
  • +
+
challenge = 'thirty\tdays\tof\tpython'
+print(challenge.expandtabs())   # 'thirty  days    of      python'
+print(challenge.expandtabs(10)) # 'thirty    days      of        python'
+
+
    +
  • find(): 返回子字符串的第一次出现的索引,如果未找到则返回-1
  • +
+
challenge = 'thirty days of python'
+print(challenge.find('y'))  # 5
+print(challenge.find('th')) # 0
+
+
    +
  • rfind(): 返回子字符串的最后一次出现的索引,如果未找到则返回-1
  • +
+
challenge = 'thirty days of python'
+print(challenge.rfind('y'))  # 16
+print(challenge.rfind('th')) # 17
+
+
    +
  • format(): 将字符串格式化为更好的输出。 + 有关字符串格式化的更多信息,请查看此链接
  • +
+
first_name = 'Asabeneh'
+last_name = 'Yetayeh'
+age = 250
+job = 'teacher'
+country = 'Finland'
+sentence = 'I am {} {}. I am a {}. I am {} years old. I live in {}.'.format(first_name, last_name, age, job, country)
+print(sentence) # I am Asabeneh Yetayeh. I am 250 years old. I am a teacher. I live in Finland.
+
+radius = 10
+pi = 3.14
+area = pi * radius ** 2
+result = 'The area of a circle with radius {} is {}'.format(str(radius), str(area))
+print(result) # The area of a circle with radius 10 is 314
+
+
    +
  • index(): 返回子字符串的最低索引,附加参数指示开始和结束索引(默认为0和字符串长度-1)。如果未找到子字符串,则引发ValueError。
  • +
+
challenge = 'thirty days of python'
+sub_string = 'da'
+print(challenge.index(sub_string))  # 7
+print(challenge.index(sub_string, 9)) # 错误
+
+
    +
  • rindex(): 返回子字符串的最高索引,附加参数指示开始和结束索引(默认为0和字符串长度-1)。
  • +
+
challenge = 'thirty days of python'
+sub_string = 'da'
+print(challenge.rindex(sub_string))  # 8
+print(challenge.rindex(sub_string, 9)) # 错误
+
+
    +
  • isalnum(): 检查是否为字母数字字符
  • +
+
challenge = 'ThirtyDaysPython'
+print(challenge.isalnum()) # True
+
+challenge = '30DaysPython'
+print(challenge.isalnum()) # True
+
+challenge = 'thirty days of python'
+print(challenge.isalnum()) # False,空格不是字母数字字符
+
+challenge = 'thirty days of python 2019'
+print(challenge.isalnum()) # False
+
+
    +
  • isalpha(): 检查字符串中的所有元素是否都是字母字符(a-z和A-Z)
  • +
+
challenge = 'thirty days of python'
+print(challenge.isalpha()) # False,空格再次被排除
+challenge = 'ThirtyDaysPython'
+print(challenge.isalpha()) # True
+num = '123'
+print(num.isalpha())      # False
+
+
    +
  • isdecimal(): 检查字符串中的所有字符是否都是十进制数字(0-9)
  • +
+
challenge = 'thirty days of python'
+print(challenge.isdecimal())  # False
+challenge = '123'
+print(challenge.isdecimal())  # True
+challenge = '\u00B2'
+print(challenge.isdigit())   # False
+challenge = '12 3'
+print(challenge.isdecimal())  # False,不允许空格
+
+
    +
  • isdigit(): 检查字符串中的所有字符是否都是数字(0-9和一些其他用于表示数字的Unicode字符)
  • +
+
challenge = 'Thirty'
+print(challenge.isdigit()) # False
+challenge = '30'
+print(challenge.isdigit())   # True
+challenge = '\u00B2'
+print(challenge.isdigit())   # True
+
+
    +
  • isnumeric(): 检查字符串中的所有字符是否都是数字或与数字有关(与isdigit()相似,只接受更多的符号,如½)
  • +
+
num = '10'
+print(num.isnumeric()) # True
+num = '\u00BD' # ½
+print(num.isnumeric()) # True
+num = '10.5'
+print(num.isnumeric()) # False
+
+
    +
  • isidentifier(): 检查是否为有效标识符 - 它检查字符串是否为有效的变量名
  • +
+
challenge = '30DaysOfPython'
+print(challenge.isidentifier()) # False,因为以数字开头
+challenge = 'thirty_days_of_python'
+print(challenge.isidentifier()) # True
+
+
    +
  • islower(): 检查字符串中的所有字母字符是否都是小写
  • +
+
challenge = 'thirty days of python'
+print(challenge.islower()) # True
+challenge = 'Thirty days of python'
+print(challenge.islower()) # False
+
+
    +
  • isupper(): 检查字符串中的所有字母字符是否都是大写
  • +
+
challenge = 'thirty days of python'
+print(challenge.isupper()) # False
+challenge = 'THIRTY DAYS OF PYTHON'
+print(challenge.isupper()) # True
+
+
    +
  • join(): 返回连接的字符串
  • +
+
web_tech = ['HTML', 'CSS', 'JavaScript', 'React']
+result = ' '.join(web_tech)
+print(result) # 'HTML CSS JavaScript React'
+
+
web_tech = ['HTML', 'CSS', 'JavaScript', 'React']
+result = '# '.join(web_tech)
+print(result) # 'HTML# CSS# JavaScript# React'
+
+
    +
  • strip(): 从字符串的开头和结尾删除所有给定的字符
  • +
+
+

注意是满足条件的单个字符,不是字符串

+
+
challenge = 'thirty days of pythoonnn'
+print(challenge.strip('noth')) # 'irty days of py'
+
+
    +
  • replace(): 用给定的字符串替换子字符串
  • +
+
challenge = 'thirty days of python'
+print(challenge.replace('python', 'coding')) # 'thirty days of coding'
+
+
    +
  • split(): 使用给定的字符串或空格作为分隔符拆分字符串
  • +
+
challenge = 'thirty days of python'
+print(challenge.split()) # ['thirty', 'days', 'of', 'python']
+challenge = 'thirty, days, of, python'
+print(challenge.split(', ')) # ['thirty', 'days', 'of', 'python']
+
+
    +
  • title(): 返回以标题格式的字符串
  • +
+
challenge = 'thirty days of python'
+print(challenge.title()) # Thirty Days Of Python
+
+
    +
  • swapcase(): 将所有大写字符转换为小写字符,将所有小写字符转换为大写字符
  • +
+
challenge = 'thirty days of python'
+print(challenge.swapcase())   # THIRTY DAYS OF PYTHON
+challenge = 'Thirty Days Of Python'
+print(challenge.swapcase())  # tHIRTY dAYS oF pYTHON
+
+
    +
  • startswith(): 检查字符串是否以指定的字符串开头
  • +
+
challenge = 'thirty days of python'
+print(challenge.startswith('thirty')) # True
+
+challenge = '30 days of python'
+print(challenge.startswith('thirty')) # False
+
+

🌕 你是一个非凡的人,拥有卓越的潜力。 你刚刚完成了第4天的挑战,你已经走在了伟大之路上的四步。 现在,为你的大脑和肌肉做一些练习。

+

💻 练习⚓︎

+
    +
  1. +

    将字符串 'Thirty', 'Days', 'Of', 'Python' 连接为一个单一的字符串 'Thirty Days Of Python'。

    +
  2. +
  3. +

    将字符串 'Coding', 'For', 'All' 连接为一个单一的字符串 'Coding For All'。

    +
  4. +
  5. +

    声明一个名为 company 的变量,并将其初始值设置为 "Coding For All"。

    +
  6. +
  7. +

    使用 print() 打印变量 company

    +
  8. +
  9. +

    使用 len() 方法打印字符串 company 的长度,并使用 print() 打印结果。

    +
  10. +
  11. +

    使用 upper() 方法将所有字符更改为大写字母。

    +
  12. +
  13. +

    使用 lower() 方法将所有字符更改为小写字母。

    +
  14. +
  15. +

    使用 capitalize()title()swapcase() 方法格式化字符串值 "Coding For All"。

    +
  16. +
  17. +

    切割出 "Coding For All" 字符串的第一个单词。

    +
  18. +
  19. +

    检查 "Coding For All" 字符串是否包含单词 "Coding",使用 index()find() 或其他方法。

    +
  20. +
  21. +

    将字符串 "Coding For All" 中的单词 "Coding" 替换为 "Python"。

    +
  22. +
  23. +

    使用替换方法或其他方法将 "Python for Everyone" 更改为

    +
  24. +
+

"Python for All"。

+
    +
  1. +

    使用空格作为分隔符(split())拆分字符串 "Coding For All"。

    +
  2. +
  3. +

    请将字符串 "Facebook, Google, Microsoft, Apple, IBM, Oracle, Amazon" 以逗号分隔拆分。

    +
  4. +
  5. +

    字符串 "Coding For All" 中索引为0的字符是什么?

    +
  6. +
  7. +

    字符串 "Coding For All" 中的最后一个索引是什么?

    +
  8. +
  9. +

    在字符串 "Coding For All" 中的索引10处是什么字符?

    +
  10. +
  11. +

    为名称 'Python For Everyone' 创建一个首字母缩写或简称。

    +
  12. +
  13. +

    为名称 'Coding For All' 创建一个首字母缩写或简称。

    +
  14. +
  15. +

    使用 index() 确定字符串 "Coding For All" 中C的第一次出现的位置。

    +
  16. +
  17. +

    使用 index() 确定字符串 "Coding For All" 中F的第一次出现的位置。

    +
  18. +
  19. +

    使用 rfind() 确定字符串 "Coding For All People" 中l的最后一次出现的位置。

    +
  20. +
  21. +

    使用 index()find() 查找以下句子中单词 'because' 的第一次出现位置:'You cannot end a sentence with because because because is a conjunction'。

    +
  22. +
  23. +

    使用 rindex() 查找以下句子中单词 'because' 的最后一次出现位置:'You cannot end a sentence with because because because is a conjunction'。

    +
  24. +
  25. +

    在以下句子中切割出短语 'because because because':'You cannot end a sentence with because because because is a conjunction'。

    +
  26. +
  27. +

    在以下句子中找到单词 'because' 的第一次出现的位置:'You cannot end a sentence with because because because is a conjunction'。

    +
  28. +
  29. +

    在以下句子中切割出短语 'because because because':'You cannot end a sentence with because because because is a conjunction'。

    +
  30. +
  31. +

    字符串 '\Coding For All' 是否以子串 'Coding' 开头?

    +
  32. +
  33. +

    字符串 'Coding For All' 是否以子串 'coding' 结尾?

    +
  34. +
  35. +

    '   Coding For All      '  ,移除给定字符串的左侧和右侧的空格。

    +
  36. +
  37. +

    以下哪个变量在使用 isidentifier() 方法时返回 True:

    +
      +
    • 30DaysOfPython
    • +
    • thirty_days_of_python
    • +
    +
  38. +
  39. +

    以下列表包含一些Python库的名称:['Django', 'Flask', 'Bottle', 'Pyramid', 'Falcon']。使用空格字符串作为分隔符,将列表连接起来。

    +
  40. +
  41. +

    使用新行转义序列分隔以下句子。

    +
    I am enjoying this challenge.
    +I just wonder what is next.
    +
    +
  42. +
  43. +

    使用制表符转义序列编写以下行。

    +
    Name      Age     Country   City
    +Asabeneh  250     Finland   Helsinki
    +
    +
  44. +
  45. +

    使用字符串格式化方法显示以下内容:

    +
  46. +
+
radius = 10
+area = 3.14 * radius ** 2
+The area of a circle with radius 10 is 314 meters square.
+
+
    +
  1. 使用字符串格式化方法制作以下内容:
  2. +
+
8 + 6 = 14
+8 - 6 = 2
+8 * 6 = 48
+8 / 6 = 1.33
+8 % 6 = 2
+8 // 6 = 1
+8 ** 6 = 262144
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/05_lists/05_lists.md b/05_lists/05_lists.md new file mode 100644 index 0000000..ae7eb4d --- /dev/null +++ b/05_lists/05_lists.md @@ -0,0 +1,579 @@ +# 05 列表 + +## 列表 + +Python 中有四种集合数据类型: + +- 列表(List):是一种有序且可更改的集合。允许重复成员。 +- 元组(Tuple):是一种有序且不可更改的集合。允许重复成员。 +- 集合(Set):是一种无序、无索引且不可更改的集合,但我们可以向集合添加新项目。不允许重复成员。 +- 字典(Dictionary):是一种无序、可更改的集合,并具有索引。不允许重复成员。 + +列表是一种包含不同数据类型的集合,它是有序且可修改(可变)的。列表可以为空,也可以包含不同数据类型的项。 + +### 如何创建列表 + +在 Python 中,我们可以以两种方式创建列表: + +- 使用列表内置函数 + +```python +# 语法 +lst = list() +``` + +```python +empty_list = list() # 这是一个空列表,列表中没有任何项目 +print(len(empty_list)) # 0 +``` + +- 使用方括号`[]` + +```python +# 语法 +lst = [] +``` + +```python +empty_list = [] # 这是一个空列表,列表中没有任何项目 +print(len(empty_list)) # 0 +``` + +具有初始值的列表。我们使用 `len()` 来查找列表的长度。 + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] # 水果列表 +vegetables = ['Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot'] # 蔬菜列表 +animal_products = ['milk', 'meat', 'butter', 'yoghurt'] # 动物产品列表 +web_techs = ['HTML', 'CSS', 'JS', 'React', 'Redux', 'Node', 'MongDB'] # Web 技术列表 +countries = ['Finland', 'Estonia', 'Denmark', 'Sweden', 'Norway'] + +# 打印列表及其长度 +print('水果:', fruits) +print('水果数量:', len(fruits)) +print('蔬菜:', vegetables) +print('蔬菜数量:', len(vegetables)) +print('动物产品:', animal_products) +print('动物产品数量:', len(animal_products)) +print('Web 技术:', web_techs) +print('Web 技术数量:', len(web_techs)) +print('国家:', countries) +print('国家数量:', len(countries)) +``` + +```sh +输出结果 +水果: ['banana', 'orange', 'mango', 'lemon'] +水果数量: 4 +蔬菜: ['Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot'] +蔬菜数量: 5 +动物产品: ['milk', 'meat', 'butter', 'yoghurt'] +动物产品数量: 4 +Web 技术: ['HTML', 'CSS', 'JS', 'React', 'Redux', 'Node', 'MongDB'] +Web 技术数量: 7 +国家: ['Finland', 'Estonia', 'Denmark', 'Sweden', 'Norway'] +国家数量: 5 +``` + +- 列表可以包含不同数据类型的项 + +```python +lst = ['Asabeneh', 250, True, {'country': 'Finland', 'city': 'Helsinki'}] # 包含不同数据类型的列表 +``` + +### 使用正向索引访问列表项 + +我们使用它们的索引访问列表中的每个项目。列表索引从 0 开始。下面的图片清楚地显示了索引从哪里开始。 + +![List index](./images/list_index.png) + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +first_fruit = fruits[0] # 我们使用索引访问第一个项目 +print(first_fruit) # banana +second_fruit = fruits[1] +print(second_fruit) # orange +last_fruit = fruits[3] +print(last_fruit) # lemon +# 最后一个索引 +last_index = len(fruits) - 1 +last_fruit = fruits[last_index] +``` + +### 使用负向索引访问列表项 + +负索引意味着从末尾开始,-1 表示最后一个项目,-2 表示倒数第二个项目。 + +![List negative indexing](./images/list_negative_indexing.png) + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +first_fruit = fruits[-4] +last_fruit = fruits[-1] +second_last = fruits[-2] +print(first_fruit) # banana +print(last_fruit) # lemon +print(second_last) # mango +``` + +### 解包 + +```python +lst = ['item1', 'item2', 'item3', 'item4', 'item5'] +first_item, second_item, third_item, *rest = lst +print(first_item) # item1 +print(second_item) # item2 +print(third_item) # item3 +print(rest) # ['item4', 'item5'] + +``` + +```python +# 第一个示例 +fruits = ['banana', 'orange', 'mango', 'lemon', 'lime', 'apple'] +first_fruit, second_fruit, third_fruit, *rest = fruits +print(first_fruit) # banana +print(second_fruit) # orange +print(third_fruit) # mango +print(rest) # ['lemon', 'lime', 'apple'] +# 第二个示例关于解包列表 +first, second, third, *rest, tenth = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +print(first) # 1 +print(second) # 2 +print(third) # 3 +print(rest) # [4, 5, 6, 7, 8, 9] +print(tenth) # 10 +# 第三个示例关于解包列表 +countries = ['Germany', 'France', 'Belgium', 'Sweden', 'Denmark', 'Finland', 'Norway', 'Iceland', 'Estonia'] +gr, fr, bg, sw, *scandic, es = countries +print(gr) +print(fr) +print(bg) +print(sw) +print(scandic) +print(es) +``` + +>`*` 用于变量前表示解包**列表**或**元组**中的剩余元素。 + +### 切片 + +- 正向索引:我们可以通过指定开始、结束和步骤来指定一系列正索引,返回值将是一个新列表(开始默认值为 0,结束默认值为 len(lst)-1(最后一项),步长默认值为 1)。 + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +all_fruits = fruits[0:4] # 返回所有水果 +# 如果我们不设置停止位置,它将获取所有的其余水果 +all_fruits = fruits[0:] # 如果我们不设置停止位置,它将获取所有的其余水果 +orange_and_mango = fruits[1:3] # 它不包括第一个索引 +orange_mango_lemon = fruits[1:] # 从 1 开始取到结束 +orange_and_lemon = fruits[::2] # 在这里,我们使用了第三个参数,步骤。它会每隔 2 个项目取一个 - ['banana', 'mango'] +``` + +- 负向索引:我们可以通过指定开始、结束和步长来指定一系列负向索引,返回值将是一个新列表。 + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +all_fruits = fruits[-4:] # 返回所有水果 +orange_and_mango = fruits[-3:-1] # 它不包括最后一个索引,['orange', 'mango'] +orange_mango_lemon = fruits[-3:] # 这将从 -3 开始到结束,['orange', 'mango', 'lemon'] +reverse_fruits = fruits[::-1] # 负步骤将以相反的顺序获取列表,['lemon', 'mango', 'orange', 'banana'] +``` + +### 修改 + +列表是一个可变的有序集合。让我们修改水果列表。 + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +fruits[0] = 'avocado' +print(fruits) # ['avocado', 'orange', 'mango', 'lemon'] +fruits[1] = 'apple' +print(fruits) # ['avocado', 'apple', 'mango', 'lemon'] +last_index = len(fruits) - 1 +fruits[last_index] = 'lime' +print(fruits) # ['avocado', 'apple', 'mango', 'lime'] +``` + +### 检查 + +使用 `in` 运算符检查项是否是列表的成员。查看下面的示例。 + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +does_exist = 'banana' in fruits +print(does_exist) # True +does_exist = 'lime' in fruits +print(does_exist) # False +``` + +### 添加 + +要将项目添加到现有列表的末尾,我们使用 `append()` 方法。 + +```python +# 语法 +lst = list() +lst.append(item) +``` + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +fruits.append('apple') +print(fruits) # ['banana', 'orange', 'mango', 'lemon', 'apple'] +fruits.append('lime') # ['banana', 'orange', 'mango', 'lemon', 'apple', 'lime'] +print(fruits) +``` + +### 插入 + +我们可以使用 `insert()` 方法在列表中指定的索引处插入单个项目。请注意,其他项目将向右移动。`insert()` 方法接受两个参数:索引和要插入的项目。 + +```python +# 语法 +lst = ['item1', 'item2'] +lst.insert(index, item) +``` + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +fruits.insert(2, 'apple') # 在橙子和芒果之间插入苹果 +print(fruits) # ['banana', 'orange', 'apple', 'mango', 'lemon'] +fruits.insert(3, 'lime') # ['banana', 'orange', 'apple', 'lime', 'mango', 'lemon'] +print(fruits) +``` + +### 删除 + +`remove()`方法从列表中删除指定的项目 + +```python +# 语法 +lst = ['item1', 'item2'] +lst.remove(item) +``` + +```python +fruits = ['banana', 'orange', 'mango', 'lemon', 'banana'] +fruits.remove('banana') +print(fruits) # ['orange', 'mango', 'lemon', 'banana'] - 此方法删除列表中的第一个出现的项目 +fruits.remove('lemon') +print(fruits) # ['orange', 'mango', 'banana'] +``` + +#### Pop 删除 + +*pop()* 方法删除指定的索引(或如果未指定索引,则删除最后一个项目): + +```python +# 语法 +lst = ['item1', 'item2'] +lst.pop() # 最后一个项目 +lst.pop(index) +``` + +```python +fruits = ['banana', 'orange', 'mango', 'lemon'] +fruits.pop() +print(fruits) # ['banana', 'orange', 'mango'] + +fruits.pop(0) +print(fruits) # ['orange', 'mango'] +``` + +#### Del 删除 + +`del` 关键字用于删除指定的索引,还可以用于删除索引范围内的项目。它还可以完全删除列表。 + +```py +# 语法 +lst = ['item1', 'item2'] +del lst[index] # 仅删除单个项目 +del lst # 删除整个列表 +``` + +```py +fruits = ['banana', 'orange', 'mango', 'lemon', 'kiwi', 'lime'] +del fruits[0] +print(fruits) # ['orange', 'mango', 'lemon', 'kiwi', 'lime'] +del fruits[1] +print(fruits) # ['orange', 'lemon', 'kiwi', 'lime'] +del fruits[1:3] # 这将删除给定索引之间的项目,因此它不会删除索引为3的项目! +print(fruits) # ['orange', 'lime'] +del fruits +print(fruits) # 这将输出:NameError: name 'fruits' is not defined +``` + +#### 清除 + +`clear()` 方法会清空列表: + +```py +# 语法 +lst = ['item1', 'item2'] +lst.clear() +``` + +```py +fruits = ['banana', 'orange', 'mango', 'lemon'] +fruits.clear() +print(fruits) # [] +``` + +### 复制 + +可以通过将其重新分配给新变量来复制列表,如下所示:list2 = list1。现在,list2 是 list1 的引用,我们在 list2 中进行的任何更改也将修改原始的 list1。但是,有很多情况下,我们不喜欢修改原始的列表,而是希望有一个不同的副本。避免上述问题的一种方法是使用`copy()`。 + +```py +# 语法 +lst = ['item1', 'item2'] +lst_copy = lst.copy() +``` + +```py +fruits = ['banana', 'orange', 'mango', 'lemon'] +fruits_copy = fruits.copy() +print(fruits_copy) # ['banana', 'orange', 'mango', 'lemon'] +``` + +### 连接 + +在Python中,有多种连接两个或多个列表的方法。 + +- 加号运算符`+` + +```py +# 语法 +list3 = list1 + list2 +``` + +```py +positive_numbers = [1, 2, 3, 4, 5] +zero = [0] +negative_numbers = [-5,-4,-3,-2,-1] +integers = negative_numbers + zero + positive_numbers +print(integers) # [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5] +fruits = ['banana', 'orange', 'mango', 'lemon'] +vegetables = ['Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot'] +fruits_and_vegetables = fruits + vegetables +print(fruits_and_vegetables ) # ['banana', 'orange', 'mango', 'lemon', 'Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot'] +``` + +- 使用`extend()`方法连接 + `extend()` 方法允许在列表中附加另一个列表。请参见以下示例。 + +```py +# 语法 +list1 = ['item1', 'item2'] +list2 = ['item3', 'item4', 'item5'] +list1.extend(list2) +``` + +```py +num1 = [0, 1, 2, 3] +num2= [4, 5, 6] +num1.extend(num2) +print('Numbers:', num1) # Numbers: [0, 1, 2, 3, 4, 5, 6] +negative_numbers = [-5,-4,-3,-2,-1] +positive_numbers = [1, 2, 3,4,5] +zero = [0] + +negative_numbers.extend(zero) +negative_numbers.extend(positive_numbers) +print('Integers:', negative_numbers) # Integers: [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5] +fruits = ['banana', 'orange', 'mango', 'lemon'] +vegetables = ['Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot'] +fruits.extend(vegetables) +print('Fruits and vegetables:', fruits ) # Fruits and vegetables: ['banana', 'orange', 'mango', 'lemon', 'Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot'] +``` + +### 计数 + +`count()` 方法返回列表中项目出现的次数: + +```py +# 语法 +lst = ['item1', 'item2'] +lst.count(item) +``` + +```py +fruits = ['banana', 'orange', 'mango', 'lemon'] +print(fruits.count('orange')) # 1 +ages = [22, 19, 24, 25, 26, 24, 25, 24] +print(ages.count(24)) # 3 +``` + +### 查找 + +`index()` 方法返回列表中项目的索引: + +```py +# 语法 +lst = ['item1', 'item2'] +lst.index(item) +``` + +```py +fruits = ['banana', 'orange', 'mango', 'lemon'] +print(fruits.index('orange')) # 1 +ages = [22, 19, 24, 25, 26, 24, 25, 24] +print(ages.index(24)) # 2,第一次出现 +``` + +### 反转 + +`reverse()` 方法反转列表的顺序。 + +```py +# 语法 +lst = ['item1', 'item2'] +lst.reverse() +``` + +```py +fruits = ['banana', 'orange', 'mango', 'lemon'] +fruits.reverse() +print(fruits) # ['lemon', 'mango', 'orange', 'banana'] +ages = [22, 19, 24, 25, 26, 24, 25, 24] +ages.reverse() +print(ages) # [24, 25, 24, 26, 25, 24, 19, 22] +``` + +### 排序 + +要对列表进行排序,可以使用 `sort()` 方法或内置的 `sorted()` 函数。`sort()` 方法会按升序重新排列列表项并修改原始列表。如果 `sort()` 方法的 reverse 参数等于 true,则会按降序 + +排列列表。 + +- `sort()`:此方法会修改原始列表 + + ```py + # 语法 + lst = ['item1', 'item2'] + lst.sort() # 升序 + lst.sort(reverse=True) # 降序 + ``` + + **示例:** + + ```py + fruits = ['banana', 'orange', 'mango', 'lemon'] + fruits.sort() + print(fruits) # 按字母顺序排序,['banana', 'lemon', 'mango', 'orange'] + fruits.sort(reverse=True) + print(fruits) # ['orange', 'mango', 'lemon', 'banana'] + ages = [22, 19, 24, 25, 26, 24, 25, 24] + ages.sort() + print(ages) # [19, 22, 24, 24, 24, 25, 25, 26] + + ages.sort(reverse=True) + print(ages) # [26, 25, 25, 24, 24, 24, 22, 19] + ``` + + - `sorted()`:返回有序的列表,不会修改原始列表 + **示例:** + + ```py + fruits = ['banana', 'orange', 'mango', 'lemon'] + print(sorted(fruits)) # ['banana', 'lemon', 'mango', 'orange'] + # 反向排序 + fruits = ['banana', 'orange', 'mango', 'lemon'] + fruits = sorted(fruits, reverse=True) + print(fruits) # ['orange', 'mango', 'lemon', 'banana'] + ``` + + +## 补充 + +### In-place + +在Python中,“In-place”(原地)操作指的是直接修改数据结构中的数据,而不是创建一个新的数据结构。这种操作常见于可变数据类型,如列表、字典或集合。使用原地操作可以提高效率,因为它避免了创建新对象和复制数据的开销。 + +例如,列表的 `append()` 或 `extend()` 方法就会原地修改列表,添加新的元素,而不是返回一个包含了新元素的新列表。另一个例子是使用 `+=` 运算符对列表进行原地扩展。 + +需要注意的是,原地操作可能会影响代码的可读性和维护性,尤其是在复杂的数据结构和算法中。此外,对于不可变数据类型(如整数、字符串和元组),是不支持原地操作的。在对这些类型的数据进行操作时,通常会生成并返回一个新的对象。 + +## 💻 练习 + +### 练习:Level 1 + +1. 声明一个空列表 + +2. 声明一个包含5个以上项目的列表 + +3. 找出列表的长度 + +4. 获取列表的第一个项目、中间项目和最后一个项目 + +5. 声明一个名为mixed_data_types的列表,包括你的名字、年龄、身高、婚姻状况和地址 + +6. 声明一个名为it_companies的列表变量,并分配初始值Facebook、Google、Microsoft、Apple、IBM、Oracle和Amazon。 + +7. 使用_print()_打印列表 + +8. 打印列表中的公司数量 + +9. 打印第一个、中间和最后一个公司 + +10. 修改一个公司后,打印列表 + +11. 向it_companies添加一个IT公司 + +12. 在公司列表中间插入一个IT公司 + +13. 将it_companies的一个公司名称更改为大写(除了IBM!) + +14. 使用字符串'#;  '将it_companies连接起来 + +15. 检查it_companies列表中是否存在某个公司 + +16. 使用sort()方法对列表进行排序 + +17. 使用reverse()方法以降序方式反转列表 + +18. 从列表中切片出前3个公司 + +19. 从列表中切片出最后3个公司 + +20. 从列表中切片出中间的IT公司或公司 + +21. 从列表中删除第一个IT公司 + +22. 从列表中删除中间的IT公司或公司 + +23. 从列表中删除最后一个IT公司 + +24. 从列表中删除所有IT公司 + +25. 销毁IT公司列表 + +26. 连接以下列表: + + ```py + front_end = ['HTML', 'CSS', 'JS', 'React', 'Redux'] + back_end = ['Node','Express', 'MongoDB'] + ``` + +27. 在连接的列表中找到Python和SQL之后,将连接的列表复制并分配给一个名为full_stack的变量。 + +### 练习:Level 2 + +1. 以下是包含10名学生年龄的列表: + +```sh +ages = [19, 22, 19, 24, 20, 25, 26, 24, 25, 24] +``` + +- 对列表进行排序,找到最小年龄和最大年龄 +- 再次将最小年龄和最大年龄添加到列表中 +- 找到中位数年龄(一个中间项或两个中间项除以两个) +- 找到平均年龄(所有项目的总和除以它们的数量) +- 找到年龄的范围(最大值减去最小值) +- 比较(min - average)和(max - average)的值,使用_abs()_方法 + +1. 找出[countries列表](https://github.com/Asabeneh/30-Days-Of-Python/tree/master/data/countries.py)中的中间国家(国家) + +1. 如果是偶数,将国家列表分成两个相等的列表,否则为第一个半部分再添加一个国家。 + +1. ['China', 'Russia', 'USA', 'Finland', 'Sweden', 'Norway', 'Denmark']。将前三个国家拆包并将其余部分作为北欧国家。 diff --git a/05_lists/index.html b/05_lists/index.html new file mode 100644 index 0000000..c25fcb0 --- /dev/null +++ b/05_lists/index.html @@ -0,0 +1,2117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 05 列表 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

05 列表⚓︎

+

列表⚓︎

+

Python 中有四种集合数据类型:

+
    +
  • 列表(List):是一种有序且可更改的集合。允许重复成员。
  • +
  • 元组(Tuple):是一种有序且不可更改的集合。允许重复成员。
  • +
  • 集合(Set):是一种无序、无索引且不可更改的集合,但我们可以向集合添加新项目。不允许重复成员。
  • +
  • 字典(Dictionary):是一种无序、可更改的集合,并具有索引。不允许重复成员。
  • +
+

列表是一种包含不同数据类型的集合,它是有序且可修改(可变)的。列表可以为空,也可以包含不同数据类型的项。

+

如何创建列表⚓︎

+

在 Python 中,我们可以以两种方式创建列表:

+
    +
  • 使用列表内置函数
  • +
+
# 语法
+lst = list()
+
+
empty_list = list()  # 这是一个空列表,列表中没有任何项目
+print(len(empty_list))  # 0
+
+
    +
  • 使用方括号[]
  • +
+
# 语法
+lst = []
+
+
empty_list = []  # 这是一个空列表,列表中没有任何项目
+print(len(empty_list))  # 0
+
+

具有初始值的列表。我们使用 len() 来查找列表的长度。

+
fruits = ['banana', 'orange', 'mango', 'lemon']  # 水果列表
+vegetables = ['Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot']  # 蔬菜列表
+animal_products = ['milk', 'meat', 'butter', 'yoghurt']  # 动物产品列表
+web_techs = ['HTML', 'CSS', 'JS', 'React', 'Redux', 'Node', 'MongDB']  # Web 技术列表
+countries = ['Finland', 'Estonia', 'Denmark', 'Sweden', 'Norway']
+
+# 打印列表及其长度
+print('水果:', fruits)
+print('水果数量:', len(fruits))
+print('蔬菜:', vegetables)
+print('蔬菜数量:', len(vegetables))
+print('动物产品:', animal_products)
+print('动物产品数量:', len(animal_products))
+print('Web 技术:', web_techs)
+print('Web 技术数量:', len(web_techs))
+print('国家:', countries)
+print('国家数量:', len(countries))
+
+
输出结果
+水果: ['banana', 'orange', 'mango', 'lemon']
+水果数量: 4
+蔬菜: ['Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot']
+蔬菜数量: 5
+动物产品: ['milk', 'meat', 'butter', 'yoghurt']
+动物产品数量: 4
+Web 技术: ['HTML', 'CSS', 'JS', 'React', 'Redux', 'Node', 'MongDB']
+Web 技术数量: 7
+国家: ['Finland', 'Estonia', 'Denmark', 'Sweden', 'Norway']
+国家数量: 5
+
+
    +
  • 列表可以包含不同数据类型的项
  • +
+
lst = ['Asabeneh', 250, True, {'country': 'Finland', 'city': 'Helsinki'}]  # 包含不同数据类型的列表
+
+

使用正向索引访问列表项⚓︎

+

我们使用它们的索引访问列表中的每个项目。列表索引从 0 开始。下面的图片清楚地显示了索引从哪里开始。

+

List index

+
fruits = ['banana', 'orange', 'mango', 'lemon']
+first_fruit = fruits[0]  # 我们使用索引访问第一个项目
+print(first_fruit)  # banana
+second_fruit = fruits[1]
+print(second_fruit)  # orange
+last_fruit = fruits[3]
+print(last_fruit)  # lemon
+# 最后一个索引
+last_index = len(fruits) - 1
+last_fruit = fruits[last_index]
+
+

使用负向索引访问列表项⚓︎

+

负索引意味着从末尾开始,-1 表示最后一个项目,-2 表示倒数第二个项目。

+

List negative indexing

+
fruits = ['banana', 'orange', 'mango', 'lemon']
+first_fruit = fruits[-4]
+last_fruit = fruits[-1]
+second_last = fruits[-2]
+print(first_fruit)  # banana
+print(last_fruit)  # lemon
+print(second_last)  # mango
+
+

解包⚓︎

+
lst = ['item1', 'item2', 'item3', 'item4', 'item5']
+first_item, second_item, third_item, *rest = lst
+print(first_item)  # item1
+print(second_item)  # item2
+print(third_item)  # item3
+print(rest)  # ['item4', 'item5']
+
+
# 第一个示例
+fruits = ['banana', 'orange', 'mango', 'lemon', 'lime', 'apple']
+first_fruit, second_fruit, third_fruit, *rest = fruits
+print(first_fruit)  # banana
+print(second_fruit)  # orange
+print(third_fruit)  # mango
+print(rest)  # ['lemon', 'lime', 'apple']
+# 第二个示例关于解包列表
+first, second, third, *rest, tenth = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+print(first)  # 1
+print(second)  # 2
+print(third)  # 3
+print(rest)  # [4, 5, 6, 7, 8, 9]
+print(tenth)  # 10
+# 第三个示例关于解包列表
+countries = ['Germany', 'France', 'Belgium', 'Sweden', 'Denmark', 'Finland', 'Norway', 'Iceland', 'Estonia']
+gr, fr, bg, sw, *scandic, es = countries
+print(gr)
+print(fr)
+print(bg)
+print(sw)
+print(scandic)
+print(es)
+
+
+

* 用于变量前表示解包列表元组中的剩余元素。

+
+

切片⚓︎

+
    +
  • 正向索引:我们可以通过指定开始、结束和步骤来指定一系列正索引,返回值将是一个新列表(开始默认值为 0,结束默认值为 len(lst)-1(最后一项),步长默认值为 1)。
  • +
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+all_fruits = fruits[0:4]  # 返回所有水果
+# 如果我们不设置停止位置,它将获取所有的其余水果
+all_fruits = fruits[0:]  # 如果我们不设置停止位置,它将获取所有的其余水果
+orange_and_mango = fruits[1:3]  # 它不包括第一个索引
+orange_mango_lemon = fruits[1:]  # 从 1 开始取到结束
+orange_and_lemon = fruits[::2]  # 在这里,我们使用了第三个参数,步骤。它会每隔 2 个项目取一个 - ['banana', 'mango']
+
+
    +
  • 负向索引:我们可以通过指定开始、结束和步长来指定一系列负向索引,返回值将是一个新列表。
  • +
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+all_fruits = fruits[-4:]  # 返回所有水果
+orange_and_mango = fruits[-3:-1]  # 它不包括最后一个索引,['orange', 'mango']
+orange_mango_lemon = fruits[-3:]  # 这将从 -3 开始到结束,['orange', 'mango', 'lemon']
+reverse_fruits = fruits[::-1]  # 负步骤将以相反的顺序获取列表,['lemon', 'mango', 'orange', 'banana']
+
+

修改⚓︎

+

列表是一个可变的有序集合。让我们修改水果列表。

+
fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits[0] = 'avocado'
+print(fruits)  # ['avocado', 'orange', 'mango', 'lemon']
+fruits[1] = 'apple'
+print(fruits)  # ['avocado', 'apple', 'mango', 'lemon']
+last_index = len(fruits) - 1
+fruits[last_index] = 'lime'
+print(fruits)  # ['avocado', 'apple', 'mango', 'lime']
+
+

检查⚓︎

+

使用 in 运算符检查项是否是列表的成员。查看下面的示例。

+
fruits = ['banana', 'orange', 'mango', 'lemon']
+does_exist = 'banana' in fruits
+print(does_exist)  # True
+does_exist = 'lime' in fruits
+print(does_exist)  # False
+
+

添加⚓︎

+

要将项目添加到现有列表的末尾,我们使用 append() 方法。

+
# 语法
+lst = list()
+lst.append(item)
+
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits.append('apple')
+print(fruits)  # ['banana', 'orange', 'mango', 'lemon', 'apple']
+fruits.append('lime')  # ['banana', 'orange', 'mango', 'lemon', 'apple', 'lime']
+print(fruits)
+
+

插入⚓︎

+

我们可以使用 insert() 方法在列表中指定的索引处插入单个项目。请注意,其他项目将向右移动。insert() 方法接受两个参数:索引和要插入的项目。

+
# 语法
+lst = ['item1', 'item2']
+lst.insert(index, item)
+
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits.insert(2, 'apple')  # 在橙子和芒果之间插入苹果
+print(fruits)  # ['banana', 'orange', 'apple', 'mango', 'lemon']
+fruits.insert(3, 'lime')  # ['banana', 'orange', 'apple', 'lime', 'mango', 'lemon']
+print(fruits)
+
+

删除⚓︎

+

remove()方法从列表中删除指定的项目

+
# 语法
+lst = ['item1', 'item2']
+lst.remove(item)
+
+
fruits = ['banana', 'orange', 'mango', 'lemon', 'banana']
+fruits.remove('banana')
+print(fruits)  # ['orange', 'mango', 'lemon', 'banana'] - 此方法删除列表中的第一个出现的项目
+fruits.remove('lemon')
+print(fruits)  # ['orange', 'mango', 'banana']
+
+

Pop 删除⚓︎

+

pop() 方法删除指定的索引(或如果未指定索引,则删除最后一个项目):

+
# 语法
+lst = ['item1', 'item2']
+lst.pop()  # 最后一个项目
+lst.pop(index)
+
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits.pop()
+print(fruits)  # ['banana', 'orange', 'mango']
+
+fruits.pop(0)
+print(fruits)  # ['orange', 'mango']
+
+

Del 删除⚓︎

+

del 关键字用于删除指定的索引,还可以用于删除索引范围内的项目。它还可以完全删除列表。

+
# 语法
+lst = ['item1', 'item2']
+del lst[index] # 仅删除单个项目
+del lst        # 删除整个列表
+
+
fruits = ['banana', 'orange', 'mango', 'lemon', 'kiwi', 'lime']
+del fruits[0]
+print(fruits)       # ['orange', 'mango', 'lemon', 'kiwi', 'lime']
+del fruits[1]
+print(fruits)       # ['orange', 'lemon', 'kiwi', 'lime']
+del fruits[1:3]     # 这将删除给定索引之间的项目,因此它不会删除索引为3的项目!
+print(fruits)       # ['orange', 'lime']
+del fruits
+print(fruits)       # 这将输出:NameError: name 'fruits' is not defined
+
+

清除⚓︎

+

clear() 方法会清空列表:

+
# 语法
+lst = ['item1', 'item2']
+lst.clear()
+
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits.clear()
+print(fruits)       # []
+
+

复制⚓︎

+

可以通过将其重新分配给新变量来复制列表,如下所示:list2 = list1。现在,list2 是 list1 的引用,我们在 list2 中进行的任何更改也将修改原始的 list1。但是,有很多情况下,我们不喜欢修改原始的列表,而是希望有一个不同的副本。避免上述问题的一种方法是使用copy()

+
# 语法
+lst = ['item1', 'item2']
+lst_copy = lst.copy()
+
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits_copy = fruits.copy()
+print(fruits_copy)       # ['banana', 'orange', 'mango', 'lemon']
+
+

连接⚓︎

+

在Python中,有多种连接两个或多个列表的方法。

+
    +
  • 加号运算符+
  • +
+
# 语法
+list3 = list1 + list2
+
+
positive_numbers = [1, 2, 3, 4, 5]
+zero = [0]
+negative_numbers = [-5,-4,-3,-2,-1]
+integers = negative_numbers + zero + positive_numbers
+print(integers) # [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
+fruits = ['banana', 'orange', 'mango', 'lemon']
+vegetables = ['Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot']
+fruits_and_vegetables = fruits + vegetables
+print(fruits_and_vegetables ) # ['banana', 'orange', 'mango', 'lemon', 'Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot']
+
+
    +
  • 使用extend()方法连接 + extend() 方法允许在列表中附加另一个列表。请参见以下示例。
  • +
+
# 语法
+list1 = ['item1', 'item2']
+list2 = ['item3', 'item4', 'item5']
+list1.extend(list2)
+
+
num1 = [0, 1, 2, 3]
+num2= [4, 5, 6]
+num1.extend(num2)
+print('Numbers:', num1) # Numbers: [0, 1, 2, 3, 4, 5, 6]
+negative_numbers = [-5,-4,-3,-2,-1]
+positive_numbers = [1, 2, 3,4,5]
+zero = [0]
+
+negative_numbers.extend(zero)
+negative_numbers.extend(positive_numbers)
+print('Integers:', negative_numbers) # Integers: [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5]
+fruits = ['banana', 'orange', 'mango', 'lemon']
+vegetables = ['Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot']
+fruits.extend(vegetables)
+print('Fruits and vegetables:', fruits ) # Fruits and vegetables: ['banana', 'orange', 'mango', 'lemon', 'Tomato', 'Potato', 'Cabbage', 'Onion', 'Carrot']
+
+

计数⚓︎

+

count() 方法返回列表中项目出现的次数:

+
# 语法
+lst = ['item1', 'item2']
+lst.count(item)
+
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+print(fruits.count('orange'))   # 1
+ages = [22, 19, 24, 25, 26, 24, 25, 24]
+print(ages.count(24))           # 3
+
+

查找⚓︎

+

index() 方法返回列表中项目的索引:

+
# 语法
+lst = ['item1', 'item2']
+lst.index(item)
+
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+print(fruits.index('orange'))   # 1
+ages = [22, 19, 24, 25, 26, 24, 25, 24]
+print(ages.index(24))           # 2,第一次出现
+
+

反转⚓︎

+

reverse() 方法反转列表的顺序。

+
# 语法
+lst = ['item1', 'item2']
+lst.reverse()
+
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits.reverse()
+print(fruits) # ['lemon', 'mango', 'orange', 'banana']
+ages = [22, 19, 24, 25, 26, 24, 25, 24]
+ages.reverse()
+print(ages) # [24, 25, 24, 26, 25, 24, 19, 22]
+
+

排序⚓︎

+

要对列表进行排序,可以使用 sort() 方法或内置的 sorted() 函数。sort() 方法会按升序重新排列列表项并修改原始列表。如果 sort() 方法的 reverse 参数等于 true,则会按降序

+

排列列表。

+
    +
  • sort():此方法会修改原始列表
  • +
+
# 语法
+lst = ['item1', 'item2']
+lst.sort()                # 升序
+lst.sort(reverse=True)    # 降序
+
+

示例:

+
fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits.sort()
+print(fruits)             # 按字母顺序排序,['banana', 'lemon', 'mango', 'orange']
+fruits.sort(reverse=True)
+print(fruits) # ['orange', 'mango', 'lemon', 'banana']
+ages = [22, 19, 24, 25, 26, 24, 25, 24]
+ages.sort()
+print(ages) #  [19, 22, 24, 24, 24, 25, 25, 26]
+
+ages.sort(reverse=True)
+print(ages) #  [26, 25, 25, 24, 24, 24, 22, 19]
+
+
    +
  • sorted():返回有序的列表,不会修改原始列表 + 示例:
  • +
+
fruits = ['banana', 'orange', 'mango', 'lemon']
+print(sorted(fruits))   # ['banana', 'lemon', 'mango', 'orange']
+# 反向排序
+fruits = ['banana', 'orange', 'mango', 'lemon']
+fruits = sorted(fruits, reverse=True)
+print(fruits)     # ['orange', 'mango', 'lemon', 'banana']
+
+

补充⚓︎

+

In-place⚓︎

+

在Python中,“In-place”(原地)操作指的是直接修改数据结构中的数据,而不是创建一个新的数据结构。这种操作常见于可变数据类型,如列表、字典或集合。使用原地操作可以提高效率,因为它避免了创建新对象和复制数据的开销。

+

例如,列表的 append()extend() 方法就会原地修改列表,添加新的元素,而不是返回一个包含了新元素的新列表。另一个例子是使用 += 运算符对列表进行原地扩展。

+

需要注意的是,原地操作可能会影响代码的可读性和维护性,尤其是在复杂的数据结构和算法中。此外,对于不可变数据类型(如整数、字符串和元组),是不支持原地操作的。在对这些类型的数据进行操作时,通常会生成并返回一个新的对象。

+

💻 练习⚓︎

+

练习:Level 1⚓︎

+
    +
  1. +

    声明一个空列表

    +
  2. +
  3. +

    声明一个包含5个以上项目的列表

    +
  4. +
  5. +

    找出列表的长度

    +
  6. +
  7. +

    获取列表的第一个项目、中间项目和最后一个项目

    +
  8. +
  9. +

    声明一个名为mixed_data_types的列表,包括你的名字、年龄、身高、婚姻状况和地址

    +
  10. +
  11. +

    声明一个名为it_companies的列表变量,并分配初始值Facebook、Google、Microsoft、Apple、IBM、Oracle和Amazon。

    +
  12. +
  13. +

    使用_print()_打印列表

    +
  14. +
  15. +

    打印列表中的公司数量

    +
  16. +
  17. +

    打印第一个、中间和最后一个公司

    +
  18. +
  19. +

    修改一个公司后,打印列表

    +
  20. +
  21. +

    向it_companies添加一个IT公司

    +
  22. +
  23. +

    在公司列表中间插入一个IT公司

    +
  24. +
  25. +

    将it_companies的一个公司名称更改为大写(除了IBM!)

    +
  26. +
  27. +

    使用字符串'#;  '将it_companies连接起来

    +
  28. +
  29. +

    检查it_companies列表中是否存在某个公司

    +
  30. +
  31. +

    使用sort()方法对列表进行排序

    +
  32. +
  33. +

    使用reverse()方法以降序方式反转列表

    +
  34. +
  35. +

    从列表中切片出前3个公司

    +
  36. +
  37. +

    从列表中切片出最后3个公司

    +
  38. +
  39. +

    从列表中切片出中间的IT公司或公司

    +
  40. +
  41. +

    从列表中删除第一个IT公司

    +
  42. +
  43. +

    从列表中删除中间的IT公司或公司

    +
  44. +
  45. +

    从列表中删除最后一个IT公司

    +
  46. +
  47. +

    从列表中删除所有IT公司

    +
  48. +
  49. +

    销毁IT公司列表

    +
  50. +
  51. +

    连接以下列表:

    +
    front_end = ['HTML', 'CSS', 'JS', 'React', 'Redux']
    +back_end = ['Node','Express', 'MongoDB']
    +
    +
  52. +
  53. +

    在连接的列表中找到Python和SQL之后,将连接的列表复制并分配给一个名为full_stack的变量。

    +
  54. +
+

练习:Level 2⚓︎

+
    +
  1. 以下是包含10名学生年龄的列表:
  2. +
+
ages = [19, 22, 19, 24, 20, 25, 26, 24, 25, 24]
+
+
    +
  • 对列表进行排序,找到最小年龄和最大年龄
  • +
  • 再次将最小年龄和最大年龄添加到列表中
  • +
  • 找到中位数年龄(一个中间项或两个中间项除以两个)
  • +
  • 找到平均年龄(所有项目的总和除以它们的数量)
  • +
  • 找到年龄的范围(最大值减去最小值)
  • +
  • +

    比较(min - average)和(max - average)的值,使用_abs()_方法

    +
  • +
  • +

    找出countries列表中的中间国家(国家)

    +
  • +
  • +

    如果是偶数,将国家列表分成两个相等的列表,否则为第一个半部分再添加一个国家。

    +
  • +
  • +

    ['China', 'Russia', 'USA', 'Finland', 'Sweden', 'Norway', 'Denmark']。将前三个国家拆包并将其余部分作为北欧国家。

    +
  • +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/06_tuples/06_tuples.md b/06_tuples/06_tuples.md new file mode 100644 index 0000000..e9c46a5 --- /dev/null +++ b/06_tuples/06_tuples.md @@ -0,0 +1,221 @@ +# 06 元组 + +## 元组 + +元组是一个包含不同数据类型的有序且不可变(不可修改)的集合。元组用圆括号 `()` 表示。一旦创建了元组,我们就不能更改它的值。因为元组是不可修改的,所以我们不能使用 `add`、`insert`、`remove` 等方法。与列表不同,元组有很少的方法。与元组相关的方法有: + +- `tuple()`: 创建一个空元组 +- `count()`: 计算元组中指定项目的数量 +- `index()`: 查找元组中指定项目的索引 +- `+` 运算符: 连接两个或多个元组,创建一个新的元组 + +### 创建元组 + +- 空元组:创建一个空元组 + + ```python + # 语法 + empty_tuple = () + # 或使用元组构造函数 + empty_tuple = tuple() + ``` + +- 带有初始值的元组 + + ```python + # 语法 + tpl = ('item1', 'item2','item3') + ``` + + ```python + fruits = ('banana', 'orange', 'mango', 'lemon') + ``` + +### 元组长度 + +我们使用 `len()` 方法来获取元组的长度。 + +```python +# 语法 +tpl = ('item1', 'item2', 'item3') +len(tpl) +``` + +### 访问元组项目 + +- 正向索引 + 与列表数据类型类似,我们使用正向或负向索引来访问元组项目。 + + +![访问元组项目](./images/tuples_index.png) + +```python +# 语法 +tpl = ('item1', 'item2', 'item3') +first_item = tpl[0] +second_item = tpl[1] +``` + +```python +fruits = ('banana', 'orange', 'mango', 'lemon') +first_fruit = fruits[0] +second_fruit = fruits[1] +last_index = len(fruits) - 1 +last_fruit = fruits[last_index] +``` + +- 负向索引 + 负向索引表示从末尾开始,-1 表示最后一个项目,-2 表示倒数第二个项目,以此类推。 + + +![元组负向索引](./images/tuple_negative_indexing.png) + +```python +# 语法 +tpl = ('item1', 'item2', 'item3','item4') +first_item = tpl[-4] +second_item = tpl[-3] +``` + +```python +fruits = ('banana', 'orange', 'mango', 'lemon') +first_fruit = fruits[-4] +second_fruit = fruits[-3] +last_fruit = fruits[-1] +``` + +### 切片元组 + +我们可以通过指定元组中的索引范围来切片出一个子元组,返回值将是一个包含指定项目的新元组。 + +- 正向索引范围 + + ```python + # 语法 + tpl = ('item1', 'item2', 'item3','item4') + all_items = tpl[0:4] # 所有项目 + all_items = tpl[0:] # 所有项目 + middle_two_items = tpl[1:3] # 不包括索引 3 处的项目 + ``` + + ```python + fruits = ('banana', 'orange', 'mango', 'lemon') + all_fruits = fruits[0:4] # 所有项目 + all_fruits = fruits[0:] # 所有项目 + orange_mango = fruits[1:3] # 不包括索引 3 处的项目 + orange_to_the_rest = fruits[1:] + ``` + +- 负向索引范围 + + ```python + # 语法 + tpl = ('item1', 'item2', 'item3','item4') + all_items = tpl[-4:] # 所有项目 + middle_two_items = tpl[-3:-1] # 不包括索引 3 (-1) 处的项目 + ``` + + ```python + fruits = ('banana', 'orange', 'mango', 'lemon') + all_fruits = fruits[-4:] # 所有项目 + orange_mango = fruits[-3:-1] # 不包括索引 3 处的项目 + orange_to_the_rest = fruits[-3:] + ``` + +### 将元组更改为列表 + +我们可以将元组更改为列表,也可以将列表更改为元组。元组是不可变的,如果我们想要修改一个元组,我们应该将其更改为列表。 + +```python +# 语法 +tpl = ('item1', 'item2', 'item3','item4') +lst = list(tpl) +``` + +```python +fruits = ('banana', 'orange', 'mango', 'lemon') +fruits = list(fruits) +fruits[0] = 'apple' +print(fruits) # ['apple', 'orange', 'mango', 'lemon'] +fruits = tuple(fruits) +print(fruits) # ('apple', 'orange', 'mango', 'lemon') +``` + +### 检查元组中的项目 + +我们可以使用 `in` 来检查元组中是否存在某个项目,它会返回一个布尔值。 + +```python +# 语法 +tpl = ('item1', 'item2', 'item3','item4') +'item2' in tpl # True +``` + +```python +fruits = ('banana', 'orange', 'mango', 'lemon') +print('orange' in fruits) # True +print('apple' in fruits) # False +fruits[0] = 'apple' # TypeError:“tuple”对象不支持项分配 +``` + +### 连接元组 + +我们可以使用 `+` 运算符来连接两个或多个元组。 + +```python +# 语法 +tpl1 = ('item1', 'item2', 'item3') +tpl2 = ('item4', 'item5','item6') +tpl3 = tpl1 + tpl2 +``` + +```python +fruits = ('banana', 'orange', 'mango', 'lemon') +vegetables = ('Tomato', 'Potato', 'Cabbage','Onion', 'Carrot') +fruits_and_vegetables = fruits + vegetables +``` + +### 删除元组 + +不能删除元组中的单个项目,但可以使用 `del` 删除整个元组。 + +```python +# 语法 +tpl1 = ('item1', 'item2', 'item3') +del tpl1 +``` + +```python +fruits = ('banana', 'orange', 'mango', 'lemon') +del fruits +``` + +🌕 你太勇敢了,已经走到了这一步。你刚刚完成了第 6 天的挑战,距离伟大的目标又前进了 6 步。现在为你的大脑和肌肉做一些锻炼。 + +## 💻 练习:第 6 天 + +### 练习:级别 1 + +1. 创建一个空元组。 +2. 创建一个包含你的姐妹和兄弟的姓名的元组(想象中的兄弟姐妹也可以)。 +3. 连接兄弟和姐妹的元组,并将其赋值给 `siblings`。 +4. 你有多少个兄弟姐妹? +5. 修改 `siblings` 元组,添加你父亲和母亲的姓名,并将其赋值给 `family_members`。 + +### 练习:级别 2 + +1. 从 `family_members` 中解包出兄弟姐妹和父母。 +2. 创建水果、蔬菜和动物产品的元组。连接这三个元组,并将其赋值给一个名为 `food_stuff_tp` 的变量。 +3. 将上述 `food_stuff_tp` 元组更改为 `food_stuff_lt` 列表。 +4. 从 `food_stuff_tp` 元组或 `food_stuff_lt` 列表中切出中间的项目或项目。 +5. 从 `food_staff_lt` 列表中切出前三个项目和最后三个项目。 +6. 完全删除 `food_staff_tp` 元组。 +7. 检查元组中是否存在项目: + +- 检查 'Estonia' 是否是北欧国家。 + +- 检查 'Iceland' 是否是北欧国家。 + + ```python + nordic_countries = ('Denmark', 'Finland','Iceland', 'Norway', 'Sweden') + ``` diff --git a/06_tuples/index.html b/06_tuples/index.html new file mode 100644 index 0000000..456ff3b --- /dev/null +++ b/06_tuples/index.html @@ -0,0 +1,1543 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 06 元组 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

06 元组⚓︎

+

元组⚓︎

+

元组是一个包含不同数据类型的有序且不可变(不可修改)的集合。元组用圆括号 () 表示。一旦创建了元组,我们就不能更改它的值。因为元组是不可修改的,所以我们不能使用 addinsertremove 等方法。与列表不同,元组有很少的方法。与元组相关的方法有:

+
    +
  • tuple(): 创建一个空元组
  • +
  • count(): 计算元组中指定项目的数量
  • +
  • index(): 查找元组中指定项目的索引
  • +
  • + 运算符: 连接两个或多个元组,创建一个新的元组
  • +
+

创建元组⚓︎

+
    +
  • 空元组:创建一个空元组
  • +
+
# 语法
+empty_tuple = ()
+# 或使用元组构造函数
+empty_tuple = tuple()
+
+
    +
  • 带有初始值的元组
  • +
+
# 语法
+tpl = ('item1', 'item2','item3')
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+
+

元组长度⚓︎

+

我们使用 len() 方法来获取元组的长度。

+
# 语法
+tpl = ('item1', 'item2', 'item3')
+len(tpl)
+
+

访问元组项目⚓︎

+
    +
  • 正向索引 + 与列表数据类型类似,我们使用正向或负向索引来访问元组项目。
  • +
+

访问元组项目

+
# 语法
+tpl = ('item1', 'item2', 'item3')
+first_item = tpl[0]
+second_item = tpl[1]
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+first_fruit = fruits[0]
+second_fruit = fruits[1]
+last_index = len(fruits) - 1
+last_fruit = fruits[last_index]
+
+
    +
  • 负向索引 + 负向索引表示从末尾开始,-1 表示最后一个项目,-2 表示倒数第二个项目,以此类推。
  • +
+

元组负向索引

+
# 语法
+tpl = ('item1', 'item2', 'item3','item4')
+first_item = tpl[-4]
+second_item = tpl[-3]
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+first_fruit = fruits[-4]
+second_fruit = fruits[-3]
+last_fruit = fruits[-1]
+
+

切片元组⚓︎

+

我们可以通过指定元组中的索引范围来切片出一个子元组,返回值将是一个包含指定项目的新元组。

+
    +
  • 正向索引范围
  • +
+
# 语法
+tpl = ('item1', 'item2', 'item3','item4')
+all_items = tpl[0:4]         # 所有项目
+all_items = tpl[0:]          # 所有项目
+middle_two_items = tpl[1:3]  # 不包括索引 3 处的项目
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+all_fruits = fruits[0:4]    # 所有项目
+all_fruits = fruits[0:]     # 所有项目
+orange_mango = fruits[1:3]  # 不包括索引 3 处的项目
+orange_to_the_rest = fruits[1:]
+
+
    +
  • 负向索引范围
  • +
+
# 语法
+tpl = ('item1', 'item2', 'item3','item4')
+all_items = tpl[-4:]          # 所有项目
+middle_two_items = tpl[-3:-1]  # 不包括索引 3 (-1) 处的项目
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+all_fruits = fruits[-4:]      # 所有项目
+orange_mango = fruits[-3:-1]  # 不包括索引 3 处的项目
+orange_to_the_rest = fruits[-3:]
+
+

将元组更改为列表⚓︎

+

我们可以将元组更改为列表,也可以将列表更改为元组。元组是不可变的,如果我们想要修改一个元组,我们应该将其更改为列表。

+
# 语法
+tpl = ('item1', 'item2', 'item3','item4')
+lst = list(tpl)
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+fruits = list(fruits)
+fruits[0] = 'apple'
+print(fruits)     # ['apple', 'orange', 'mango', 'lemon']
+fruits = tuple(fruits)
+print(fruits)     # ('apple', 'orange', 'mango', 'lemon')
+
+

检查元组中的项目⚓︎

+

我们可以使用 in 来检查元组中是否存在某个项目,它会返回一个布尔值。

+
# 语法
+tpl = ('item1', 'item2', 'item3','item4')
+'item2' in tpl # True
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+print('orange' in fruits) # True
+print('apple' in fruits) # False
+fruits[0] = 'apple' # TypeError:“tuple”对象不支持项分配
+
+

连接元组⚓︎

+

我们可以使用 + 运算符来连接两个或多个元组。

+
# 语法
+tpl1 = ('item1', 'item2', 'item3')
+tpl2 = ('item4', 'item5','item6')
+tpl3 = tpl1 + tpl2
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+vegetables = ('Tomato', 'Potato', 'Cabbage','Onion', 'Carrot')
+fruits_and_vegetables = fruits + vegetables
+
+

删除元组⚓︎

+

不能删除元组中的单个项目,但可以使用 del 删除整个元组。

+
# 语法
+tpl1 = ('item1', 'item2', 'item3')
+del tpl1
+
+
fruits = ('banana', 'orange', 'mango', 'lemon')
+del fruits
+
+

🌕 你太勇敢了,已经走到了这一步。你刚刚完成了第 6 天的挑战,距离伟大的目标又前进了 6 步。现在为你的大脑和肌肉做一些锻炼。

+

💻 练习:第 6 天⚓︎

+

练习:级别 1⚓︎

+
    +
  1. 创建一个空元组。
  2. +
  3. 创建一个包含你的姐妹和兄弟的姓名的元组(想象中的兄弟姐妹也可以)。
  4. +
  5. 连接兄弟和姐妹的元组,并将其赋值给 siblings
  6. +
  7. 你有多少个兄弟姐妹?
  8. +
  9. 修改 siblings 元组,添加你父亲和母亲的姓名,并将其赋值给 family_members
  10. +
+

练习:级别 2⚓︎

+
    +
  1. family_members 中解包出兄弟姐妹和父母。
  2. +
  3. 创建水果、蔬菜和动物产品的元组。连接这三个元组,并将其赋值给一个名为 food_stuff_tp 的变量。
  4. +
  5. 将上述 food_stuff_tp 元组更改为 food_stuff_lt 列表。
  6. +
  7. food_stuff_tp 元组或 food_stuff_lt 列表中切出中间的项目或项目。
  8. +
  9. food_staff_lt 列表中切出前三个项目和最后三个项目。
  10. +
  11. 完全删除 food_staff_tp 元组。
  12. +
  13. +

    检查元组中是否存在项目:

    +
  14. +
  15. +

    检查 'Estonia' 是否是北欧国家。

    +
  16. +
  17. +

    检查 'Iceland' 是否是北欧国家。

    +
  18. +
+
nordic_countries = ('Denmark', 'Finland','Iceland', 'Norway', 'Sweden')
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/07_sets/07_sets.md b/07_sets/07_sets.md new file mode 100644 index 0000000..3ef9479 --- /dev/null +++ b/07_sets/07_sets.md @@ -0,0 +1,383 @@ +# 07 集合 + +## 集合 + +集合是一组项的集合。 + +数学中对集合的定义也可以应用到Python中。集合是一组无序、无索引的不同元素。在Python中,集合用于存储唯一的项,可以在集合之间找到 _并集_、_交集_、_差集_、_对称差_、_子集_、_超集_ 和 _不相交集_ 等操作。 + +### 创建集合 + +我们使用内置的 _set()_ 函数来创建集合。 + +- 创建一个空集合 + +```py +# 语法 +st = set() +``` + +- 创建带有初始项的集合 + +```py +# 语法 +st = {'item1', 'item2', 'item3', 'item4'} +``` + +**示例:** + +```py +# 语法 +fruits = {'banana', 'orange', 'mango', 'lemon'} +``` + +### 获取集合的长度 + +我们使用 **len()** 方法来查找集合的长度。 + +```py +# 语法 +st = {'item1', 'item2', 'item3', 'item4'} +len(st) +``` + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +len(fruits) +``` + +### 访问集合中的项 + +我们使用循环来访问项。我们将在循环部分中看到这一点。 + +### 检查项 + +要检查列表中是否存在项,我们使用 _in_ 成员运算符。 + +```py +# 语法 +st = {'item1', 'item2', 'item3', 'item4'} +print("集合 st 是否包含 item3? ", 'item3' in st) # 集合 st 是否包含 item3? True +``` + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +print('mango' in fruits) # True +``` + +### 向集合中添加项 + +一旦创建了集合,我们就不能更改任何项,但可以添加其他项。 + +- 使用 _add()_ 添加一个项 + +```py +# 语法 +st = {'item1', 'item2', 'item3', 'item4'} +st.add('item5') +``` + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +fruits.add('lime') +``` + +- 使用 _update()_ 添加多个项 + _update()_ 允许向集合中添加多个项。_update()_ 方法接受一个列表参数。 + +```py +# 语法 +st = {'item1', 'item2', 'item3', 'item4'} +st.update(['item5','item6','item7']) +``` + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +vegetables = ('tomato', 'potato', 'cabbage','onion', 'carrot') +fruits.update(vegetables) +``` + +### 从集合中删除项 + +我们可以使用 _remove()_ 方法从集合中删除项。如果找不到项,_remove()_ 方法将引发错误,因此最好检查项是否存在于给定的集合中。然而,_discard()_ 方法不会引发任何错误。 + +```py +# 语法 +st = {'item1', 'item2', 'item3', 'item4'} +st.remove('item2') +``` + +pop() 方法从列表中删除一个随机项,并返回已删除的项。 + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +fruits.pop() # 从集合中删除一个随机项 +``` + +如果我们对已删除的项感兴趣。 + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +removed_item = fruits.pop() +``` + +### 清空集合中的项 + +如果要清空集合,我们使用 _clear_ 方法。 + +```py +# 语法 +st = {'item1', 'item2', 'item3', 'item4'} +st.clear() +``` + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'le + +mon'} +fruits.clear() +print(fruits) # set() +``` + +### 删除集合 + +如果要删除集合本身,我们使用 _del_ 运算符。 + +```py +# 语法 +st = {'item1', 'item2', 'item3', 'item4'} +del st +``` + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +del fruits +``` + +### 将列表转换为集合 + +我们可以将列表转换为集合,集合转换为列表。将列表转换为集合会删除重复项,只保留唯一项。 + +```py +# 语法 +lst = ['item1', 'item2', 'item3', 'item4', 'item1'] +st = set(lst) # {'item2', 'item4', 'item1', 'item3'} - 顺序是随机的,因为集合通常是无序的 +``` + +**示例:** + +```py +fruits = ['banana', 'orange', 'mango', 'lemon','orange', 'banana'] +fruits = set(fruits) # {'mango', 'lemon', 'banana', 'orange'} +``` + +### 合并集合 + +我们可以使用 _union()_ 或 _update()_ 方法合并两个集合。 + +- union + 该方法返回一个新的集合 + +```py +# 语法 +st1 = {'item1', 'item2', 'item3', 'item4'} +st2 = {'item5', 'item6', 'item7', 'item8'} +st3 = st1.union(st2) +``` + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +vegetables = {'tomato', 'potato', 'cabbage','onion', 'carrot'} +print(fruits.union(vegetables)) # {'lemon', 'carrot', 'tomato', 'banana', 'mango', 'orange', 'cabbage', 'potato', 'onion'} +``` + +- update + 该方法将一个集合插入到另一个集合中 + +```py +# 语法 +st1 = {'item1', 'item2', 'item3', 'item4'} +st2 = {'item5', 'item6', 'item7', 'item8'} +st1.update(st2) # 将 st2 的内容添加到 st1 中 +``` + +**示例:** + +```py +fruits = {'banana', 'orange', 'mango', 'lemon'} +vegetables = {'tomato', 'potato', 'cabbage','onion', 'carrot'} +fruits.update(vegetables) +print(fruits) # {'lemon', 'carrot', 'tomato', 'banana', 'mango', 'orange', 'cabbage', 'potato', 'onion'} +``` + +### 查找两个集合的交集项 + +交集返回两个集合中都存在的项。请参见示例 + +```py +# 语法 +st1 = {'item1', 'item2', 'item3', 'item4'} +st2 = {'item3', 'item2'} +st1.intersection(st2) # {'item3', 'item2'} +``` + +**示例:** + +```py +whole_numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} +even_numbers = {0, 2, 4, 6, 8, 10} +whole_numbers.intersection(even_numbers) # {0, 2, 4, 6, 8, 10} + +python = {'p', 'y', 't', 'h', 'o','n'} +dragon = {'d', 'r', 'a', 'g', 'o','n'} +python.intersection(dragon) # {'o', 'n'} +``` + +### 检查子集和超集 + +一个集合可以是其他集合的子集或超集: + +- 子集: _issubset()_ +- 超集: _issuperset()_ + +```py +# 语法 +st1 = {'item1', 'item2', 'item3', 'item4'} +st2 = {'item2', 'item3'} +st2.issubset(st1) # True +st1.issuperset(st2) # True +``` + +**示例:** + +```py +whole_numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} +even_numbers = {0, 2, 4, 6, 8, 10} +whole_numbers.issubset(even_numbers) # False,因为它是超集 +whole_numbers.issuperset(even_numbers) # True + +python = {'p', 'y', 't', 'h', 'o','n'} +dragon = {'d', 'r', 'a', 'g', 'o','n'} +python.issubset(dragon) # False +``` + +### 检查两个集合之间的差异 + +它返回两个集合之间的差异。 + +```py +# 语法 +st1 = {'item1', 'item2', 'item3', 'item4'} +st2 = {'item2', 'item3'} +st2.difference(st1) # set() +st1.difference(st2) # {'item1', 'item4'} => st1\st2 +``` + +**示例:** + +```py +whole_numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} +even_numbers = {0, 2, 4, 6, 8, 10} +whole_numbers.difference(even_numbers) # {1, 3, 5, 7, 9} + +python = {'p', 'y', 't', 'o','n'} +dragon = {'d', 'r', 'a', 'g', 'o','n'} +python.difference(dragon) # {'p', 'y', 't'} - 结果是无序的(集合的特点) +dragon.difference(python) # {'d', 'r', 'a', 'g'} +``` + +### 寻找两个集合的对称差异 + +它返回两个集合之间的对称差异symmetric difference。这意味着它返回一个包含两个集合中的所有项,但不包含同时存在于两个集合中的项的集合,数学上表示为:(A\B) ∪ (B\A) + +```python +# 语法 +st1 = {'item1', 'item2', 'item3', 'item4'} +st2 = {'item2', 'item3'} +# 这意味着 (A\B)∪(B\A) +st2.symmetric_difference(st1) # {'item1', 'item4'} +``` + +**示例:** + +```python +whole_numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10} +some_numbers = {1, 2, 3, 4, 5} +whole_numbers.symmetric_difference(some_numbers) # {0, 6, 7, 8, 9, 10} + +python = {'p', 'y', 't', 'h', 'o','n'} +dragon = {'d', 'r', 'a', 'g', 'o','n'} +python.symmetric_difference(dragon) # {'r', 't', 'p', 'y', 'g', 'a', 'd', 'h'} +``` + +### 连接集合 + +如果两个集合没有共同的项,我们称它们为不相交集合。我们可以使用 _isdisjoint()_ 方法来检查两个集合是否是相交的或不相交的。 + +```python +# 语法 +st1 = {'item1', 'item2', 'item3', 'item4'} +st2 = {'item2', 'item3'} +st2.isdisjoint(st1) # False +``` + +**示例:** + +```python +even_numbers = {0, 2, 4 ,6, 8} +even_numbers = {1, 3, 5, 7, 9} +even_numbers.isdisjoint(odd_numbers) # True,因为没有共同项 + +python = {'p', 'y', 't', 'h', 'o','n'} +dragon = {'d', 'r', 'a', 'g', 'o','n'} +python.isdisjoint(dragon) # False,有共同项 {'o', 'n'} +``` +## 💻 练习:第 7 天 + +```python +# 集合 +it_companies = {'Facebook', 'Google', 'Microsoft', 'Apple', 'IBM', 'Oracle', 'Amazon'} +A = {19, 22, 24, 20, 25, 26} +B = {19, 22, 20, 25, 26, 24, 28, 27} +age = [22, 19, 24, 25, 26, 24, 25, 24] +``` + +### 练习:级别 1 + +1. 查找集合 it_companies 的长度。 +2. 将 'Twitter' 添加到 it_companies 中。 +3. 一次性将多个 IT 公司插入到集合 it_companies 中。 +4. 从集合 it_companies 中删除一个公司。 +5. remove 和 discard 之间的区别是什么? + +### 练习:级别 2 + +1. 连接 A 和 B。 +2. 查找 A 和 B 的交集。 +3. A 是否为 B 的子集? +4. A 和 B 是否为不相交集? +5. 将 A 与 B 连接,然后将 B 与 A 连接。 +6. A 和 B 之间的对称差异是什么? +7. 完全删除这些集合。 + +### 练习:级别 3 + +1. 将年龄转换为集合,并比较列表和集合的长度,哪一个更大? +2. 解释以下数据类型之间的区别:字符串、列表、元组和集合。 +3. _我是一名教师,我热爱启发和教育人们。_ 这个句子中使用了多少个独特的单词?使用分割方法和集合来获取独特的单词。 diff --git a/07_sets/index.html b/07_sets/index.html new file mode 100644 index 0000000..469eb86 --- /dev/null +++ b/07_sets/index.html @@ -0,0 +1,1788 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 07 集合 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

07 集合⚓︎

+

集合⚓︎

+

集合是一组项的集合。

+

数学中对集合的定义也可以应用到Python中。集合是一组无序、无索引的不同元素。在Python中,集合用于存储唯一的项,可以在集合之间找到 并集交集差集对称差子集超集不相交集 等操作。

+

创建集合⚓︎

+

我们使用内置的 set() 函数来创建集合。

+
    +
  • 创建一个空集合
  • +
+
# 语法
+st = set()
+
+
    +
  • 创建带有初始项的集合
  • +
+
# 语法
+st = {'item1', 'item2', 'item3', 'item4'}
+
+

示例:

+
# 语法
+fruits = {'banana', 'orange', 'mango', 'lemon'}
+
+

获取集合的长度⚓︎

+

我们使用 len() 方法来查找集合的长度。

+
# 语法
+st = {'item1', 'item2', 'item3', 'item4'}
+len(st)
+
+

示例:

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+len(fruits)
+
+

访问集合中的项⚓︎

+

我们使用循环来访问项。我们将在循环部分中看到这一点。

+

检查项⚓︎

+

要检查列表中是否存在项,我们使用 in 成员运算符。

+
# 语法
+st = {'item1', 'item2', 'item3', 'item4'}
+print("集合 st 是否包含 item3? ", 'item3' in st) # 集合 st 是否包含 item3? True
+
+

示例:

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+print('mango' in fruits) # True
+
+

向集合中添加项⚓︎

+

一旦创建了集合,我们就不能更改任何项,但可以添加其他项。

+
    +
  • 使用 add() 添加一个项
  • +
+
# 语法
+st = {'item1', 'item2', 'item3', 'item4'}
+st.add('item5')
+
+

示例:

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+fruits.add('lime')
+
+
    +
  • 使用 update() 添加多个项 + update() 允许向集合中添加多个项。update() 方法接受一个列表参数。
  • +
+
# 语法
+st = {'item1', 'item2', 'item3', 'item4'}
+st.update(['item5','item6','item7'])
+
+

示例:

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+vegetables = ('tomato', 'potato', 'cabbage','onion', 'carrot')
+fruits.update(vegetables)
+
+

从集合中删除项⚓︎

+

我们可以使用 remove() 方法从集合中删除项。如果找不到项,remove() 方法将引发错误,因此最好检查项是否存在于给定的集合中。然而,discard() 方法不会引发任何错误。

+
# 语法
+st = {'item1', 'item2', 'item3', 'item4'}
+st.remove('item2')
+
+

pop() 方法从列表中删除一个随机项,并返回已删除的项。

+

示例:

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+fruits.pop()  # 从集合中删除一个随机项
+
+

如果我们对已删除的项感兴趣。

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+removed_item = fruits.pop() 
+
+

清空集合中的项⚓︎

+

如果要清空集合,我们使用 clear 方法。

+
# 语法
+st = {'item1', 'item2', 'item3', 'item4'}
+st.clear()
+
+

示例:

+
fruits = {'banana', 'orange', 'mango', 'le
+
+mon'}
+fruits.clear()
+print(fruits) # set()
+
+

删除集合⚓︎

+

如果要删除集合本身,我们使用 del 运算符。

+
# 语法
+st = {'item1', 'item2', 'item3', 'item4'}
+del st
+
+

示例:

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+del fruits
+
+

将列表转换为集合⚓︎

+

我们可以将列表转换为集合,集合转换为列表。将列表转换为集合会删除重复项,只保留唯一项。

+
# 语法
+lst = ['item1', 'item2', 'item3', 'item4', 'item1']
+st = set(lst)  # {'item2', 'item4', 'item1', 'item3'} - 顺序是随机的,因为集合通常是无序的
+
+

示例:

+
fruits = ['banana', 'orange', 'mango', 'lemon','orange', 'banana']
+fruits = set(fruits) # {'mango', 'lemon', 'banana', 'orange'}
+
+

合并集合⚓︎

+

我们可以使用 union()update() 方法合并两个集合。

+
    +
  • union + 该方法返回一个新的集合
  • +
+
# 语法
+st1 = {'item1', 'item2', 'item3', 'item4'}
+st2 = {'item5', 'item6', 'item7', 'item8'}
+st3 = st1.union(st2)
+
+

示例:

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+vegetables = {'tomato', 'potato', 'cabbage','onion', 'carrot'}
+print(fruits.union(vegetables)) # {'lemon', 'carrot', 'tomato', 'banana', 'mango', 'orange', 'cabbage', 'potato', 'onion'}
+
+
    +
  • update + 该方法将一个集合插入到另一个集合中
  • +
+
# 语法
+st1 = {'item1', 'item2', 'item3', 'item4'}
+st2 = {'item5', 'item6', 'item7', 'item8'}
+st1.update(st2) # 将 st2 的内容添加到 st1 中
+
+

示例:

+
fruits = {'banana', 'orange', 'mango', 'lemon'}
+vegetables = {'tomato', 'potato', 'cabbage','onion', 'carrot'}
+fruits.update(vegetables)
+print(fruits) # {'lemon', 'carrot', 'tomato', 'banana', 'mango', 'orange', 'cabbage', 'potato', 'onion'}
+
+

查找两个集合的交集项⚓︎

+

交集返回两个集合中都存在的项。请参见示例

+
# 语法
+st1 = {'item1', 'item2', 'item3', 'item4'}
+st2 = {'item3', 'item2'}
+st1.intersection(st2) # {'item3', 'item2'}
+
+

示例:

+
whole_numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+even_numbers = {0, 2, 4, 6, 8, 10}
+whole_numbers.intersection(even_numbers) # {0, 2, 4, 6, 8, 10}
+
+python = {'p', 'y', 't', 'h', 'o','n'}
+dragon = {'d', 'r', 'a', 'g', 'o','n'}
+python.intersection(dragon)     # {'o', 'n'}
+
+

检查子集和超集⚓︎

+

一个集合可以是其他集合的子集或超集:

+
    +
  • 子集: issubset()
  • +
  • 超集: issuperset()
  • +
+
# 语法
+st1 = {'item1', 'item2', 'item3', 'item4'}
+st2 = {'item2', 'item3'}
+st2.issubset(st1) # True
+st1.issuperset(st2) # True
+
+

示例:

+
whole_numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+even_numbers = {0, 2, 4, 6, 8, 10}
+whole_numbers.issubset(even_numbers) # False,因为它是超集
+whole_numbers.issuperset(even_numbers) # True
+
+python = {'p', 'y', 't', 'h', 'o','n'}
+dragon = {'d', 'r', 'a', 'g', 'o','n'}
+python.issubset(dragon)     # False
+
+

检查两个集合之间的差异⚓︎

+

它返回两个集合之间的差异。

+
# 语法
+st1 = {'item1', 'item2', 'item3', 'item4'}
+st2 = {'item2', 'item3'}
+st2.difference(st1) # set()
+st1.difference(st2) # {'item1', 'item4'} => st1\st2
+
+

示例:

+
whole_numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+even_numbers = {0, 2, 4, 6, 8, 10}
+whole_numbers.difference(even_numbers) # {1, 3, 5, 7, 9}
+
+python = {'p', 'y', 't', 'o','n'}
+dragon = {'d', 'r', 'a', 'g', 'o','n'}
+python.difference(dragon)     # {'p', 'y', 't'}  - 结果是无序的(集合的特点)
+dragon.difference(python)     # {'d', 'r', 'a', 'g'}
+
+

寻找两个集合的对称差异⚓︎

+

它返回两个集合之间的对称差异symmetric difference。这意味着它返回一个包含两个集合中的所有项,但不包含同时存在于两个集合中的项的集合,数学上表示为:(A\B) ∪ (B\A)

+
# 语法
+st1 = {'item1', 'item2', 'item3', 'item4'}
+st2 = {'item2', 'item3'}
+# 这意味着 (A\B)∪(B\A)
+st2.symmetric_difference(st1) # {'item1', 'item4'}
+
+

示例:

+
whole_numbers = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+some_numbers = {1, 2, 3, 4, 5}
+whole_numbers.symmetric_difference(some_numbers) # {0, 6, 7, 8, 9, 10}
+
+python = {'p', 'y', 't', 'h', 'o','n'}
+dragon = {'d', 'r', 'a', 'g', 'o','n'}
+python.symmetric_difference(dragon)  # {'r', 't', 'p', 'y', 'g', 'a', 'd', 'h'}
+
+

连接集合⚓︎

+

如果两个集合没有共同的项,我们称它们为不相交集合。我们可以使用 isdisjoint() 方法来检查两个集合是否是相交的或不相交的。

+
# 语法
+st1 = {'item1', 'item2', 'item3', 'item4'}
+st2 = {'item2', 'item3'}
+st2.isdisjoint(st1) # False
+
+

示例:

+
even_numbers = {0, 2, 4 ,6, 8}
+even_numbers = {1, 3, 5, 7, 9}
+even_numbers.isdisjoint(odd_numbers) # True,因为没有共同项
+
+python = {'p', 'y', 't', 'h', 'o','n'}
+dragon = {'d', 'r', 'a', 'g', 'o','n'}
+python.isdisjoint(dragon)  # False,有共同项 {'o', 'n'}
+
+

💻 练习:第 7 天⚓︎

+
# 集合
+it_companies = {'Facebook', 'Google', 'Microsoft', 'Apple', 'IBM', 'Oracle', 'Amazon'}
+A = {19, 22, 24, 20, 25, 26}
+B = {19, 22, 20, 25, 26, 24, 28, 27}
+age = [22, 19, 24, 25, 26, 24, 25, 24]
+
+

练习:级别 1⚓︎

+
    +
  1. 查找集合 it_companies 的长度。
  2. +
  3. 将 'Twitter' 添加到 it_companies 中。
  4. +
  5. 一次性将多个 IT 公司插入到集合 it_companies 中。
  6. +
  7. 从集合 it_companies 中删除一个公司。
  8. +
  9. remove 和 discard 之间的区别是什么?
  10. +
+

练习:级别 2⚓︎

+
    +
  1. 连接 A 和 B。
  2. +
  3. 查找 A 和 B 的交集。
  4. +
  5. A 是否为 B 的子集?
  6. +
  7. A 和 B 是否为不相交集?
  8. +
  9. 将 A 与 B 连接,然后将 B 与 A 连接。
  10. +
  11. A 和 B 之间的对称差异是什么?
  12. +
  13. 完全删除这些集合。
  14. +
+

练习:级别 3⚓︎

+
    +
  1. 将年龄转换为集合,并比较列表和集合的长度,哪一个更大?
  2. +
  3. 解释以下数据类型之间的区别:字符串、列表、元组和集合。
  4. +
  5. 我是一名教师,我热爱启发和教育人们。 这个句子中使用了多少个独特的单词?使用分割方法和集合来获取独特的单词。
  6. +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/08_dictionaries/08_dictionaries.md b/08_dictionaries/08_dictionaries.md new file mode 100644 index 0000000..7fe7122 --- /dev/null +++ b/08_dictionaries/08_dictionaries.md @@ -0,0 +1,301 @@ +# 08 字典 + +## 字典 + +字典是一种无序、可修改(可变)的键值对(key: value)数据类型的集合。 + +### 创建字典 + +要创建一个字典,我们使用花括号 {} 或内置函数 *dict()*。 + +```py +# 语法 +empty_dict = {} +# 带有数据值的字典 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +``` + +**示例:** + +```py +person = { + 'first_name':'Asabeneh', + 'last_name':'Yetayeh', + 'age':250, + 'country':'Finland', + 'is_married':True, + 'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address':{ + 'street':'Space street', + 'zipcode':'02210' + } + } +``` + +上面的字典示例显示值可以是任何数据类型:字符串、布尔值、列表、元组、集合或字典。 + +### 字典长度 + +它检查字典中的 'key: value' 对的数量。 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +print(len(dct)) # 4 +``` + +**示例:** + +```py +person = { + 'first_name':'Asabeneh', + 'last_name':'Yetayeh', + 'age':250, + 'country':'Finland', + 'is_married':True, + 'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address':{ + 'street':'Space street', + 'zipcode':'02210' + } + } +print(len(person)) # 7 +``` + +### 访问字典项 + +我们可以通过引用其键名来访问字典项。 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +print(dct['key1']) # value1 +print(dct['key4']) # value4 +``` + +**示例:** + +```py +person = { + 'first_name':'Asabeneh', + 'last_name':'Yetayeh', + 'age':250, + 'country':'Finland', + 'is_married':True, + 'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address':{ + 'street':'Space street', + 'zipcode':'02210' + } + } +print(person['first_name']) # Asabeneh +print(person['country']) # Finland +print(person['skills']) # ['JavaScript', 'React', 'Node', 'MongoDB', 'Python'] +print(person['skills'][0]) # JavaScript +print(person['address']['street']) # Space street +print(person['city']) # 错误 +``` + +通过键名访问项会在键不存在时引发错误。为了避免这种错误,首先我们必须检查键是否存在,或者我们可以使用 _get_ 方法。get 方法如果键不存在,则返回一个 None,这是一个 NoneType 对象数据类型。 + +```py +person = { + 'first_name':'Asabeneh', + 'last_name':'Yetayeh', + 'age':250, + 'country':'Finland', + 'is_married':True, + 'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address':{ + 'street':'Space street', + 'zipcode':'02210' + } + } +print(person.get('first_name')) # Asabeneh +print(person.get('country')) # Finland +print(person.get('skills')) #['HTML','CSS','JavaScript', 'React', 'Node', 'MongoDB', 'Python'] +print(person.get('city')) # None +``` + +### 向字典中添加项 + +我们可以向字典中添加新的键值对 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +dct['key5'] = 'value5' +``` + +**示例:** + +```py +person = { + 'first_name':'Asabeneh', + 'last_name':'Yetayeh', + 'age':250, + 'country':'Finland', + 'is_married':True, + 'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address':{ + 'street':'Space street', + 'zipcode':'02210' + } +} +person['job_title'] = 'Instructor' +person['skills'].append('HTML') +print(person) +``` + +### 修改字典中的项 + +我们可以修改字典中的项 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +dct['key1'] = 'value-one' +``` + +**示例:** + +```py +person = { + 'first_name':'Asabeneh', + 'last_name':'Yetayeh', + 'age':250, + 'country':'Finland', + 'is_married':True, + 'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address':{ + 'street':'Space street', + 'zipcode':'02210' + } + } +person['first_name'] = 'Eyob' +person['age'] = 252 +``` + +### 检查字典中的键 + +我们使用 _in_ 运算符来检查字典中是否存在键 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +print('key2' in dct) # True +print('key5' in dct) # False +``` + +### 从字典中删除键值对 + +- _pop(key)_: 移除具有指定键名的项 +- _popitem()_: 移除最后一个项 +- _del_: 移除具有指定键名的项 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +dct.pop('key1') # 移除 key1 项 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +dct.popitem() # 移除最后一项 + + +del dct['key2'] # 移除 key2 项 +``` + +**示例:** + +```py +person = { + 'first_name':'Asabeneh', + 'last_name':'Yetayeh', + 'age':250, + 'country':'Finland', + 'is_married':True, + 'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address':{ + 'street':'Space street', + 'zipcode':'02210' + } + } +person.pop('first_name') # 移除 firstname 项 +person.popitem() # 移除 address 项 +del person['is_married'] # 移除 is_married 项 +``` + +### 将字典转换为项的列表 + +_items()_ 方法将字典转换为项的元组列表。 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +print(dct.items()) # dict_items([('key1', 'value1'), ('key2', 'value2'), ('key3', 'value3'), ('key4', 'value4')]) +``` + +### 清空字典 + +如果我们不想要字典中的项,可以使用 _clear()_ 方法将其清空 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +print(dct.clear()) # None +``` + +### 删除字典 + +如果我们不使用字典,可以完全删除它 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +del dct +``` + +### 复制字典 + +我们可以使用 _copy()_ 方法复制一个字典。使用复制,我们可以避免修改原始字典。 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +dct_copy = dct.copy() # {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +``` + +### 将字典的键作为列表获取 + +_keys()_ 方法将字典的所有键作为列表返回。 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +keys = dct.keys() +print(keys) # dict_keys(['key1', 'key2', 'key3', 'key4']) +``` + +### 将字典的值作为列表获取 + +_values_ 方法将字典的所有值作为列表返回。 + +```py +# 语法 +dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'} +values = dct.values() +print(values) # dict_values(['value1', 'value2', 'value3', 'value4']) +``` + +## 💻 练习: 第8天 + +1. 创建一个名为 "dog" 的空字典。 +2. 向 "dog" 字典添加名字、颜色、品种、腿数和年龄等键值对。 +3. 创建一个名为 "student" 的字典,并添加 "first_name"、"last_name"、"gender"、"age"、"marital_status"、"skills"、"country"、"city" 和 "address" 作为键。 +4. 获取 "student" 字典的长度。 +5. 获取 "skills" 的值并检查其数据类型,应该是一个列表。 +6. 修改 "skills" 的值,添加一个或两个技能。 +7. 获取字典的键作为一个列表。 +8. 获取字典的值作为一个列表。 +9. 使用 _items()_ 方法将字典变为一个元组列表。 +10. 删除字典中的一项。 +11. 删除一个字典。 diff --git a/08_dictionaries/index.html b/08_dictionaries/index.html new file mode 100644 index 0000000..fc1e473 --- /dev/null +++ b/08_dictionaries/index.html @@ -0,0 +1,1644 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 08 字典 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

08 字典⚓︎

+

字典⚓︎

+

字典是一种无序、可修改(可变)的键值对(key: value)数据类型的集合。

+

创建字典⚓︎

+

要创建一个字典,我们使用花括号 {} 或内置函数 dict()

+
# 语法
+empty_dict = {}
+# 带有数据值的字典
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+
+

示例:

+
person = {
+    'first_name':'Asabeneh',
+    'last_name':'Yetayeh',
+    'age':250,
+    'country':'Finland',
+    'is_married':True,
+    'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address':{
+        'street':'Space street',
+        'zipcode':'02210'
+    }
+    }
+
+

上面的字典示例显示值可以是任何数据类型:字符串、布尔值、列表、元组、集合或字典。

+

字典长度⚓︎

+

它检查字典中的 'key: value' 对的数量。

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+print(len(dct)) # 4
+
+

示例:

+
person = {
+    'first_name':'Asabeneh',
+    'last_name':'Yetayeh',
+    'age':250,
+    'country':'Finland',
+    'is_married':True,
+    'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address':{
+        'street':'Space street',
+        'zipcode':'02210'
+    }
+    }
+print(len(person)) # 7
+
+

访问字典项⚓︎

+

我们可以通过引用其键名来访问字典项。

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+print(dct['key1']) # value1
+print(dct['key4']) # value4
+
+

示例:

+
person = {
+    'first_name':'Asabeneh',
+    'last_name':'Yetayeh',
+    'age':250,
+    'country':'Finland',
+    'is_married':True,
+    'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address':{
+        'street':'Space street',
+        'zipcode':'02210'
+    }
+    }
+print(person['first_name']) # Asabeneh
+print(person['country'])    # Finland
+print(person['skills'])     # ['JavaScript', 'React', 'Node', 'MongoDB', 'Python']
+print(person['skills'][0])  # JavaScript
+print(person['address']['street']) # Space street
+print(person['city'])       # 错误
+
+

通过键名访问项会在键不存在时引发错误。为了避免这种错误,首先我们必须检查键是否存在,或者我们可以使用 get 方法。get 方法如果键不存在,则返回一个 None,这是一个 NoneType 对象数据类型。

+
person = {
+    'first_name':'Asabeneh',
+    'last_name':'Yetayeh',
+    'age':250,
+    'country':'Finland',
+    'is_married':True,
+    'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address':{
+        'street':'Space street',
+        'zipcode':'02210'
+    }
+    }
+print(person.get('first_name')) # Asabeneh
+print(person.get('country'))    # Finland
+print(person.get('skills')) #['HTML','CSS','JavaScript', 'React', 'Node', 'MongoDB', 'Python']
+print(person.get('city'))   # None
+
+

向字典中添加项⚓︎

+

我们可以向字典中添加新的键值对

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+dct['key5'] = 'value5'
+
+

示例:

+
person = {
+    'first_name':'Asabeneh',
+    'last_name':'Yetayeh',
+    'age':250,
+    'country':'Finland',
+    'is_married':True,
+    'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address':{
+        'street':'Space street',
+        'zipcode':'02210'
+        }
+}
+person['job_title'] = 'Instructor'
+person['skills'].append('HTML')
+print(person)
+
+

修改字典中的项⚓︎

+

我们可以修改字典中的项

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+dct['key1'] = 'value-one'
+
+

示例:

+
person = {
+    'first_name':'Asabeneh',
+    'last_name':'Yetayeh',
+    'age':250,
+    'country':'Finland',
+    'is_married':True,
+    'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address':{
+        'street':'Space street',
+        'zipcode':'02210'
+    }
+    }
+person['first_name'] = 'Eyob'
+person['age'] = 252
+
+

检查字典中的键⚓︎

+

我们使用 in 运算符来检查字典中是否存在键

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+print('key2' in dct) # True
+print('key5' in dct) # False
+
+

从字典中删除键值对⚓︎

+
    +
  • pop(key): 移除具有指定键名的项
  • +
  • popitem(): 移除最后一个项
  • +
  • del: 移除具有指定键名的项
  • +
+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+dct.pop('key1') # 移除 key1 项
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+dct.popitem() # 移除最后一项
+
+
+del dct['key2'] # 移除 key2 项
+
+

示例:

+
person = {
+    'first_name':'Asabeneh',
+    'last_name':'Yetayeh',
+    'age':250,
+    'country':'Finland',
+    'is_married':True,
+    'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address':{
+        'street':'Space street',
+        'zipcode':'02210'
+    }
+    }
+person.pop('first_name')        # 移除 firstname 项
+person.popitem()                # 移除 address 项
+del person['is_married']        # 移除 is_married 项
+
+

将字典转换为项的列表⚓︎

+

items() 方法将字典转换为项的元组列表。

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+print(dct.items()) # dict_items([('key1', 'value1'), ('key2', 'value2'), ('key3', 'value3'), ('key4', 'value4')])
+
+

清空字典⚓︎

+

如果我们不想要字典中的项,可以使用 clear() 方法将其清空

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+print(dct.clear()) # None
+
+

删除字典⚓︎

+

如果我们不使用字典,可以完全删除它

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+del dct
+
+

复制字典⚓︎

+

我们可以使用 copy() 方法复制一个字典。使用复制,我们可以避免修改原始字典。

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+dct_copy = dct.copy() # {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+
+

将字典的键作为列表获取⚓︎

+

keys() 方法将字典的所有键作为列表返回。

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+keys = dct.keys()
+print(keys)     # dict_keys(['key1', 'key2', 'key3', 'key4'])
+
+

将字典的值作为列表获取⚓︎

+

values 方法将字典的所有值作为列表返回。

+
# 语法
+dct = {'key1':'value1', 'key2':'value2', 'key3':'value3', 'key4':'value4'}
+values = dct.values()
+print(values)     # dict_values(['value1', 'value2', 'value3', 'value4'])
+
+

💻 练习: 第8天⚓︎

+
    +
  1. 创建一个名为 "dog" 的空字典。
  2. +
  3. 向 "dog" 字典添加名字、颜色、品种、腿数和年龄等键值对。
  4. +
  5. 创建一个名为 "student" 的字典,并添加 "first_name"、"last_name"、"gender"、"age"、"marital_status"、"skills"、"country"、"city" 和 "address" 作为键。
  6. +
  7. 获取 "student" 字典的长度。
  8. +
  9. 获取 "skills" 的值并检查其数据类型,应该是一个列表。
  10. +
  11. 修改 "skills" 的值,添加一个或两个技能。
  12. +
  13. 获取字典的键作为一个列表。
  14. +
  15. 获取字典的值作为一个列表。
  16. +
  17. 使用 items() 方法将字典变为一个元组列表。
  18. +
  19. 删除字典中的一项。
  20. +
  21. 删除一个字典。
  22. +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/09_conditionals/09_conditionals.md b/09_conditionals/09_conditionals.md new file mode 100644 index 0000000..ca9538a --- /dev/null +++ b/09_conditionals/09_conditionals.md @@ -0,0 +1,250 @@ +# 09 条件语句 + +## 条件语句 + +默认情况下,Python 脚本中的语句按顺序从上到下执行。如果处理逻辑需要,执行流程可以通过两种方式进行修改: + +- 条件执行:如果某个表达式为真,则将执行一个或多个语句块 +- 重复执行:只要某个表达式为真,就会重复执行一个或多个语句块。在本节中,我们将介绍 _if_、_else_、_elif_ 语句。会用上之前的比较和逻辑运算符。 + +### if 条件 + +在 Python 和其他编程语言中,关键字 _if_ 用于检查条件是否为真,并执行代码块。请记住冒号后的缩进。 + +```py +# 语法 +if 条件: + 当条件为真时执行此部分代码 +``` + +**示例:1** + +```py +a = 3 +if a > 0: + print('A 是一个正数') +# A 是一个正数 +``` + +正如上面的示例所示,3 大于 0。条件为真,代码块被执行。但是,如果条件为假,我们就看不到结果。为了看到假条件的结果,我们应该有另一个代码块,它将是 _else_。 + +### if else + +如果条件为真,将执行第一个代码块,否则将运行 else 条件。 + +```py +# 语法 +if 条件: + 当条件为真时执行此部分代码 +else: + 当条件为假时执行此部分代码 +``` + +**示例:** + +```py +a = 3 +if a < 0: + print('A 是一个负数') +else: + print('A 是一个正数') +``` + +上面的条件不成立,因此执行了 else 代码块。那么如果我们的条件有两个以上怎么办?我们可以使用 _elif_。 + +### if elif else + +在日常生活中,我们每天都要做决策。与生活类似,编程也充满了条件。当我们有多个条件时,我们使用 _elif_。 + +```py +# 语法 +if 条件: + 代码 +elif 条件: + 代码 +else: + 代码 + +``` + +**示例:** + +```py +a = 0 +if a > 0: + print('A 是一个正数') +elif a < 0: + print('A 是一个负数') +else: + print('A 是零') +``` + +### 简写 + +```py +# 语法 +code if 条件 else code +``` + +**示例:** + +```py +a = 3 +print('A 是正数') if a > 0 else print('A 是负数') # 第一个条件满足,将打印 'A 是正数' +``` + +### 嵌套条件 + +条件可以嵌套 + +```py +# 语法 +if 条件: + 代码 + if 条件: + 代码 +``` + +**示例:** + +```py +a = 0 +if a > 0: + if a % 2 == 0: + print('A 是正偶数') + else: + print('A 是正数') +elif a == 0: + print('A 是零') +else: + print('A 是负数') + +``` + +我们可以使用逻辑运算符 _and_ 来避免编写嵌套条件。 + +### if 条件和逻辑运算符 + +```py +# 语法 +if 条件 and 条件: + 代码 +``` + +**示例:** + +```py +a = 0 +if a > 0 and a % 2 == 0: + print('A 是正偶数') +elif a > 0 and a % 2 != 0: + print('A 是正数') +elif a == 0: + print('A 是零') +else: + print('A 是负数') +``` + +### if 和 or 逻辑运算符 + +```py +# 语法 +if 条件 or 条件: + 代码 +``` + +**示例:** + +```py +user = 'James' +access_level = 3 +if user == 'admin' or access_level >= 4: + print('访问已授权!') +else: + print('访问被拒绝!') +``` + +## 💻 练习:第 9 天 + +### 练习:级别 1 + +1. 使用 input("输入您的年龄:") 获取用户输入。如果用户年龄为 18 岁或更高,给予反馈:您足够年龄学习开车了。如果年龄低于 18 岁,请提供等待缺少年龄的反馈。输出: + + ```sh + 输入您的年龄:30 + 您足够年龄学习开车了。 + 输出: + 输入您的年龄:15 + 您需要再等待 3 年才能学开车。 + ``` + +2. 使用 if ... else 比较 my_age 和 your_age 的值。谁更年长(我还是你)?使用 input("输入您的年龄:") 获取年龄作为输入。您可以使用嵌套条件来打印 1 年年龄差异的 'year',更大的差异的 'years',如果 my_age = your_age,则打印自定义文本。输出: + + ```sh + 输入您的年龄:30 + 你比我大 5 岁。 + ``` + +3. 使用 input 提示从用户获取两个数字。如果 a 大于 b,则返回 a 大于 b,如果 a 小于 b,则返回 a 小 + +于 b,否则 a 等于 b。输出: + + ```sh + 输入第一个数字:4 + 输入第二个数字:3 + 4 大于 3 + ``` + +### 练习:级别 2 + +1. 编写一个代码,根据学生的得分给予他们成绩: + + ```sh + 80-100, A + 70-89, B + 60-69, C + 50-59, D + 0-49, F + ``` + +2. 检查季节是秋天、冬天、春天还是夏天。如果用户输入是: + 9 月、10 月或 11 月,则季节是秋天。 + 12 月、1 月或 2 月,则季节是冬天。 + 3 月、4 月或 5 月,则季节是春天。 + 6 月、7 月或 8 月,则季节是夏天。 + +3. 以下列表包含一些水果: + + ```sh + fruits = ['banana', 'orange', 'mango', 'lemon'] + ``` + + 如果一个水果不存在于列表中,将该水果添加到列表中并打印修改后的列表。如果水果存在,则打印('该水果已存在于列表中')。 + +### 练习:级别 3 + +1. 这里我们有一个人的字典。随意修改它! + +```py + person = { + 'first_name': 'Asabeneh', + 'last_name': 'Yetayeh', + 'age': 250, + 'country': 'Finland', + 'is_married': True, + 'skills': ['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address': { + 'street': 'Space street', + 'zipcode': '02210' + } + } +``` + + * 检查 person 字典是否具有 skills 键,如果是,则打印 skills 列表中的中间技能。 + * 检查 person 字典是否具有 skills 键,如果是,则检查 person 是否具有 'Python' 技能并打印结果。 + * 如果一个人的技能只有 JavaScript 和 React,请打印('他是前端开发人员'),如果一个人的技能有 Node、Python、MongoDB,请打印('他是后端开发人员'),如果一个人的技能有 React、Node 和 MongoDB,请打印('他是全栈开发人员'),否则打印('未知职称') - 为了获得更精确的结果,可以嵌套更多条件! + * 如果这个人结婚了,并且他住在芬兰,请以以下格式打印信息: + +```py + Asabeneh Yetayeh 住在芬兰。他已婚。 +``` diff --git a/09_conditionals/index.html b/09_conditionals/index.html new file mode 100644 index 0000000..9173ea3 --- /dev/null +++ b/09_conditionals/index.html @@ -0,0 +1,1566 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 09 条件语句 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

09 条件语句⚓︎

+

条件语句⚓︎

+

默认情况下,Python 脚本中的语句按顺序从上到下执行。如果处理逻辑需要,执行流程可以通过两种方式进行修改:

+
    +
  • 条件执行:如果某个表达式为真,则将执行一个或多个语句块
  • +
  • 重复执行:只要某个表达式为真,就会重复执行一个或多个语句块。在本节中,我们将介绍 ifelseelif 语句。会用上之前的比较和逻辑运算符。
  • +
+

if 条件⚓︎

+

在 Python 和其他编程语言中,关键字 if 用于检查条件是否为真,并执行代码块。请记住冒号后的缩进。

+
# 语法
+if 条件:
+    当条件为真时执行此部分代码
+
+

示例:1

+
a = 3
+if a > 0:
+    print('A 是一个正数')
+# A 是一个正数
+
+

正如上面的示例所示,3 大于 0。条件为真,代码块被执行。但是,如果条件为假,我们就看不到结果。为了看到假条件的结果,我们应该有另一个代码块,它将是 else

+

if else⚓︎

+

如果条件为真,将执行第一个代码块,否则将运行 else 条件。

+
# 语法
+if 条件:
+    当条件为真时执行此部分代码
+else:
+     当条件为假时执行此部分代码
+
+

示例:

+
a = 3
+if a < 0:
+    print('A 是一个负数')
+else:
+    print('A 是一个正数')
+
+

上面的条件不成立,因此执行了 else 代码块。那么如果我们的条件有两个以上怎么办?我们可以使用 elif

+

if elif else⚓︎

+

在日常生活中,我们每天都要做决策。与生活类似,编程也充满了条件。当我们有多个条件时,我们使用 elif

+
# 语法
+if 条件:
+    代码
+elif 条件:
+    代码
+else:
+    代码
+
+

示例:

+
a = 0
+if a > 0:
+    print('A 是一个正数')
+elif a < 0:
+    print('A 是一个负数')
+else:
+    print('A 是零')
+
+

简写⚓︎

+
# 语法
+code if 条件 else code
+
+

示例:

+
a = 3
+print('A 是正数') if a > 0 else print('A 是负数') # 第一个条件满足,将打印 'A 是正数'
+
+

嵌套条件⚓︎

+

条件可以嵌套

+
# 语法
+if 条件:
+    代码
+    if 条件:
+    代码
+
+

示例:

+
a = 0
+if a > 0:
+    if a % 2 == 0:
+        print('A 是正偶数')
+    else:
+        print('A 是正数')
+elif a == 0:
+    print('A 是零')
+else:
+    print('A 是负数')
+
+

我们可以使用逻辑运算符 and 来避免编写嵌套条件。

+

if 条件和逻辑运算符⚓︎

+
# 语法
+if 条件 and 条件:
+    代码
+
+

示例:

+
a = 0
+if a > 0 and a % 2 == 0:
+        print('A 是正偶数')
+elif a > 0 and a % 2 !=  0:
+     print('A 是正数')
+elif a == 0:
+    print('A 是零')
+else:
+    print('A 是负数')
+
+

if 和 or 逻辑运算符⚓︎

+
# 语法
+if 条件 or 条件:
+    代码
+
+

示例:

+
user = 'James'
+access_level = 3
+if user == 'admin' or access_level >= 4:
+        print('访问已授权!')
+else:
+    print('访问被拒绝!')
+
+

💻 练习:第 9 天⚓︎

+

练习:级别 1⚓︎

+
    +
  1. +

    使用 input("输入您的年龄:") 获取用户输入。如果用户年龄为 18 岁或更高,给予反馈:您足够年龄学习开车了。如果年龄低于 18 岁,请提供等待缺少年龄的反馈。输出:

    +
    输入您的年龄:30
    +您足够年龄学习开车了。
    +输出:
    +输入您的年龄:15
    +您需要再等待 3 年才能学开车。
    +
    +
  2. +
  3. +

    使用 if ... else 比较 my_age 和 your_age 的值。谁更年长(我还是你)?使用 input("输入您的年龄:") 获取年龄作为输入。您可以使用嵌套条件来打印 1 年年龄差异的 'year',更大的差异的 'years',如果 my_age = your_age,则打印自定义文本。输出:

    +
    输入您的年龄:30
    +你比我大 5 岁。
    +
    +
  4. +
  5. +

    使用 input 提示从用户获取两个数字。如果 a 大于 b,则返回 a 大于 b,如果 a 小于 b,则返回 a 小

    +
  6. +
+

于 b,否则 a 等于 b。输出:

+
```sh
+输入第一个数字:4
+输入第二个数字:3
+4 大于 3
+```
+
+

练习:级别 2⚓︎

+
    +
  1. +

    编写一个代码,根据学生的得分给予他们成绩:

    +
    80-100, A
    +70-89, B
    +60-69, C
    +50-59, D
    +0-49, F
    +
    +
  2. +
  3. +

    检查季节是秋天、冬天、春天还是夏天。如果用户输入是: + 9 月、10 月或 11 月,则季节是秋天。 + 12 月、1 月或 2 月,则季节是冬天。 + 3 月、4 月或 5 月,则季节是春天。 + 6 月、7 月或 8 月,则季节是夏天。

    +
  4. +
  5. +

    以下列表包含一些水果:

    +
    fruits = ['banana', 'orange', 'mango', 'lemon']
    +
    +

    如果一个水果不存在于列表中,将该水果添加到列表中并打印修改后的列表。如果水果存在,则打印('该水果已存在于列表中')。

    +
  6. +
+

练习:级别 3⚓︎

+
    +
  1. 这里我们有一个人的字典。随意修改它!
  2. +
+
    person = {
+        'first_name': 'Asabeneh',
+        'last_name': 'Yetayeh',
+        'age': 250,
+        'country': 'Finland',
+        'is_married': True,
+        'skills': ['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+        'address': {
+            'street': 'Space street',
+            'zipcode': '02210'
+        }
+    }
+
+
* 检查 person 字典是否具有 skills 键,如果是,则打印 skills 列表中的中间技能。
+* 检查 person 字典是否具有 skills 键,如果是,则检查 person 是否具有 'Python' 技能并打印结果。
+* 如果一个人的技能只有 JavaScript 和 React,请打印('他是前端开发人员'),如果一个人的技能有 Node、Python、MongoDB,请打印('他是后端开发人员'),如果一个人的技能有 React、Node 和 MongoDB,请打印('他是全栈开发人员'),否则打印('未知职称') - 为了获得更精确的结果,可以嵌套更多条件!
+* 如果这个人结婚了,并且他住在芬兰,请以以下格式打印信息:
+
+
    Asabeneh Yetayeh 住在芬兰他已婚
+
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/10_loops/10_loops.md b/10_loops/10_loops.md new file mode 100644 index 0000000..207cf9d --- /dev/null +++ b/10_loops/10_loops.md @@ -0,0 +1,424 @@ +# 10 循环 + +## 循环 + +生活充满了日常工作routines。在编程中,我们也经常执行重复的任务。为了处理重复的任务,编程语言使用循环。Python编程语言也提供了以下两种类型的循环: + +1. while循环 +2. for循环 + +### While循环 + +我们使用保留字 _while_ 来创建一个while循环。它用于重复执行一组语句,直到满足给定条件为止。当条件变为假时,循环后的代码行将继续执行。 + +```py + # 语法 +while 条件: + 代码放在这里 +``` + +**示例:** + +```py +count = 0 +while count < 5: + print(count) + count = count + 1 +#输出从0到4 +``` + +在上面的while循环中,当count为5时,条件变为假。这时循环停止。 +如果我们想要在条件不再为真时运行一段代码块,我们可以使用 _else_。 + +```py + # 语法 +while 条件: + 代码放在这里 +else: + 代码放在这里 +``` + +**示例:** + +```py +count = 0 +while count < 5: + print(count) + count = count + 1 +else: + print(count) +``` + +上面的循环条件在count为5时为假,循环停止,然后执行else语句。结果会打印出5。 + +### Break和Continue - 第1部分 + +- Break:当我们想要退出或停止循环时,使用break。 + +```py +# 语法 +while 条件: + 代码放在这里 + if 另一个条件: + break +``` + +**示例:** + +```py +count = 0 +while count < 5: + print(count) + count = count + 1 + if count == 3: + break +``` + +上面的while循环仅打印0、1、2,但当它达到3时会停止。 + +- Continue:使用continue语句,我们可以跳过当前迭代,继续下一次迭代: + +```py + # 语法 +while 条件: + 代码放在这里 + if 另一个条件: + continue +``` + +**示例:** + +```py +count = 0 +while count < 5: + if count == 3: + count = count + 1 + continue + print(count) + count = count + 1 +``` + +上面的while循环仅打印0、1、2和4(跳过3)。 + +### For循环 + +使用 _for_ 关键字创建for循环,与其他编程语言类似,但有一些语法差异。循环用于迭代序列(可以是列表、元组、字典、集合或字符串)。 + +- 带列表的for循环 + +```py +# 语法 +for 迭代器 in 列表: + 代码放在这里 +``` + +**示例:** + +```py +numbers = [0, 1, 2, 3, 4, 5] +for number in numbers: # number是用来引用列表项的临时名称,只在这个循环内部有效 + print(number) # 数字将逐行打印,从0到5 +``` + +- 带字符串的for循环 + +```py +# 语法 +for 迭代器 in 字符串: + 代码放在这里 +``` + +**示例:** + +```py +language = 'Python' +for letter in language: + print(letter) + + +for i in range(len(language)): + print(language[i]) +``` + +- 带元组的for循环 + +```py +# 语法 +for 迭代器 in 元组: + 代码放在这里 +``` + +**示例:** + +```py +numbers = (0, 1, 2, 3, 4, 5) +for number in numbers: + print(number) +``` + +- 带字典的for循环 + 遍历字典会得到字典的键。 + +```py + # 语法 +for 迭代器 in 字典: + 代码放在这里 +``` + +**示例:** + +```py +person = { + 'first_name':'Asabeneh', + 'last_name':'Yetayeh', + 'age':250, + 'country':'Finland', + 'is_marred':True, + 'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address':{ + 'street':'Space street', + 'zipcode':'02210' + } +} +for key in person: + print(key) + +for key, value in person.items(): + print(key, value) # 这样我们可以打印出键和值 +``` + +- 集合中的循环 + +```py +# 语法 +for 迭代器 in 集合: + 代码放在这里 +``` + +**示例:** + +```py +it_companies = {'Facebook', 'Google', 'Microsoft', 'Apple', 'IBM', 'Oracle', 'Amazon'} +for company in it_companies: + print(company) +``` + +### Break和Continue - 第2部分 + +简短的提醒: +> 当我们想要在循环完成之前停止循环时,使用break。 + +```py +# 语法 +for 迭代器 in 序列: + 代码放在这里 + if 条件: + break +``` + +**示例:** + +```py +numbers = (0,1,2,3,4,5) +for number in numbers: + print(number) + if number == 3: + break +``` + +在上面的示例中,当它达到3时,循环停止。 + +> 当我们想要在循环迭代中跳过某些步骤时,使用continue。 + +```py + # 语法 +for 迭代器 in 序列: + 代码放在这里 + if 条件: + continue +``` + +**示例:** + +```py +numbers = (0,1,2,3,4,5) +for number in numbers: + print(number) + if number == 3: + continue + print('下一个数字应该是', number + 1) if number != 5 else print("循环结束") # 对于简写条件需要同时使用if和else语句 +print('循环外') +``` + +在上面的示例中,如果数字等于3,那么在条件后的步骤(但在循环内)会被跳过,如果还有其他迭代,循环继续执行。 + +### Range函数 + +_range()_ 函数用于生成一系列数字。_range(start, end, step)_ 接受三个参数:起始、结束和步进。默认情况下,它从0开始,步进为1。range序列至少需要一个参数(结束)。 +使用range创建序列 + +```py +lst = list(range(11)) +print(lst) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +st = set(range(1, 11)) # 2个参数表示序列的起始和结束,步长设置为默认值1 +print(st) # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} + +lst = list(range(0,11,2)) +print(lst) # [0, 2, 4, 6, 8, 10] +st = set(range(0,11,2)) +print(st) # {0, 2, 4, 6, 8, 10} +``` + +```py +# 语法 +for 迭代器 in range(起始, 结束, 步进): +``` + +**示例:** + +```py +for number in range(11): + print(number) # 打印0到10,不包括11 +``` + +### 嵌套的For循环 + +我们可以在循环内部编写循环。 + +```py +# 语法 +for x in y: + for t in x: + print(t) +``` + +**示例:** + +```py +person = { + 'first_name': 'Asabeneh', + 'last_name': 'Yetayeh', + 'age': 250, + 'country': 'Finland', + 'is_marred': True, + 'skills': ['JavaScript', 'React', 'Node', 'MongoDB', 'Python'], + 'address': { + 'street': 'Space street', + 'zipcode': '02210' + } +} +for key in person: + if key == 'skills': + for skill in person['skills']: + print(skill) +``` + +### For Else + +如果我们想在循环结束时执行一些消息,我们可以使用else。 + +```py +# 语法 +for 迭代器 in range(起始, 结束, 步进): + 做某事 +else: + print('循环结束') +``` + +**示例:** + +```py +for number in range(11): + print(number) # 打印0到10,不包括11 +else: + print('循环停在', number) +``` + +### Pass + +在Python中,当需要语句(分号后)但我们不想执行任何代码时,我们可以写上单词 _pass_ 来避免错误。同时,我们可以将其用作未来语句的占位符。 + +**示例:** + +```py +for number in range(6): + pass +``` + +## 💻 练习:第10天 + +### 练习:级别1 + +1. 使用for循环迭代0到10,然后使用while循环执行相同的操作。 + +2. 使用for循环迭代10到0,然后使用while循环执行相同的操作。 + +3. 编写一个循环,调用七次print(),以便我们在输出中获得以下三角形: + + ```py + # + ## + ### + #### + ##### + ###### + ####### + ``` + +4. 使用嵌套循环创建以下内容: + + ```sh + # # # # # # # # + # # # # # # # # + # # # # # # # # + # # # # # # # # + # # # # # # # # + # # # # # # # # + # # # # # # # # + # # # # # # # # + ``` + +5. 打印以下模式: + + ```sh + 0 x 0 = 0 + 1 x 1 = 1 + 2 x 2 = 4 + 3 x 3 = 9 + 4 x 4 = 16 + 5 x 5 = 25 + 6 x 6 = 36 + 7 x 7 = 49 + 8 x 8 = 64 + 9 x 9 = 81 + 10 x 10 = 100 + ``` + +6. 使用for循环迭代列表['Python', 'Numpy','Pandas','Django', 'Flask'],并打印出其中的项。 + +7. 使用for循环迭代0到100,仅打印偶数。 + +8. 使用for循环迭代0到100,仅打印奇数。 + +### 练习:级别2 + +1. 使用for循环迭代0到100,并打印所有数字的和。 + + ```sh + 所有数字的总和是5050。 + ``` + +2. 使用for循环迭代0到100,并打印所有偶数的和以及所有奇数的和。 + + ```sh + 所有偶数的总和为2550。而所有奇数的总和为2500。 + ``` + +### 练习:级别3 + +1. 进入data文件夹,使用[countries.py](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/countries.py)文件。循环遍历国家并提取所有包含单词 _land_ 的国家。 +2. 这是一个水果列表,['banana', 'orange', 'mango', 'lemon'] 使用循环反转顺序。 +3. 进入data文件夹,使用[countries_data.py](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/countries-data.py)文件。 + 1. 数据中有多少种语言 + 2. 从数据中找出使用最多的十种语言 + 3. 找出世界上人口最多的10个国家 diff --git a/10_loops/index.html b/10_loops/index.html new file mode 100644 index 0000000..11c06a1 --- /dev/null +++ b/10_loops/index.html @@ -0,0 +1,1731 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 循环 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

10 循环⚓︎

+

循环⚓︎

+

生活充满了日常工作routines。在编程中,我们也经常执行重复的任务。为了处理重复的任务,编程语言使用循环。Python编程语言也提供了以下两种类型的循环:

+
    +
  1. while循环
  2. +
  3. for循环
  4. +
+

While循环⚓︎

+

我们使用保留字 while 来创建一个while循环。它用于重复执行一组语句,直到满足给定条件为止。当条件变为假时,循环后的代码行将继续执行。

+
  # 语法
+while 条件:
+    代码放在这里
+
+

示例:

+
count = 0
+while count < 5:
+    print(count)
+    count = count + 1
+#输出从0到4
+
+

在上面的while循环中,当count为5时,条件变为假。这时循环停止。 +如果我们想要在条件不再为真时运行一段代码块,我们可以使用 else

+
  # 语法
+while 条件:
+    代码放在这里
+else:
+    代码放在这里
+
+

示例:

+
count = 0
+while count < 5:
+    print(count)
+    count = count + 1
+else:
+    print(count)
+
+

上面的循环条件在count为5时为假,循环停止,然后执行else语句。结果会打印出5。

+

Break和Continue - 第1部分⚓︎

+
    +
  • Break:当我们想要退出或停止循环时,使用break。
  • +
+
# 语法
+while 条件:
+    代码放在这里
+    if 另一个条件:
+        break
+
+

示例:

+
count = 0
+while count < 5:
+    print(count)
+    count = count + 1
+    if count == 3:
+        break
+
+

上面的while循环仅打印0、1、2,但当它达到3时会停止。

+
    +
  • Continue:使用continue语句,我们可以跳过当前迭代,继续下一次迭代:
  • +
+
  # 语法
+while 条件:
+    代码放在这里
+    if 另一个条件:
+        continue
+
+

示例:

+
count = 0
+while count < 5:
+    if count == 3:
+        count = count + 1
+        continue
+    print(count)
+    count = count + 1
+
+

上面的while循环仅打印0、1、2和4(跳过3)。

+

For循环⚓︎

+

使用 for 关键字创建for循环,与其他编程语言类似,但有一些语法差异。循环用于迭代序列(可以是列表、元组、字典、集合或字符串)。

+
    +
  • 带列表的for循环
  • +
+
# 语法
+for 迭代器 in 列表:
+    代码放在这里
+
+

示例:

+
numbers = [0, 1, 2, 3, 4, 5]
+for number in numbers: # number是用来引用列表项的临时名称,只在这个循环内部有效
+    print(number)       # 数字将逐行打印,从0到5
+
+
    +
  • 带字符串的for循环
  • +
+
# 语法
+for 迭代器 in 字符串:
+    代码放在这里
+
+

示例:

+
language = 'Python'
+for letter in language:
+    print(letter)
+
+
+for i in range(len(language)):
+    print(language[i])
+
+
    +
  • 带元组的for循环
  • +
+
# 语法
+for 迭代器 in 元组:
+    代码放在这里
+
+

示例:

+
numbers = (0, 1, 2, 3, 4, 5)
+for number in numbers:
+    print(number)
+
+
    +
  • 带字典的for循环 + 遍历字典会得到字典的键。
  • +
+
  # 语法
+for 迭代器 in 字典:
+    代码放在这里
+
+

示例:

+
person = {
+    'first_name':'Asabeneh',
+    'last_name':'Yetayeh',
+    'age':250,
+    'country':'Finland',
+    'is_marred':True,
+    'skills':['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address':{
+        'street':'Space street',
+        'zipcode':'02210'
+    }
+}
+for key in person:
+    print(key)
+
+for key, value in person.items():
+    print(key, value) # 这样我们可以打印出键和值
+
+
    +
  • 集合中的循环
  • +
+
# 语法
+for 迭代器 in 集合:
+    代码放在这里
+
+

示例:

+
it_companies = {'Facebook', 'Google', 'Microsoft', 'Apple', 'IBM', 'Oracle', 'Amazon'}
+for company in it_companies:
+    print(company)
+
+

Break和Continue - 第2部分⚓︎

+

简短的提醒:

+
+

当我们想要在循环完成之前停止循环时,使用break。

+
+
# 语法
+for 迭代器 in 序列:
+    代码放在这里
+    if 条件:
+        break
+
+

示例:

+
numbers = (0,1,2,3,4,5)
+for number in numbers:
+    print(number)
+    if number == 3:
+        break
+
+

在上面的示例中,当它达到3时,循环停止。

+
+

当我们想要在循环迭代中跳过某些步骤时,使用continue。

+
+
  # 语法
+for 迭代器 in 序列:
+    代码放在这里
+    if 条件:
+        continue
+
+

示例:

+
numbers = (0,1,2,3,4,5)
+for number in numbers:
+    print(number)
+    if number == 3:
+       continue
+    print('下一个数字应该是', number + 1) if number != 5 else print("循环结束") # 对于简写条件需要同时使用if和else语句
+print('循环外')
+
+

在上面的示例中,如果数字等于3,那么在条件后的步骤(但在循环内)会被跳过,如果还有其他迭代,循环继续执行。

+

Range函数⚓︎

+

range() 函数用于生成一系列数字。range(start, end, step) 接受三个参数:起始、结束和步进。默认情况下,它从0开始,步进为1。range序列至少需要一个参数(结束)。 +使用range创建序列

+
lst = list(range(11)) 
+print(lst) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+st = set(range(1, 11))    # 2个参数表示序列的起始和结束,步长设置为默认值1
+print(st) # {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
+
+lst = list(range(0,11,2))
+print(lst) # [0, 2, 4, 6, 8, 10]
+st = set(range(0,11,2))
+print(st) #  {0, 2, 4, 6, 8, 10}
+
+
# 语法
+for 迭代器 in range(起始, 结束, 步进):
+
+

示例:

+
for number in range(11):
+    print(number)   # 打印0到10,不包括11
+
+

嵌套的For循环⚓︎

+

我们可以在循环内部编写循环。

+
# 语法
+for x in y:
+    for t in x:
+        print(t)
+
+

示例:

+
person = {
+    'first_name': 'Asabeneh',
+    'last_name': 'Yetayeh',
+    'age': 250,
+    'country': 'Finland',
+    'is_marred': True,
+    'skills': ['JavaScript', 'React', 'Node', 'MongoDB', 'Python'],
+    'address': {
+        'street': 'Space street',
+        'zipcode': '02210'
+    }
+}
+for key in person:
+    if key == 'skills':
+        for skill in person['skills']:
+            print(skill)
+
+

For Else⚓︎

+

如果我们想在循环结束时执行一些消息,我们可以使用else。

+
# 语法
+for 迭代器 in range(起始, 结束, 步进):
+    做某事
+else:
+    print('循环结束')
+
+

示例:

+
for number in range(11):
+    print(number)   # 打印0到10,不包括11
+else:
+    print('循环停在', number)
+
+

Pass⚓︎

+

在Python中,当需要语句(分号后)但我们不想执行任何代码时,我们可以写上单词 pass 来避免错误。同时,我们可以将其用作未来语句的占位符。

+

示例:

+
for number in range(6):
+    pass
+
+

💻 练习:第10天⚓︎

+

练习:级别1⚓︎

+
    +
  1. +

    使用for循环迭代0到10,然后使用while循环执行相同的操作。

    +
  2. +
  3. +

    使用for循环迭代10到0,然后使用while循环执行相同的操作。

    +
  4. +
  5. +

    编写一个循环,调用七次print(),以便我们在输出中获得以下三角形:

    +
  6. +
+
  #
+  ##
+  ###
+  ####
+  #####
+  ######
+  #######
+
+
    +
  1. 使用嵌套循环创建以下内容:
  2. +
+
# # # # # # # #
+# # # # # # # #
+# # # # # # # #
+# # # # # # # #
+# # # # # # # #
+# # # # # # # #
+# # # # # # # #
+# # # # # # # #
+
+
    +
  1. 打印以下模式:
  2. +
+
0 x 0 = 0
+1 x 1 = 1
+2 x 2 = 4
+3 x 3 = 9
+4 x 4 = 16
+5 x 5 = 25
+6 x 6 = 36
+7 x 7 = 49
+8 x 8 = 64
+9 x 9 = 81
+10 x 10 = 100
+
+
    +
  1. +

    使用for循环迭代列表['Python', 'Numpy','Pandas','Django', 'Flask'],并打印出其中的项。

    +
  2. +
  3. +

    使用for循环迭代0到100,仅打印偶数。

    +
  4. +
  5. +

    使用for循环迭代0到100,仅打印奇数。

    +
  6. +
+

练习:级别2⚓︎

+
    +
  1. 使用for循环迭代0到100,并打印所有数字的和。
  2. +
+
所有数字的总和是5050。
+
+
    +
  1. 使用for循环迭代0到100,并打印所有偶数的和以及所有奇数的和。
  2. +
+
所有偶数的总和为2550。而所有奇数的总和为2500。
+
+

练习:级别3⚓︎

+
    +
  1. 进入data文件夹,使用countries.py文件。循环遍历国家并提取所有包含单词 land 的国家。
  2. +
  3. 这是一个水果列表,['banana', 'orange', 'mango', 'lemon'] 使用循环反转顺序。
  4. +
  5. 进入data文件夹,使用countries_data.py文件。
  6. +
  7. 数据中有多少种语言
  8. +
  9. 从数据中找出使用最多的十种语言
  10. +
  11. 找出世界上人口最多的10个国家
  12. +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/11_functions/11_functions.md b/11_functions/11_functions.md new file mode 100644 index 0000000..0a2bcf5 --- /dev/null +++ b/11_functions/11_functions.md @@ -0,0 +1,419 @@ +# 11 函数 + +## 函数 + +到目前为止,我们已经看到了许多内置的Python函数。在本节中,我们将关注自定义函数。什么是函数?在我们开始创建函数之前,让我们学习一下函数是什么以及为什么需要它们? + +### 定义函数 + +函数是一块可重复使用的代码块或编程语句,旨在执行某个特定的任务。要定义或声明一个函数,Python提供了`def`关键字。以下是定义函数的语法。只有在调用或调用函数时,函数的代码块才会被执行。 + +### 声明和调用函数 + +当我们创建一个函数时,我们称之为声明函数。当我们开始使用它时,我们称之为*调用(*calling/ *invoking*)函数。函数可以带参数或不带参数。 + +```py +# 语法 +# 声明一个函数 +def function_name(): + 代码 + 代码 +# 调用一个函数 +function_name() +``` + +### 无参数的函数 + +函数可以在不带参数的情况下声明。 + +**示例:** + +```py +def generate_full_name(): + first_name = 'Asabeneh' + last_name = 'Yetayeh' + space = ' ' + full_name = first_name + space + last_name + print(full_name) +generate_full_name() # 调用一个函数 + +def add_two_numbers(): + num_one = 2 + num_two = 3 + total = num_one + num_two + print(total) +add_two_numbers() +``` + +### 有返回值的函数 - 第1部分 + +函数也可以返回值,如果一个函数没有返回语句,函数的值就是None。现在,让我们使用return来重写上面的函数。从现在开始,我们在调用函数时从函数中获取一个值并打印它。 + +```py +def generate_full_name(): + first_name = 'Asabeneh' + last_name = 'Yetayeh' + space = ' ' + full_name = first_name + space + last_name + return full_name +print(generate_full_name()) + +def add_two_numbers(): + num_one = 2 + num_two = 3 + total = num_one + num_two + return total +print(add_two_numbers()) +``` + +### 带参数的函数 + +在函数中,我们可以将不同的数据类型(数字、字符串、布尔值、列表、元组、字典或集合)作为参数传递 + +- 单个参数:如果我们的函数带有参数,我们应该使用一个参数来调用我们的函数 + +```py + # 语法 + # 声明一个函数 + def function_name(parameter): + 代码 + 代码 + # 调用函数 + print(function_name(argument)) +``` + +**示例:** + +```py +def greetings(name): + message = name + ',欢迎来到Python for Everyone!' + return message + +print(greetings('Asabeneh')) + +def add_ten(num): + ten = 10 + return num + ten +print(add_ten(90)) + +def square_number(x): + return x * x +print(square_number(2)) + +def area_of_circle(r): + PI = 3.14 + area = PI * r ** 2 + return area +print(area_of_circle(10)) + +def sum_of_numbers(n): + total = 0 + for i in range(n+1): + total+=i + print(total) +print(sum_of_numbers(10)) # 55 +print(sum_of_numbers(100)) # 5050 +``` + +- 两个参数:一个函数可以有参数也可以没有参数。一个函数也可以有两个或更多的参数。如果我们的函数有参数,我们应该用参数来调用它。让我们看一个带有两个参数的函数: + +```py + # 语法 + # 声明一个函数 + def function_name(para1, para2): + 代码 + 代码 + # 调用函数 + print(function_name(arg1, arg2)) +``` + +**示例:** + +```py +def generate_full_name(first_name, last_name): + space = ' ' + full_name = first_name + space + last_name + return full_name +print('全名:', generate_full_name('Asabeneh','Yetayeh')) + +def sum_two_numbers(num_one, num_two): + sum = num_one + num_two + return sum +print('两个数字的和:', sum_two_numbers(1, 9)) + +def calculate_age(current_year, birth_year): + age = current_year - birth_year + return age; + +print('年龄:', calculate_age(2021, 1819)) + +def weight_of_object(mass, gravity): + weight = str(mass * gravity)+ ' N' # 将值首先更改为字符串 + return weight +print('牛顿下的物体重量:', weight_of_object(100, 9.81)) +``` + +### 使用键和值传递参数 + +如果我们使用键和值传递参数,参数的顺序就不重要了。 + +```py +# 语法 +# 声明一个函数 +def function_name(para1, para2): + 代码 + 代码 +# 调用函数 +print(function_name(para1 = 'John', para2 = 'Doe')) # 参数的顺序在这里不重要 +``` + +**示例:** + +```py +def print_fullname(firstname, lastname): + space = ' ' + full_name = firstname + space + lastname + print(full_name) +print(print_fullname(firstname = 'Asabeneh', lastname = 'Yetayeh')) + +def add_two_numbers(num1, num2): + total = num1 + num2 + print(total) +print(add_two_numbers(num2 = 3, num1 = 2)) # 顺序不重要 +``` + +### 有返回值的函数 - 第2部分 + +如果我们不使用函数返回值,那么默认情况下我们的函数将返回`None`。为了从函数中返回一个值,我们使用关键字`return`后跟我们要返回的变量。我们可以从函数中返回任何类型的数据。 + +- 返回一个字符串: + **示例:** + +```py +def print_name(firstname): + return firstname +print_name('Asabeneh') # Asabeneh + +def print_full_name(firstname, lastname): + space = ' ' + full_name = firstname + space + lastname + return full_name +print_full_name(firstname='Asabeneh', lastname='Yetayeh') +``` + +- 返回一个数字: + +**示例:** + +```py +def add_two_numbers(num1, num2): + total = num1 + num2 + return total +print(add_two_numbers(2, 3)) + +def calculate_age(current_year, birth_year): + age = current_year - birth_year + return age; +print('年龄:', calculate_age(2019, 1819)) +``` + +- 返回一个布尔值: + **示例:** + +```py +def is_even(n): + if n % 2 == 0: + print('偶数') + return True # return会停止函数的进一步执行,类似于break + return False +print(is_even(10)) # True +print(is_even(7)) # False +``` + +- 返回一个列表: + **示例:** + +```py +def find_even_numbers(n): + evens = [] + for i in range(n + 1): + if i % 2 == 0: + evens.append(i) + return evens +print(find_even_numbers(10)) +``` + +### 具有默认参数的函数 + +有时,当我们调用函数时,我们会传递默认值给参数。如果我们在调用函数时不传递参数,那么参数的默认值将被使用。 + +```py +# 语法 +# 声明一个函数 +def function_name(param = value): + 代码 + 代码 +# 调用函数 +function_name() +function_name(arg) +``` + +**示例:** + +```py +def greetings(name = 'Peter'): + message = name + ',欢迎来到Python for Everyone!' + return message +print(greetings()) +print(greetings('Asabeneh')) + +def generate_full_name(first_name = 'Asabeneh', last_name = 'Yetayeh'): + space = ' ' + full_name = first_name + space + last_name + return full_name + +print(generate_full_name()) +print(generate_full_name('David','Smith')) + +def calculate_age(birth_year, current_year = 2021): + age = current_year - birth_year + return age; +print('年龄:', calculate_age(1821)) + +def weight_of_object(mass, gravity = 9.81): + weight = str(mass * gravity)+ ' N' # 将值首先更改为字符串 + return weight +print('牛顿下的物体重量:', weight_of_object(100)) # 9.81 - 地表上的平均重力 +print('牛顿下的物体重量:', weight_of_object(100, 1.62)) # 月球表面上的重力 +``` + +### 任意数量的参数 + +如果我们不知道要传递给函数的参数数量,我们可以通过在参数名之前添加\*来创建一个可以接受任意数量参数的函数。 + +```py +# 语法 +# 声明一个函数 +def function_name(*args): + 代码 + 代码 +# 调用函数 +function_name(param1, param2, param3,..) +``` + +**示例:** + +```py +def sum_all_nums(*nums): + total = 0 + for num in nums: + total += num # 相当于 total = total + num + return total +print(sum_all_nums(2, 3, 5)) # 10 +``` + +### 函数中的默认参数和任意数量的参数 + +```py +def generate_groups(*args, team='Default Team'): + print(team) + for i in args: + print(i) + +generate_groups('Asabeneh', 'Brook', 'David', 'Eyob') +``` + +``` +Default Team +Asabeneh +Brook +David +Eyob +``` + +### 函数作为另一个函数的参数 + +```py +# 您可以将函数作为参数传递 +def square_number(n): + return n * n +def do_something(f, x): + return f(x) +print(do_something(square_number, 3)) # 9 +``` + +## 💻 练习:第11天 + +### 练习:级别1 + +1. 声明一个名为_add_two_numbers_的函数。它接受两个参数并返回它们的和。 +2. 圆的面积计算如下:面积 = π x r x r。编写一个计算_area_of_circle的函数。 +3. 编写一个名为add_all_nums的函数,它接受任意数量的参数并求它们的总和。检查列表中的所有项目是否都是数字类型。如果不是,请给出合理的反馈。 +4. 摄氏度可以使用以下公式转换为华氏度:°F = (°C x 9/5) + 32。编写一个将°C转换为°F的函数_convert_celsius_to_fahrenheit_。 +5. 编写一个名为check_season的函数,它接受一个月份参数并返回季节:秋季、冬季、春季或夏季。 +6. 编写一个名为calculate_slope的函数,它返回线性方程的斜率。 +7. 二次方程计算如下:ax² + bx + c = 0。编写一个计算二次方程解集的函数_solve_quadratic_eqn_。 +8. 声明一个名为print_list的函数。它接受一个列表作为参数,并打印出列表的每个元素。 +9. 声明一个名为reverse_list的函数。它接受一个数组作为参数,并返回数组的反转版本(使用循环)。 + +```py +print(reverse_list([1, 2, 3, 4, 5])) +# [5, 4, 3, 2, 1] +print(reverse_list1(["A", "B", "C"])) +# ["C", "B", "A"] +``` + +10. 声明一个名为capitalize_list_items的函数。它接受一个列表作为参数,并返回首字母大写的项目列表。 +11. 声明一个名为add_item的函数。它接受一个列表和一个项目作为参数。它返回一个在列表末尾添加了项目的列表。 + +```py +food_staff = ['Potato', 'Tomato', 'Mango', 'Milk']; +print(add_item(food_staff, 'Meat')) # ['Potato', 'Tomato', 'Mango', 'Milk','Meat']; +numbers = [2, 3, 7, 9]; +print(add_item(numbers, 5)) [2, 3, 7, 9, 5] +``` + +12. 声明一个名为remove_item的函数。它接受一个列表和一个项目作为参数。它返回一个从中删除了项目的列表。 + +```py +food_staff = ['Potato', 'Tomato', 'Mango', 'Milk']; +print(remove_item(food_staff, 'Mango')) # ['Potato', 'Tomato', 'Milk']; +numbers = [2, 3, 7, 9]; +print(remove_item(numbers, 3)) # [2, 7, 9] +``` + +13. 声明一个名为sum_of_numbers的函数。它接受一个数字参数并将该范围内的所有数字相加。 + +```py +print(sum_of_numbers(5)) # 15 +print(sum_all_numbers(10)) # 55 +print(sum_all_numbers(100)) # 5050 +``` + +14. 声明一个名为sum_of_odds的函数。它接受一个数字参数并将该范围内的所有奇数相加。 +15. 声明一个名为sum_of_even的函数。它接受一个数字参数并将该范围内的所有偶数相加。 + +### 练习:级别2 + +1. 声明一个名为evens_and_odds的函数。它接受一个正整数作为参数,并统计数字中的偶数和奇数个数。 + +```py + print(evens_and_odds(100)) + # 奇数的数量为50。 + # 偶数的数量为51。 +``` + +2. 调用您的函数factorial,它接受一个整数作为参数,并返回该数字的阶乘。 +3. 调用您的函数_is_empty_,它接受一个参数并检查它是否为空。 +4. 编写不同的函数,它们接受列表作为参数。它们应该计算均值、中位数、众数、范围、方差和标准差。 + +### 练习:级别3 + +1. 编写一个名为is_prime的函数,它检查一个数是否为质数。 +2. 编写一个函数,检查列表中的所有项目是否都是唯一的。 +3. 编写一个函数,检查列表中的所有项目是否都属于相同的数据类型。 +4. 编写一个函数,检查提供的变量是否是有效的Python变量。 +5. 转到数据文件夹并访问countries-data.py文件。 + +- 创建一个名为most_spoken_languages_in_the_world的函数。它应返回世界上最常用的10或20种语言,按降序排列。 +- 创建一个名为most_populated_countries的函数。它应返回世界上最多人口的10或20个国家,按降序排列。 diff --git a/11_functions/index.html b/11_functions/index.html new file mode 100644 index 0000000..209765b --- /dev/null +++ b/11_functions/index.html @@ -0,0 +1,1800 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 11 函数 - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +

11 函数⚓︎

+

函数⚓︎

+

到目前为止,我们已经看到了许多内置的Python函数。在本节中,我们将关注自定义函数。什么是函数?在我们开始创建函数之前,让我们学习一下函数是什么以及为什么需要它们?

+

定义函数⚓︎

+

函数是一块可重复使用的代码块或编程语句,旨在执行某个特定的任务。要定义或声明一个函数,Python提供了def关键字。以下是定义函数的语法。只有在调用或调用函数时,函数的代码块才会被执行。

+

声明和调用函数⚓︎

+

当我们创建一个函数时,我们称之为声明函数。当我们开始使用它时,我们称之为调用(calling/ invoking)函数。函数可以带参数或不带参数。

+
# 语法
+# 声明一个函数
+def function_name():
+    代码
+    代码
+# 调用一个函数
+function_name()
+
+

无参数的函数⚓︎

+

函数可以在不带参数的情况下声明。

+

示例:

+
def generate_full_name():
+    first_name = 'Asabeneh'
+    last_name = 'Yetayeh'
+    space = ' '
+    full_name = first_name + space + last_name
+    print(full_name)
+generate_full_name() # 调用一个函数
+
+def add_two_numbers():
+    num_one = 2
+    num_two = 3
+    total = num_one + num_two
+    print(total)
+add_two_numbers()
+
+

有返回值的函数 - 第1部分⚓︎

+

函数也可以返回值,如果一个函数没有返回语句,函数的值就是None。现在,让我们使用return来重写上面的函数。从现在开始,我们在调用函数时从函数中获取一个值并打印它。

+
def generate_full_name():
+    first_name = 'Asabeneh'
+    last_name = 'Yetayeh'
+    space = ' '
+    full_name = first_name + space + last_name
+    return full_name
+print(generate_full_name())
+
+def add_two_numbers():
+    num_one = 2
+    num_two = 3
+    total = num_one + num_two
+    return total
+print(add_two_numbers())
+
+

带参数的函数⚓︎

+

在函数中,我们可以将不同的数据类型(数字、字符串、布尔值、列表、元组、字典或集合)作为参数传递

+
    +
  • 单个参数:如果我们的函数带有参数,我们应该使用一个参数来调用我们的函数
  • +
+
  # 语法
+  # 声明一个函数
+  def function_name(parameter):
+    代码
+    代码
+  # 调用函数
+  print(function_name(argument))
+
+

示例:

+
def greetings(name):
+    message = name + ',欢迎来到Python for Everyone!'
+    return message
+
+print(greetings('Asabeneh'))
+
+def add_ten(num):
+    ten = 10
+    return num + ten
+print(add_ten(90))
+
+def square_number(x):
+    return x * x
+print(square_number(2))
+
+def area_of_circle(r):
+    PI = 3.14
+    area = PI * r ** 2
+    return area
+print(area_of_circle(10))
+
+def sum_of_numbers(n):
+    total = 0
+    for i in range(n+1):
+        total+=i
+    print(total)
+print(sum_of_numbers(10)) # 55
+print(sum_of_numbers(100)) # 5050
+
+
    +
  • 两个参数:一个函数可以有参数也可以没有参数。一个函数也可以有两个或更多的参数。如果我们的函数有参数,我们应该用参数来调用它。让我们看一个带有两个参数的函数:
  • +
+
  # 语法
+  # 声明一个函数
+  def function_name(para1, para2):
+    代码
+    代码
+  # 调用函数
+  print(function_name(arg1, arg2))
+
+

示例:

+
def generate_full_name(first_name, last_name):
+    space = ' '
+    full_name = first_name + space + last_name
+    return full_name
+print('全名:', generate_full_name('Asabeneh','Yetayeh'))
+
+def sum_two_numbers(num_one, num_two):
+    sum = num_one + num_two
+    return sum
+print('两个数字的和:', sum_two_numbers(1, 9))
+
+def calculate_age(current_year, birth_year):
+    age = current_year - birth_year
+    return age;
+
+print('年龄:', calculate_age(2021, 1819))
+
+def weight_of_object(mass, gravity):
+    weight = str(mass * gravity)+ ' N' # 将值首先更改为字符串
+    return weight
+print('牛顿下的物体重量:', weight_of_object(100, 9.81))
+
+

使用键和值传递参数⚓︎

+

如果我们使用键和值传递参数,参数的顺序就不重要了。

+
# 语法
+# 声明一个函数
+def function_name(para1, para2):
+    代码
+    代码
+# 调用函数
+print(function_name(para1 = 'John', para2 = 'Doe')) # 参数的顺序在这里不重要
+
+

示例:

+
def print_fullname(firstname, lastname):
+    space = ' '
+    full_name = firstname  + space + lastname
+    print(full_name)
+print(print_fullname(firstname = 'Asabeneh', lastname = 'Yetayeh'))
+
+def add_two_numbers(num1, num2):
+    total = num1 + num2
+    print(total)
+print(add_two_numbers(num2 = 3, num1 = 2)) # 顺序不重要
+
+

有返回值的函数 - 第2部分⚓︎

+

如果我们不使用函数返回值,那么默认情况下我们的函数将返回None。为了从函数中返回一个值,我们使用关键字return后跟我们要返回的变量。我们可以从函数中返回任何类型的数据。

+
    +
  • 返回一个字符串: + 示例:
  • +
+
def print_name(firstname):
+    return firstname
+print_name('Asabeneh') # Asabeneh
+
+def print_full_name(firstname, lastname):
+    space = ' '
+    full_name = firstname  + space + lastname
+    return full_name
+print_full_name(firstname='Asabeneh', lastname='Yetayeh')
+
+
    +
  • 返回一个数字:
  • +
+

示例:

+
def add_two_numbers(num1, num2):
+    total = num1 + num2
+    return total
+print(add_two_numbers(2, 3))
+
+def calculate_age(current_year, birth_year):
+    age = current_year - birth_year
+    return age;
+print('年龄:', calculate_age(2019, 1819))
+
+
    +
  • 返回一个布尔值: + 示例:
  • +
+
def is_even(n):
+    if n % 2 == 0:
+        print('偶数')
+        return True    # return会停止函数的进一步执行,类似于break
+    return False
+print(is_even(10)) # True
+print(is_even(7)) # False
+
+
    +
  • 返回一个列表: + 示例:
  • +
+
def find_even_numbers(n):
+    evens = []
+    for i in range(n + 1):
+        if i % 2 == 0:
+            evens.append(i)
+    return evens
+print(find_even_numbers(10))
+
+

具有默认参数的函数⚓︎

+

有时,当我们调用函数时,我们会传递默认值给参数。如果我们在调用函数时不传递参数,那么参数的默认值将被使用。

+
# 语法
+# 声明一个函数
+def function_name(param = value):
+    代码
+    代码
+# 调用函数
+function_name()
+function_name(arg)
+
+

示例:

+
def greetings(name = 'Peter'):
+    message = name + ',欢迎来到Python for Everyone!'
+    return message
+print(greetings())
+print(greetings('Asabeneh'))
+
+def generate_full_name(first_name = 'Asabeneh', last_name = 'Yetayeh'):
+    space = ' '
+    full_name = first_name + space + last_name
+    return full_name
+
+print(generate_full_name())
+print(generate_full_name('David','Smith'))
+
+def calculate_age(birth_year, current_year = 2021):
+    age = current_year - birth_year
+    return age;
+print('年龄:', calculate_age(1821))
+
+def weight_of_object(mass, gravity = 9.81):
+    weight = str(mass * gravity)+ ' N' # 将值首先更改为字符串
+    return weight
+print('牛顿下的物体重量:', weight_of_object(100)) # 9.81 - 地表上的平均重力
+print('牛顿下的物体重量:', weight_of_object(100, 1.62)) # 月球表面上的重力
+
+

任意数量的参数⚓︎

+

如果我们不知道要传递给函数的参数数量,我们可以通过在参数名之前添加*来创建一个可以接受任意数量参数的函数。

+
# 语法
+# 声明一个函数
+def function_name(*args):
+    代码
+    代码
+# 调用函数
+function_name(param1, param2, param3,..)
+
+

示例:

+
def sum_all_nums(*nums):
+    total = 0
+    for num in nums:
+        total += num     # 相当于 total = total + num
+    return total
+print(sum_all_nums(2, 3, 5)) # 10
+
+

函数中的默认参数和任意数量的参数⚓︎

+
def generate_groups(*args, team='Default Team'):
+    print(team)
+    for i in args:
+        print(i)
+
+generate_groups('Asabeneh', 'Brook', 'David', 'Eyob')
+
+
Default Team
+Asabeneh
+Brook
+David
+Eyob
+
+

函数作为另一个函数的参数⚓︎

+
# 您可以将函数作为参数传递
+def square_number(n):
+    return n * n
+def do_something(f, x):
+    return f(x)
+print(do_something(square_number, 3)) # 9
+
+

💻 练习:第11天⚓︎

+

练习:级别1⚓︎

+
    +
  1. 声明一个名为_add_two_numbers_的函数。它接受两个参数并返回它们的和。
  2. +
  3. 圆的面积计算如下:面积 = π x r x r。编写一个计算_area_of_circle的函数。
  4. +
  5. 编写一个名为add_all_nums的函数,它接受任意数量的参数并求它们的总和。检查列表中的所有项目是否都是数字类型。如果不是,请给出合理的反馈。
  6. +
  7. 摄氏度可以使用以下公式转换为华氏度:°F = (°C x 9/5) + 32。编写一个将°C转换为°F的函数_convert_celsius_to_fahrenheit_。
  8. +
  9. 编写一个名为check_season的函数,它接受一个月份参数并返回季节:秋季、冬季、春季或夏季。
  10. +
  11. 编写一个名为calculate_slope的函数,它返回线性方程的斜率。
  12. +
  13. 二次方程计算如下:ax² + bx + c = 0。编写一个计算二次方程解集的函数_solve_quadratic_eqn_。
  14. +
  15. 声明一个名为print_list的函数。它接受一个列表作为参数,并打印出列表的每个元素。
  16. +
  17. 声明一个名为reverse_list的函数。它接受一个数组作为参数,并返回数组的反转版本(使用循环)。
  18. +
+
print(reverse_list([1, 2, 3, 4, 5]))
+# [5, 4, 3, 2, 1]
+print(reverse_list1(["A", "B", "C"]))
+# ["C", "B", "A"]
+
+
    +
  1. 声明一个名为capitalize_list_items的函数。它接受一个列表作为参数,并返回首字母大写的项目列表。
  2. +
  3. 声明一个名为add_item的函数。它接受一个列表和一个项目作为参数。它返回一个在列表末尾添加了项目的列表。
  4. +
+
food_staff = ['Potato', 'Tomato', 'Mango', 'Milk'];
+print(add_item(food_staff, 'Meat'))     # ['Potato', 'Tomato', 'Mango', 'Milk','Meat'];
+numbers = [2, 3, 7, 9];
+print(add_item(numbers, 5))      [2, 3, 7, 9, 5]
+
+
    +
  1. 声明一个名为remove_item的函数。它接受一个列表和一个项目作为参数。它返回一个从中删除了项目的列表。
  2. +
+
food_staff = ['Potato', 'Tomato', 'Mango', 'Milk'];
+print(remove_item(food_staff, 'Mango'))  # ['Potato', 'Tomato', 'Milk'];
+numbers = [2, 3, 7, 9];
+print(remove_item(numbers, 3))  # [2, 7, 9]
+
+
    +
  1. 声明一个名为sum_of_numbers的函数。它接受一个数字参数并将该范围内的所有数字相加。
  2. +
+
print(sum_of_numbers(5))  # 15
+print(sum_all_numbers(10)) # 55
+print(sum_all_numbers(100)) # 5050
+
+
    +
  1. 声明一个名为sum_of_odds的函数。它接受一个数字参数并将该范围内的所有奇数相加。
  2. +
  3. 声明一个名为sum_of_even的函数。它接受一个数字参数并将该范围内的所有偶数相加。
  4. +
+

练习:级别2⚓︎

+
    +
  1. 声明一个名为evens_and_odds的函数。它接受一个正整数作为参数,并统计数字中的偶数和奇数个数。
  2. +
+
    print(evens_and_odds(100))
+    # 奇数的数量为50。
+    # 偶数的数量为51。
+
+
    +
  1. 调用您的函数factorial,它接受一个整数作为参数,并返回该数字的阶乘。
  2. +
  3. 调用您的函数_is_empty_,它接受一个参数并检查它是否为空。
  4. +
  5. 编写不同的函数,它们接受列表作为参数。它们应该计算均值、中位数、众数、范围、方差和标准差。
  6. +
+

练习:级别3⚓︎

+
    +
  1. 编写一个名为is_prime的函数,它检查一个数是否为质数。
  2. +
  3. 编写一个函数,检查列表中的所有项目是否都是唯一的。
  4. +
  5. 编写一个函数,检查列表中的所有项目是否都属于相同的数据类型。
  6. +
  7. 编写一个函数,检查提供的变量是否是有效的Python变量。
  8. +
  9. +

    转到数据文件夹并访问countries-data.py文件。

    +
  10. +
  11. +

    创建一个名为most_spoken_languages_in_the_world的函数。它应返回世界上最常用的10或20种语言,按降序排列。

    +
  12. +
  13. 创建一个名为most_populated_countries的函数。它应返回世界上最多人口的10或20个国家,按降序排列。
  14. +
+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/12_modules/12_modules.md b/12_modules/12_modules.md new file mode 100644 index 0000000..caa6e94 --- /dev/null +++ b/12_modules/12_modules.md @@ -0,0 +1,305 @@ +
+

30 Days Of Python: Day 12 - Modules

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+ +
+ + +[<< Day 11](../11_Day_Functions/11_functions.md) | [Day 13>>](../13_Day_List_comprehension/13_list_comprehension.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 12](#-day-12) + - [Modules](#modules) + - [What is a Module](#what-is-a-module) + - [Creating a Module](#creating-a-module) + - [Importing a Module](#importing-a-module) + - [Import Functions from a Module](#import-functions-from-a-module) + - [Import Functions from a Module and Renaming](#import-functions-from-a-module-and-renaming) + - [Import Built-in Modules](#import-built-in-modules) + - [OS Module](#os-module) + - [Sys Module](#sys-module) + - [Statistics Module](#statistics-module) + - [Math Module](#math-module) + - [String Module](#string-module) + - [Random Module](#random-module) + - [💻 Exercises: Day 12](#-exercises-day-12) + - [Exercises: Level 1](#exercises-level-1) + - [Exercises: Level 2](#exercises-level-2) + - [Exercises: Level 3](#exercises-level-3) + +# 📘 Day 12 + +## Modules + +### What is a Module + +A module is a file containing a set of codes or a set of functions which can be included to an application. A module could be a file containing a single variable, a function or a big code base. + +### Creating a Module + +To create a module we write our codes in a python script and we save it as a .py file. Create a file named mymodule.py inside your project folder. Let us write some code in this file. + +```py +# mymodule.py file +def generate_full_name(firstname, lastname): + return firstname + ' ' + lastname +``` + +Create main.py file in your project directory and import the mymodule.py file. + +### Importing a Module + +To import the file we use the _import_ keyword and the name of the file only. + +```py +# main.py file +import mymodule +print(mymodule.generate_full_name('Asabeneh', 'Yetayeh')) # Asabeneh Yetayeh +``` + +### Import Functions from a Module + +We can have many functions in a file and we can import all the functions differently. + +```py +# main.py file +from mymodule import generate_full_name, sum_two_nums, person, gravity +print(generate_full_name('Asabneh','Yetayeh')) +print(sum_two_nums(1,9)) +mass = 100; +weight = mass * gravity +print(weight) +print(person['firstname']) +``` + +### Import Functions from a Module and Renaming + +During importing we can rename the name of the module. + +```py +# main.py file +from mymodule import generate_full_name as fullname, sum_two_nums as total, person as p, gravity as g +print(fullname('Asabneh','Yetayeh')) +print(total(1, 9)) +mass = 100; +weight = mass * g +print(weight) +print(p) +print(p['firstname']) +``` + +## Import Built-in Modules + +Like other programming languages we can also import modules by importing the file/function using the key word _import_. Let's import the common module we will use most of the time. Some of the common built-in modules: _math_, _datetime_, _os_,_sys_, _random_, _statistics_, _collections_, _json_,_re_ + +### OS Module + +Using python _os_ module it is possible to automatically perform many operating system tasks. The OS module in Python provides functions for creating, changing current working directory, and removing a directory (folder), fetching its contents, changing and identifying the current directory. + +```py +# import the module +import os +# Creating a directory +os.mkdir('directory_name') +# Changing the current directory +os.chdir('path') +# Getting current working directory +os.getcwd() +# Removing directory +os.rmdir() +``` + +### Sys Module + +The sys module provides functions and variables used to manipulate different parts of the Python runtime environment. Function sys.argv returns a list of command line arguments passed to a Python script. The item at index 0 in this list is always the name of the script, at index 1 is the argument passed from the command line. + +Example of a script.py file: + +```py +import sys +#print(sys.argv[0], argv[1],sys.argv[2]) # this line would print out: filename argument1 argument2 +print('Welcome {}. Enjoy {} challenge!'.format(sys.argv[1], sys.argv[2])) +``` + +Now to check how this script works I wrote in command line: + +```sh +python script.py Asabeneh 30DaysOfPython +``` + +The result: + +```sh +Welcome Asabeneh. Enjoy 30DayOfPython challenge! +``` + +Some useful sys commands: + +```py +# to exit sys +sys.exit() +# To know the largest integer variable it takes +sys.maxsize +# To know environment path +sys.path +# To know the version of python you are using +sys.version +``` + +### Statistics Module + +The statistics module provides functions for mathematical statistics of numeric data. The popular statistical functions which are defined in this module: _mean_, _median_, _mode_, _stdev_ etc. + +```py +from statistics import * # importing all the statistics modules +ages = [20, 20, 4, 24, 25, 22, 26, 20, 23, 22, 26] +print(mean(ages)) # ~22.9 +print(median(ages)) # 23 +print(mode(ages)) # 20 +print(stdev(ages)) # ~2.3 +``` + +### Math Module + +Module containing many mathematical operations and constants. + +```py +import math +print(math.pi) # 3.141592653589793, pi constant +print(math.sqrt(2)) # 1.4142135623730951, square root +print(math.pow(2, 3)) # 8.0, exponential function +print(math.floor(9.81)) # 9, rounding to the lowest +print(math.ceil(9.81)) # 10, rounding to the highest +print(math.log10(100)) # 2, logarithm with 10 as base +``` + +Now, we have imported the *math* module which contains lots of function which can help us to perform mathematical calculations. To check what functions the module has got, we can use _help(math)_, or _dir(math)_. This will display the available functions in the module. If we want to import only a specific function from the module we import it as follows: + +```py +from math import pi +print(pi) +``` + +It is also possible to import multiple functions at once + +```py + +from math import pi, sqrt, pow, floor, ceil, log10 +print(pi) # 3.141592653589793 +print(sqrt(2)) # 1.4142135623730951 +print(pow(2, 3)) # 8.0 +print(floor(9.81)) # 9 +print(ceil(9.81)) # 10 +print(math.log10(100)) # 2 + +``` + +But if we want to import all the function in math module we can use \* . + +```py +from math import * +print(pi) # 3.141592653589793, pi constant +print(sqrt(2)) # 1.4142135623730951, square root +print(pow(2, 3)) # 8.0, exponential +print(floor(9.81)) # 9, rounding to the lowest +print(ceil(9.81)) # 10, rounding to the highest +print(math.log10(100)) # 2 +``` + +When we import we can also rename the name of the function. + +```py +from math import pi as PI +print(PI) # 3.141592653589793 +``` + +### String Module + +A string module is a useful module for many purposes. The example below shows some use of the string module. + +```py +import string +print(string.ascii_letters) # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ +print(string.digits) # 0123456789 +print(string.punctuation) # !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~ +``` + +### Random Module + +By now you are familiar with importing modules. Let us do one more import to get very familiar with it. Let us import _random_ module which gives us a random number between 0 and 0.9999.... The _random_ module has lots of functions but in this section we will only use _random_ and _randint_. + +```py +from random import random, randint +print(random()) # it doesn't take any arguments; it returns a value between 0 and 0.9999 +print(randint(5, 20)) # it returns a random integer number between [5, 20] inclusive +``` + +🌕 You are going far. Keep going! You have just completed day 12 challenges and you are 12 steps a head in to your way to greatness. Now do some exercises for your brain and muscles. + +## 💻 Exercises: Day 12 + +### Exercises: Level 1 + +1. Writ a function which generates a six digit/character random_user_id. + ```py + print(random_user_id()); + '1ee33d' + ``` +2. Modify the previous task. Declare a function named user_id_gen_by_user. It doesn’t take any parameters but it takes two inputs using input(). One of the inputs is the number of characters and the second input is the number of IDs which are supposed to be generated. + +```py +print(user_id_gen_by_user()) # user input: 5 5 +#output: +#kcsy2 +#SMFYb +#bWmeq +#ZXOYh +#2Rgxf + +print(user_id_gen_by_user()) # 16 5 +#1GCSgPLMaBAVQZ26 +#YD7eFwNQKNs7qXaT +#ycArC5yrRupyG00S +#UbGxOFI7UXSWAyKN +#dIV0SSUTgAdKwStr +``` + +3. Write a function named rgb_color_gen. It will generate rgb colors (3 values ranging from 0 to 255 each). + +```py +print(rgb_color_gen()) +# rgb(125,244,255) - the output should be in this form +``` + +### Exercises: Level 2 + +1. Write a function list_of_hexa_colors which returns any number of hexadecimal colors in an array (six hexadecimal numbers written after #. Hexadecimal numeral system is made out of 16 symbols, 0-9 and first 6 letters of the alphabet, a-f. Check the task 6 for output examples). +1. Write a function list_of_rgb_colors which returns any number of RGB colors in an array. +1. Write a function generate_colors which can generate any number of hexa or rgb colors. + +```py + generate_colors('hexa', 3) # ['#a3e12f','#03ed55','#eb3d2b'] + generate_colors('hexa', 1) # ['#b334ef'] + generate_colors('rgb', 3) # ['rgb(5, 55, 175','rgb(50, 105, 100','rgb(15, 26, 80'] + generate_colors('rgb', 1) # ['rgb(33,79, 176)'] + ``` + +### Exercises: Level 3 + +1. Call your function shuffle_list, it takes a list as a parameter and it returns a shuffled list +1. Write a function which returns an array of seven random numbers in a range of 0-9. All the numbers must be unique. + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 11](../11_Day_Functions/11_functions.md) | [Day 13>>](../13_Day_List_comprehension/13_list_comprehension.md) diff --git a/12_modules/index.html b/12_modules/index.html new file mode 100644 index 0000000..998355f --- /dev/null +++ b/12_modules/index.html @@ -0,0 +1,1706 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 modules - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+

<< Day 11 | Day 13>>

+

30DaysOfPython

+ +

📘 Day 12⚓︎

+

Modules⚓︎

+

What is a Module⚓︎

+

A module is a file containing a set of codes or a set of functions which can be included to an application. A module could be a file containing a single variable, a function or a big code base.

+

Creating a Module⚓︎

+

To create a module we write our codes in a python script and we save it as a .py file. Create a file named mymodule.py inside your project folder. Let us write some code in this file.

+
# mymodule.py file
+def generate_full_name(firstname, lastname):
+    return firstname + ' ' + lastname
+
+

Create main.py file in your project directory and import the mymodule.py file.

+

Importing a Module⚓︎

+

To import the file we use the import keyword and the name of the file only.

+
# main.py file
+import mymodule
+print(mymodule.generate_full_name('Asabeneh', 'Yetayeh')) # Asabeneh Yetayeh
+
+

Import Functions from a Module⚓︎

+

We can have many functions in a file and we can import all the functions differently.

+
# main.py file
+from mymodule import generate_full_name, sum_two_nums, person, gravity
+print(generate_full_name('Asabneh','Yetayeh'))
+print(sum_two_nums(1,9))
+mass = 100;
+weight = mass * gravity
+print(weight)
+print(person['firstname'])
+
+

Import Functions from a Module and Renaming⚓︎

+

During importing we can rename the name of the module.

+
# main.py file
+from mymodule import generate_full_name as fullname, sum_two_nums as total, person as p, gravity as g
+print(fullname('Asabneh','Yetayeh'))
+print(total(1, 9))
+mass = 100;
+weight = mass * g
+print(weight)
+print(p)
+print(p['firstname'])
+
+

Import Built-in Modules⚓︎

+

Like other programming languages we can also import modules by importing the file/function using the key word import. Let's import the common module we will use most of the time. Some of the common built-in modules: math, datetime, os,sys, random, statistics, collections, json,re

+

OS Module⚓︎

+

Using python os module it is possible to automatically perform many operating system tasks. The OS module in Python provides functions for creating, changing current working directory, and removing a directory (folder), fetching its contents, changing and identifying the current directory.

+
# import the module
+import os
+# Creating a directory
+os.mkdir('directory_name')
+# Changing the current directory
+os.chdir('path')
+# Getting current working directory
+os.getcwd()
+# Removing directory
+os.rmdir()
+
+

Sys Module⚓︎

+

The sys module provides functions and variables used to manipulate different parts of the Python runtime environment. Function sys.argv returns a list of command line arguments passed to a Python script. The item at index 0 in this list is always the name of the script, at index 1 is the argument passed from the command line.

+

Example of a script.py file:

+
import sys
+#print(sys.argv[0], argv[1],sys.argv[2])  # this line would print out: filename argument1 argument2
+print('Welcome {}. Enjoy  {} challenge!'.format(sys.argv[1], sys.argv[2]))
+
+

Now to check how this script works I wrote in command line:

+
python script.py Asabeneh 30DaysOfPython
+
+

The result:

+
Welcome Asabeneh. Enjoy  30DayOfPython challenge! 
+
+

Some useful sys commands:

+
# to exit sys
+sys.exit()
+# To know the largest integer variable it takes
+sys.maxsize
+# To know environment path
+sys.path
+# To know the version of python you are using
+sys.version
+
+

Statistics Module⚓︎

+

The statistics module provides functions for mathematical statistics of numeric data. The popular statistical functions which are defined in this module: mean, median, mode, stdev etc.

+
from statistics import * # importing all the statistics modules
+ages = [20, 20, 4, 24, 25, 22, 26, 20, 23, 22, 26]
+print(mean(ages))       # ~22.9
+print(median(ages))     # 23
+print(mode(ages))       # 20
+print(stdev(ages))      # ~2.3
+
+

Math Module⚓︎

+

Module containing many mathematical operations and constants.

+
import math
+print(math.pi)           # 3.141592653589793, pi constant
+print(math.sqrt(2))      # 1.4142135623730951, square root
+print(math.pow(2, 3))    # 8.0, exponential function
+print(math.floor(9.81))  # 9, rounding to the lowest
+print(math.ceil(9.81))   # 10, rounding to the highest
+print(math.log10(100))   # 2, logarithm with 10 as base
+
+

Now, we have imported the math module which contains lots of function which can help us to perform mathematical calculations. To check what functions the module has got, we can use help(math), or dir(math). This will display the available functions in the module. If we want to import only a specific function from the module we import it as follows:

+
from math import pi
+print(pi)
+
+

It is also possible to import multiple functions at once

+
from math import pi, sqrt, pow, floor, ceil, log10
+print(pi)                 # 3.141592653589793
+print(sqrt(2))            # 1.4142135623730951
+print(pow(2, 3))          # 8.0
+print(floor(9.81))        # 9
+print(ceil(9.81))         # 10
+print(math.log10(100))    # 2
+
+

But if we want to import all the function in math module we can use * .

+
from math import *
+print(pi)                  # 3.141592653589793, pi constant
+print(sqrt(2))             # 1.4142135623730951, square root
+print(pow(2, 3))           # 8.0, exponential
+print(floor(9.81))         # 9, rounding to the lowest
+print(ceil(9.81))          # 10, rounding to the highest
+print(math.log10(100))     # 2
+
+

When we import we can also rename the name of the function.

+
from math import pi as  PI
+print(PI) # 3.141592653589793
+
+

String Module⚓︎

+

A string module is a useful module for many purposes. The example below shows some use of the string module.

+
import string
+print(string.ascii_letters) # abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ
+print(string.digits)        # 0123456789
+print(string.punctuation)   # !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~
+
+

Random Module⚓︎

+

By now you are familiar with importing modules. Let us do one more import to get very familiar with it. Let us import random module which gives us a random number between 0 and 0.9999.... The random module has lots of functions but in this section we will only use random and randint.

+
from random import random, randint
+print(random())   # it doesn't take any arguments; it returns a value between 0 and 0.9999
+print(randint(5, 20)) # it returns a random integer number between [5, 20] inclusive
+
+

🌕 You are going far. Keep going! You have just completed day 12 challenges and you are 12 steps a head in to your way to greatness. Now do some exercises for your brain and muscles.

+

💻 Exercises: Day 12⚓︎

+

Exercises: Level 1⚓︎

+
    +
  1. Writ a function which generates a six digit/character random_user_id. +
      print(random_user_id());
    +  '1ee33d'
    +
  2. +
  3. Modify the previous task. Declare a function named user_id_gen_by_user. It doesn’t take any parameters but it takes two inputs using input(). One of the inputs is the number of characters and the second input is the number of IDs which are supposed to be generated.
  4. +
+
print(user_id_gen_by_user()) # user input: 5 5
+#output:
+#kcsy2
+#SMFYb
+#bWmeq
+#ZXOYh
+#2Rgxf
+
+print(user_id_gen_by_user()) # 16 5
+#1GCSgPLMaBAVQZ26
+#YD7eFwNQKNs7qXaT
+#ycArC5yrRupyG00S
+#UbGxOFI7UXSWAyKN
+#dIV0SSUTgAdKwStr
+
+
    +
  1. Write a function named rgb_color_gen. It will generate rgb colors (3 values ranging from 0 to 255 each).
  2. +
+
print(rgb_color_gen())
+# rgb(125,244,255) - the output should be in this form
+
+

Exercises: Level 2⚓︎

+
    +
  1. Write a function list_of_hexa_colors which returns any number of hexadecimal colors in an array (six hexadecimal numbers written after #. Hexadecimal numeral system is made out of 16 symbols, 0-9 and first 6 letters of the alphabet, a-f. Check the task 6 for output examples).
  2. +
  3. Write a function list_of_rgb_colors which returns any number of RGB colors in an array.
  4. +
  5. Write a function generate_colors which can generate any number of hexa or rgb colors.
  6. +
+

py + generate_colors('hexa', 3) # ['#a3e12f','#03ed55','#eb3d2b'] + generate_colors('hexa', 1) # ['#b334ef'] + generate_colors('rgb', 3) # ['rgb(5, 55, 175','rgb(50, 105, 100','rgb(15, 26, 80'] + generate_colors('rgb', 1) # ['rgb(33,79, 176)']

+

Exercises: Level 3⚓︎

+
    +
  1. Call your function shuffle_list, it takes a list as a parameter and it returns a shuffled list
  2. +
  3. Write a function which returns an array of seven random numbers in a range of 0-9. All the numbers must be unique.
  4. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 11 | Day 13>>

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/13_list_comprehension/13_list_comprehension.md b/13_list_comprehension/13_list_comprehension.md new file mode 100644 index 0000000..d5c392f --- /dev/null +++ b/13_list_comprehension/13_list_comprehension.md @@ -0,0 +1,209 @@ +
+

30 Days Of Python: Day 13 - List Comprehension

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+ +
+ + +[<< Day 12](../12_Day_Modules/12_modules.md) | [Day 14>>](../14_Day_Higher_order_functions/14_higher_order_functions.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 13](#-day-13) + - [List Comprehension](#list-comprehension) + - [Lambda Function](#lambda-function) + - [Creating a Lambda Function](#creating-a-lambda-function) + - [Lambda Function Inside Another Function](#lambda-function-inside-another-function) + - [💻 Exercises: Day 13](#-exercises-day-13) + +# 📘 Day 13 + +## List Comprehension + +List comprehension in Python is a compact way of creating a list from a sequence. It is a short way to create a new list. List comprehension is considerably faster than processing a list using the _for_ loop. + +```py +# syntax +[i for i in iterable if expression] +``` + +**Example:1** + +For instance if you want to change a string to a list of characters. You can use a couple of methods. Let's see some of them: + +```py +# One way +language = 'Python' +lst = list(language) # changing the string to list +print(type(lst)) # list +print(lst) # ['P', 'y', 't', 'h', 'o', 'n'] + +# Second way: list comprehension +lst = [i for i in language] +print(type(lst)) # list +print(lst) # ['P', 'y', 't', 'h', 'o', 'n'] + +``` + +**Example:2** + +For instance if you want to generate a list of numbers + +```py +# Generating numbers +numbers = [i for i in range(11)] # to generate numbers from 0 to 10 +print(numbers) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + +# It is possible to do mathematical operations during iteration +squares = [i * i for i in range(11)] +print(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100] + +# It is also possible to make a list of tuples +numbers = [(i, i * i) for i in range(11)] +print(numbers) # [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)] + +``` + +**Example:2** + +List comprehension can be combined with if expression + + +```py +# Generating even numbers +even_numbers = [i for i in range(21) if i % 2 == 0] # to generate even numbers list in range 0 to 21 +print(even_numbers) # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20] + +# Generating odd numbers +odd_numbers = [i for i in range(21) if i % 2 != 0] # to generate odd numbers in range 0 to 21 +print(odd_numbers) # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19] +# Filter numbers: let's filter out positive even numbers from the list below +numbers = [-8, -7, -3, -1, 0, 1, 3, 4, 5, 7, 6, 8, 10] +positive_even_numbers = [i for i in range(21) if i % 2 == 0 and i > 0] +print(positive_even_numbers) # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20] + +# Flattening a three dimensional array +list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]] +flattened_list = [ number for row in list_of_lists for number in row] +print(flattened_list) # [1, 2, 3, 4, 5, 6, 7, 8, 9] +``` + +## Lambda Function + +Lambda function is a small anonymous function without a name. It can take any number of arguments, but can only have one expression. Lambda function is similar to anonymous functions in JavaScript. We need it when we want to write an anonymous function inside another function. + +### Creating a Lambda Function + +To create a lambda function we use _lambda_ keyword followed by a parameter(s), followed by an expression. See the syntax and the example below. Lambda function does not use return but it explicitly returns the expression. + +```py +# syntax +x = lambda param1, param2, param3: param1 + param2 + param2 +print(x(arg1, arg2, arg3)) +``` + +**Example:** + +```py +# Named function +def add_two_nums(a, b): + return a + b + +print(add_two_nums(2, 3)) # 5 +# Lets change the above function to a lambda function +add_two_nums = lambda a, b: a + b +print(add_two_nums(2,3)) # 5 + +# Self invoking lambda function +(lambda a, b: a + b)(2,3) # 5 - need to encapsulate it in print() to see the result in the console + +square = lambda x : x ** 2 +print(square(3)) # 9 +cube = lambda x : x ** 3 +print(cube(3)) # 27 + +# Multiple variables +multiple_variable = lambda a, b, c: a ** 2 - 3 * b + 4 * c +print(multiple_variable(5, 5, 3)) # 22 +``` + +### Lambda Function Inside Another Function + +Using a lambda function inside another function. + +```py +def power(x): + return lambda n : x ** n + +cube = power(2)(3) # function power now need 2 arguments to run, in separate rounded brackets +print(cube) # 8 +two_power_of_five = power(2)(5) +print(two_power_of_five) # 32 +``` + +🌕 Keep up the good work. Keep the momentum going, the sky is the limit! You have just completed day 13 challenges and you are 13 steps a head in to your way to greatness. Now do some exercises for your brain and muscles. + +## 💻 Exercises: Day 13 + +1. Filter only negative and zero in the list using list comprehension + ```py + numbers = [-4, -3, -2, -1, 0, 2, 4, 6] + ``` +2. Flatten the following list of lists of lists to a one dimensional list : + + ```py + list_of_lists =[[[1, 2, 3]], [[4, 5, 6]], [[7, 8, 9]]] + + output + [1, 2, 3, 4, 5, 6, 7, 8, 9] + ``` + +3. Using list comprehension create the following list of tuples: + ```py + [(0, 1, 0, 0, 0, 0, 0), + (1, 1, 1, 1, 1, 1, 1), + (2, 1, 2, 4, 8, 16, 32), + (3, 1, 3, 9, 27, 81, 243), + (4, 1, 4, 16, 64, 256, 1024), + (5, 1, 5, 25, 125, 625, 3125), + (6, 1, 6, 36, 216, 1296, 7776), + (7, 1, 7, 49, 343, 2401, 16807), + (8, 1, 8, 64, 512, 4096, 32768), + (9, 1, 9, 81, 729, 6561, 59049), + (10, 1, 10, 100, 1000, 10000, 100000)] + ``` +4. Flatten the following list to a new list: + ```py + countries = [[('Finland', 'Helsinki')], [('Sweden', 'Stockholm')], [('Norway', 'Oslo')]] + output: + [['FINLAND','FIN', 'HELSINKI'], ['SWEDEN', 'SWE', 'STOCKHOLM'], ['NORWAY', 'NOR', 'OSLO']] + ``` +5. Change the following list to a list of dictionaries: + ```py + countries = [[('Finland', 'Helsinki')], [('Sweden', 'Stockholm')], [('Norway', 'Oslo')]] + output: + [{'country': 'FINLAND', 'city': 'HELSINKI'}, + {'country': 'SWEDEN', 'city': 'STOCKHOLM'}, + {'country': 'NORWAY', 'city': 'OSLO'}] + ``` +6. Change the following list of lists to a list of concatenated strings: + ```py + names = [[('Asabeneh', 'Yetayeh')], [('David', 'Smith')], [('Donald', 'Trump')], [('Bill', 'Gates')]] + output + ['Asabeneh Yetaeyeh', 'David Smith', 'Donald Trump', 'Bill Gates'] + ``` +7. Write a lambda function which can solve a slope or y-intercept of linear functions. + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 12](../12_Day_Modules/12_modules.md) | [Day 14>>](../14_Day_Higher_order_functions/14_higher_order_functions.md) diff --git a/13_list_comprehension/index.html b/13_list_comprehension/index.html new file mode 100644 index 0000000..223e7f3 --- /dev/null +++ b/13_list_comprehension/index.html @@ -0,0 +1,1405 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 13 list comprehension - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+

<< Day 12 | Day 14>>

+

30DaysOfPython

+ +

📘 Day 13⚓︎

+

List Comprehension⚓︎

+

List comprehension in Python is a compact way of creating a list from a sequence. It is a short way to create a new list. List comprehension is considerably faster than processing a list using the for loop.

+
# syntax
+[i for i in iterable if expression]
+
+

Example:1

+

For instance if you want to change a string to a list of characters. You can use a couple of methods. Let's see some of them:

+
# One way
+language = 'Python'
+lst = list(language) # changing the string to list
+print(type(lst))     # list
+print(lst)           # ['P', 'y', 't', 'h', 'o', 'n']
+
+# Second way: list comprehension
+lst = [i for i in language]
+print(type(lst)) # list
+print(lst)       # ['P', 'y', 't', 'h', 'o', 'n']
+
+

Example:2

+

For instance if you want to generate a list of numbers

+
# Generating numbers
+numbers = [i for i in range(11)]  # to generate numbers from 0 to 10
+print(numbers)                    # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+
+# It is possible to do mathematical operations during iteration
+squares = [i * i for i in range(11)]
+print(squares)                    # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
+
+# It is also possible to make a list of tuples
+numbers = [(i, i * i) for i in range(11)]
+print(numbers)                             # [(0, 0), (1, 1), (2, 4), (3, 9), (4, 16), (5, 25)]
+
+

Example:2

+

List comprehension can be combined with if expression

+
# Generating even numbers
+even_numbers = [i for i in range(21) if i % 2 == 0]  # to generate even numbers list in range 0 to 21
+print(even_numbers)                    # [0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+
+# Generating odd numbers
+odd_numbers = [i for i in range(21) if i % 2 != 0]  # to generate odd numbers in range 0 to 21
+print(odd_numbers)                      # [1, 3, 5, 7, 9, 11, 13, 15, 17, 19]
+# Filter numbers: let's filter out positive even numbers from the list below
+numbers = [-8, -7, -3, -1, 0, 1, 3, 4, 5, 7, 6, 8, 10]
+positive_even_numbers = [i for i in range(21) if i % 2 == 0 and i > 0]
+print(positive_even_numbers)                    # [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
+
+# Flattening a three dimensional array
+list_of_lists = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
+flattened_list = [ number for row in list_of_lists for number in row]
+print(flattened_list)    # [1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+

Lambda Function⚓︎

+

Lambda function is a small anonymous function without a name. It can take any number of arguments, but can only have one expression. Lambda function is similar to anonymous functions in JavaScript. We need it when we want to write an anonymous function inside another function.

+

Creating a Lambda Function⚓︎

+

To create a lambda function we use lambda keyword followed by a parameter(s), followed by an expression. See the syntax and the example below. Lambda function does not use return but it explicitly returns the expression.

+
# syntax
+x = lambda param1, param2, param3: param1 + param2 + param2
+print(x(arg1, arg2, arg3))
+
+

Example:

+
# Named function
+def add_two_nums(a, b):
+    return a + b
+
+print(add_two_nums(2, 3))     # 5
+# Lets change the above function to a lambda function
+add_two_nums = lambda a, b: a + b
+print(add_two_nums(2,3))    # 5
+
+# Self invoking lambda function
+(lambda a, b: a + b)(2,3) # 5 - need to encapsulate it in print() to see the result in the console
+
+square = lambda x : x ** 2
+print(square(3))    # 9
+cube = lambda x : x ** 3
+print(cube(3))    # 27
+
+# Multiple variables
+multiple_variable = lambda a, b, c: a ** 2 - 3 * b + 4 * c
+print(multiple_variable(5, 5, 3)) # 22
+
+

Lambda Function Inside Another Function⚓︎

+

Using a lambda function inside another function.

+
def power(x):
+    return lambda n : x ** n
+
+cube = power(2)(3)   # function power now need 2 arguments to run, in separate rounded brackets
+print(cube)          # 8
+two_power_of_five = power(2)(5) 
+print(two_power_of_five)  # 32
+
+

🌕 Keep up the good work. Keep the momentum going, the sky is the limit! You have just completed day 13 challenges and you are 13 steps a head in to your way to greatness. Now do some exercises for your brain and muscles.

+

💻 Exercises: Day 13⚓︎

+
    +
  1. Filter only negative and zero in the list using list comprehension +
    numbers = [-4, -3, -2, -1, 0, 2, 4, 6]
    +
  2. +
  3. Flatten the following list of lists of lists to a one dimensional list :
  4. +
+
list_of_lists =[[[1, 2, 3]], [[4, 5, 6]], [[7, 8, 9]]]
+
+output
+[1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+
    +
  1. Using list comprehension create the following list of tuples: +
    [(0, 1, 0, 0, 0, 0, 0),
    +(1, 1, 1, 1, 1, 1, 1),
    +(2, 1, 2, 4, 8, 16, 32),
    +(3, 1, 3, 9, 27, 81, 243),
    +(4, 1, 4, 16, 64, 256, 1024),
    +(5, 1, 5, 25, 125, 625, 3125),
    +(6, 1, 6, 36, 216, 1296, 7776),
    +(7, 1, 7, 49, 343, 2401, 16807),
    +(8, 1, 8, 64, 512, 4096, 32768),
    +(9, 1, 9, 81, 729, 6561, 59049),
    +(10, 1, 10, 100, 1000, 10000, 100000)]
    +
  2. +
  3. Flatten the following list to a new list: +
    countries = [[('Finland', 'Helsinki')], [('Sweden', 'Stockholm')], [('Norway', 'Oslo')]]
    +output:
    +[['FINLAND','FIN', 'HELSINKI'], ['SWEDEN', 'SWE', 'STOCKHOLM'], ['NORWAY', 'NOR', 'OSLO']]
    +
  4. +
  5. Change the following list to a list of dictionaries: +
    countries = [[('Finland', 'Helsinki')], [('Sweden', 'Stockholm')], [('Norway', 'Oslo')]]
    +output:
    +[{'country': 'FINLAND', 'city': 'HELSINKI'},
    +{'country': 'SWEDEN', 'city': 'STOCKHOLM'},
    +{'country': 'NORWAY', 'city': 'OSLO'}]
    +
  6. +
  7. Change the following list of lists to a list of concatenated strings: +
    names = [[('Asabeneh', 'Yetayeh')], [('David', 'Smith')], [('Donald', 'Trump')], [('Bill', 'Gates')]]
    +output
    +['Asabeneh Yetaeyeh', 'David Smith', 'Donald Trump', 'Bill Gates']
    +
  8. +
  9. Write a lambda function which can solve a slope or y-intercept of linear functions.
  10. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 12 | Day 14>>

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/14_higher_order_functions/14_higher_order_functions.md b/14_higher_order_functions/14_higher_order_functions.md new file mode 100644 index 0000000..2af24c6 --- /dev/null +++ b/14_higher_order_functions/14_higher_order_functions.md @@ -0,0 +1,370 @@ +
+

30 Days Of Python: Day 14 - Higher Order Functions

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ + +[<< Day 13](../13_Day_List_comprehension/13_list_comprehension.md) | [Day 15>>](../15_Day_Python_type_errors/15_python_type_errors.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) +- [📘 Day 14](#-day-14) + - [Higher Order Functions](#higher-order-functions) + - [Function as a Parameter](#function-as-a-parameter) + - [Function as a Return Value](#function-as-a-return-value) + - [Python Closures](#python-closures) + - [Python Decorators](#python-decorators) + - [Creating Decorators](#creating-decorators) + - [Applying Multiple Decorators to a Single Function](#applying-multiple-decorators-to-a-single-function) + - [Accepting Parameters in Decorator Functions](#accepting-parameters-in-decorator-functions) + - [Built-in Higher Order Functions](#built-in-higher-order-functions) + - [Python - Map Function](#python---map-function) + - [Python - Filter Function](#python---filter-function) + - [Python - Reduce Function](#python---reduce-function) + - [💻 Exercises: Day 14](#-exercises-day-14) + - [Exercises: Level 1](#exercises-level-1) + - [Exercises: Level 2](#exercises-level-2) + - [Exercises: Level 3](#exercises-level-3) + +# 📘 Day 14 + +## Higher Order Functions + +In Python functions are treated as first class citizens, allowing you to perform the following operations on functions: + +- A function can take one or more functions as parameters +- A function can be returned as a result of another function +- A function can be modified +- A function can be assigned to a variable + +In this section, we will cover: + +1. Handling functions as parameters +2. Returning functions as return value from another functions +3. Using Python closures and decorators + +### Function as a Parameter + +```py +def sum_numbers(nums): # normal function + return sum(nums) # a sad function abusing the built-in sum function :< + +def higher_order_function(f, lst): # function as a parameter + summation = f(lst) + return summation +result = higher_order_function(sum_numbers, [1, 2, 3, 4, 5]) +print(result) # 15 +``` + +### Function as a Return Value + +```py +def square(x): # a square function + return x ** 2 + +def cube(x): # a cube function + return x ** 3 + +def absolute(x): # an absolute value function + if x >= 0: + return x + else: + return -(x) + +def higher_order_function(type): # a higher order function returning a function + if type == 'square': + return square + elif type == 'cube': + return cube + elif type == 'absolute': + return absolute + +result = higher_order_function('square') +print(result(3)) # 9 +result = higher_order_function('cube') +print(result(3)) # 27 +result = higher_order_function('absolute') +print(result(-3)) # 3 +``` + +You can see from the above example that the higher order function is returning different functions depending on the passed parameter + +## Python Closures + +Python allows a nested function to access the outer scope of the enclosing function. This is is known as a Closure. Let us have a look at how closures work in Python. In Python, closure is created by nesting a function inside another encapsulating function and then returning the inner function. See the example below. + +**Example:** + +```py +def add_ten(): + ten = 10 + def add(num): + return num + ten + return add + +closure_result = add_ten() +print(closure_result(5)) # 15 +print(closure_result(10)) # 20 +``` + +## Python Decorators + +A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate. + +### Creating Decorators + +To create a decorator function, we need an outer function with an inner wrapper function. + +**Example:** + +```py +# Normal function +def greeting(): + return 'Welcome to Python' +def uppercase_decorator(function): + def wrapper(): + func = function() + make_uppercase = func.upper() + return make_uppercase + return wrapper +g = uppercase_decorator(greeting) +print(g()) # WELCOME TO PYTHON + +## Let us implement the example above with a decorator + +'''This decorator function is a higher order function +that takes a function as a parameter''' +def uppercase_decorator(function): + def wrapper(): + func = function() + make_uppercase = func.upper() + return make_uppercase + return wrapper +@uppercase_decorator +def greeting(): + return 'Welcome to Python' +print(greeting()) # WELCOME TO PYTHON + +``` + +### Applying Multiple Decorators to a Single Function + +```py + +'''These decorator functions are higher order functions +that take functions as parameters''' + +# First Decorator +def uppercase_decorator(function): + def wrapper(): + func = function() + make_uppercase = func.upper() + return make_uppercase + return wrapper + +# Second decorator +def split_string_decorator(function): + def wrapper(): + func = function() + splitted_string = func.split() + return splitted_string + + return wrapper + +@split_string_decorator +@uppercase_decorator # order with decorators is important in this case - .upper() function does not work with lists +def greeting(): + return 'Welcome to Python' +print(greeting()) # WELCOME TO PYTHON +``` + +### Accepting Parameters in Decorator Functions + +Most of the time we need our functions to take parameters, so we might need to define a decorator that accepts parameters. + +```py +def decorator_with_parameters(function): + def wrapper_accepting_parameters(para1, para2, para3): + function(para1, para2, para3) + print("I live in {}".format(para3)) + return wrapper_accepting_parameters + +@decorator_with_parameters +def print_full_name(first_name, last_name, country): + print("I am {} {}. I love to teach.".format( + first_name, last_name, country)) + +print_full_name("Asabeneh", "Yetayeh",'Finland') +``` + +## Built-in Higher Order Functions + +Some of the built-in higher order functions that we cover in this part are _map()_, _filter_, and _reduce_. +Lambda function can be passed as a parameter and the best use case of lambda functions is in functions like map, filter and reduce. + +### Python - Map Function + +The map() function is a built-in function that takes a function and iterable as parameters. + +```py + # syntax + map(function, iterable) +``` + +**Example:1** + +```py +numbers = [1, 2, 3, 4, 5] # iterable +def square(x): + return x ** 2 +numbers_squared = map(square, numbers) +print(list(numbers_squared)) # [1, 4, 9, 16, 25] +# Lets apply it with a lambda function +numbers_squared = map(lambda x : x ** 2, numbers) +print(list(numbers_squared)) # [1, 4, 9, 16, 25] +``` + +**Example:2** + +```py +numbers_str = ['1', '2', '3', '4', '5'] # iterable +numbers_int = map(int, numbers_str) +print(list(numbers_int)) # [1, 2, 3, 4, 5] +``` + +**Example:3** + +```py +names = ['Asabeneh', 'Lidiya', 'Ermias', 'Abraham'] # iterable + +def change_to_upper(name): + return name.upper() + +names_upper_cased = map(change_to_upper, names) +print(list(names_upper_cased)) # ['ASABENEH', 'LIDIYA', 'ERMIAS', 'ABRAHAM'] + +# Let us apply it with a lambda function +names_upper_cased = map(lambda name: name.upper(), names) +print(list(names_upper_cased)) # ['ASABENEH', 'LIDIYA', 'ERMIAS', 'ABRAHAM'] +``` + +What actually map does is iterating over a list. For instance, it changes the names to upper case and returns a new list. + +### Python - Filter Function + +The filter() function calls the specified function which returns boolean for each item of the specified iterable (list). It filters the items that satisfy the filtering criteria. + +```py + # syntax + filter(function, iterable) +``` + +**Example:1** + +```py +# Lets filter only even nubers +numbers = [1, 2, 3, 4, 5] # iterable + +def is_even(num): + if num % 2 == 0: + return True + return False + +even_numbers = filter(is_even, numbers) +print(list(even_numbers)) # [2, 4] +``` + +**Example:2** + +```py +numbers = [1, 2, 3, 4, 5] # iterable + +def is_odd(num): + if num % 2 != 0: + return True + return False + +odd_numbers = filter(is_odd, numbers) +print(list(odd_numbers)) # [1, 3, 5] +``` + +```py +# Filter long name +names = ['Asabeneh', 'Lidiya', 'Ermias', 'Abraham'] # iterable +def is_name_long(name): + if len(name) > 7: + return True + return False + +long_names = filter(is_name_long, names) +print(list(long_names)) # ['Asabeneh'] +``` + +### Python - Reduce Function + +The _reduce()_ function is defined in the functools module and we should import it from this module. Like map and filter it takes two parameters, a function and an iterable. However, it does not return another iterable, instead it returns a single value. +**Example:1** + +```py +numbers_str = ['1', '2', '3', '4', '5'] # iterable +def add_two_nums(x, y): + return int(x) + int(y) + +total = reduce(add_two_nums, numbers_str) +print(total) # 15 +``` + +## 💻 Exercises: Day 14 + +```py +countries = ['Estonia', 'Finland', 'Sweden', 'Denmark', 'Norway', 'Iceland'] +names = ['Asabeneh', 'Lidiya', 'Ermias', 'Abraham'] +numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] +``` + +### Exercises: Level 1 + +1. Explain the difference between map, filter, and reduce. +2. Explain the difference between higher order function, closure and decorator +3. Define a call function before map, filter or reduce, see examples. +4. Use for loop to print each country in the countries list. +5. Use for to print each name in the names list. +6. Use for to print each number in the numbers list. + +### Exercises: Level 2 + +1. Use map to create a new list by changing each country to uppercase in the countries list +1. Use map to create a new list by changing each number to its square in the numbers list +1. Use map to change each name to uppercase in the names list +1. Use filter to filter out countries containing 'land'. +1. Use filter to filter out countries having exactly six characters. +1. Use filter to filter out countries containing six letters and more in the country list. +1. Use filter to filter out countries starting with an 'E' +1. Chain two or more list iterators (eg. arr.map(callback).filter(callback).reduce(callback)) +1. Declare a function called get_string_lists which takes a list as a parameter and then returns a list containing only string items. +1. Use reduce to sum all the numbers in the numbers list. +1. Use reduce to concatenate all the countries and to produce this sentence: Estonia, Finland, Sweden, Denmark, Norway, and Iceland are north European countries +1. Declare a function called categorize_countries that returns a list of countries with some common pattern (you can find the [countries list](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/countries.py) in this repository as countries.js(eg 'land', 'ia', 'island', 'stan')). +1. Create a function returning a dictionary, where keys stand for starting letters of countries and values are the number of country names starting with that letter. +2. Declare a get_first_ten_countries function - it returns a list of first ten countries from the countries.js list in the data folder. +1. Declare a get_last_ten_countries function that returns the last ten countries in the countries list. + +### Exercises: Level 3 + +1. Use the countries_data.py (https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/countries-data.py) file and follow the tasks below: + - Sort countries by name, by capital, by population + - Sort out the ten most spoken languages by location. + - Sort out the ten most populated countries. + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 13](../13_Day_List_comprehension/13_list_comprehension.md) | [Day 15>>](../15_Day_Python_type_errors/15_python_type_errors.md) \ No newline at end of file diff --git a/14_higher_order_functions/index.html b/14_higher_order_functions/index.html new file mode 100644 index 0000000..d67d355 --- /dev/null +++ b/14_higher_order_functions/index.html @@ -0,0 +1,1772 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 14 higher order functions - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+

<< Day 13 | Day 15>>

+

30DaysOfPython +- 📘 Day 14 + - Higher Order Functions + - Function as a Parameter + - Function as a Return Value + - Python Closures + - Python Decorators + - Creating Decorators + - Applying Multiple Decorators to a Single Function + - Accepting Parameters in Decorator Functions + - Built-in Higher Order Functions + - Python - Map Function + - Python - Filter Function + - Python - Reduce Function + - 💻 Exercises: Day 14 + - Exercises: Level 1 + - Exercises: Level 2 + - Exercises: Level 3

+

📘 Day 14⚓︎

+

Higher Order Functions⚓︎

+

In Python functions are treated as first class citizens, allowing you to perform the following operations on functions:

+
    +
  • A function can take one or more functions as parameters
  • +
  • A function can be returned as a result of another function
  • +
  • A function can be modified
  • +
  • A function can be assigned to a variable
  • +
+

In this section, we will cover:

+
    +
  1. Handling functions as parameters
  2. +
  3. Returning functions as return value from another functions
  4. +
  5. Using Python closures and decorators
  6. +
+

Function as a Parameter⚓︎

+
def sum_numbers(nums):  # normal function
+    return sum(nums)    # a sad function abusing the built-in sum function :<
+
+def higher_order_function(f, lst):  # function as a parameter
+    summation = f(lst)
+    return summation
+result = higher_order_function(sum_numbers, [1, 2, 3, 4, 5])
+print(result)       # 15
+
+

Function as a Return Value⚓︎

+
def square(x):          # a square function
+    return x ** 2
+
+def cube(x):            # a cube function
+    return x ** 3
+
+def absolute(x):        # an absolute value function
+    if x >= 0:
+        return x
+    else:
+        return -(x)
+
+def higher_order_function(type): # a higher order function returning a function
+    if type == 'square':
+        return square
+    elif type == 'cube':
+        return cube
+    elif type == 'absolute':
+        return absolute
+
+result = higher_order_function('square')
+print(result(3))       # 9
+result = higher_order_function('cube')
+print(result(3))       # 27
+result = higher_order_function('absolute')
+print(result(-3))      # 3
+
+

You can see from the above example that the higher order function is returning different functions depending on the passed parameter

+

Python Closures⚓︎

+

Python allows a nested function to access the outer scope of the enclosing function. This is is known as a Closure. Let us have a look at how closures work in Python. In Python, closure is created by nesting a function inside another encapsulating function and then returning the inner function. See the example below.

+

Example:

+
def add_ten():
+    ten = 10
+    def add(num):
+        return num + ten
+    return add
+
+closure_result = add_ten()
+print(closure_result(5))  # 15
+print(closure_result(10))  # 20
+
+

Python Decorators⚓︎

+

A decorator is a design pattern in Python that allows a user to add new functionality to an existing object without modifying its structure. Decorators are usually called before the definition of a function you want to decorate.

+

Creating Decorators⚓︎

+

To create a decorator function, we need an outer function with an inner wrapper function.

+

Example:

+
# Normal function
+def greeting():
+    return 'Welcome to Python'
+def uppercase_decorator(function):
+    def wrapper():
+        func = function()
+        make_uppercase = func.upper()
+        return make_uppercase
+    return wrapper
+g = uppercase_decorator(greeting)
+print(g())          # WELCOME TO PYTHON
+
+## Let us implement the example above with a decorator
+
+'''This decorator function is a higher order function
+that takes a function as a parameter'''
+def uppercase_decorator(function):
+    def wrapper():
+        func = function()
+        make_uppercase = func.upper()
+        return make_uppercase
+    return wrapper
+@uppercase_decorator
+def greeting():
+    return 'Welcome to Python'
+print(greeting())   # WELCOME TO PYTHON
+
+

Applying Multiple Decorators to a Single Function⚓︎

+
'''These decorator functions are higher order functions
+that take functions as parameters'''
+
+# First Decorator
+def uppercase_decorator(function):
+    def wrapper():
+        func = function()
+        make_uppercase = func.upper()
+        return make_uppercase
+    return wrapper
+
+# Second decorator
+def split_string_decorator(function):
+    def wrapper():
+        func = function()
+        splitted_string = func.split()
+        return splitted_string
+
+    return wrapper
+
+@split_string_decorator
+@uppercase_decorator     # order with decorators is important in this case - .upper() function does not work with lists
+def greeting():
+    return 'Welcome to Python'
+print(greeting())   # WELCOME TO PYTHON
+
+

Accepting Parameters in Decorator Functions⚓︎

+

Most of the time we need our functions to take parameters, so we might need to define a decorator that accepts parameters.

+
def decorator_with_parameters(function):
+    def wrapper_accepting_parameters(para1, para2, para3):
+        function(para1, para2, para3)
+        print("I live in {}".format(para3))
+    return wrapper_accepting_parameters
+
+@decorator_with_parameters
+def print_full_name(first_name, last_name, country):
+    print("I am {} {}. I love to teach.".format(
+        first_name, last_name, country))
+
+print_full_name("Asabeneh", "Yetayeh",'Finland')
+
+

Built-in Higher Order Functions⚓︎

+

Some of the built-in higher order functions that we cover in this part are map(), filter, and reduce. +Lambda function can be passed as a parameter and the best use case of lambda functions is in functions like map, filter and reduce.

+

Python - Map Function⚓︎

+

The map() function is a built-in function that takes a function and iterable as parameters.

+
    # syntax
+    map(function, iterable)
+
+

Example:1

+
numbers = [1, 2, 3, 4, 5] # iterable
+def square(x):
+    return x ** 2
+numbers_squared = map(square, numbers)
+print(list(numbers_squared))    # [1, 4, 9, 16, 25]
+# Lets apply it with a lambda function
+numbers_squared = map(lambda x : x ** 2, numbers)
+print(list(numbers_squared))    # [1, 4, 9, 16, 25]
+
+

Example:2

+
numbers_str = ['1', '2', '3', '4', '5']  # iterable
+numbers_int = map(int, numbers_str)
+print(list(numbers_int))    # [1, 2, 3, 4, 5]
+
+

Example:3

+
names = ['Asabeneh', 'Lidiya', 'Ermias', 'Abraham']  # iterable
+
+def change_to_upper(name):
+    return name.upper()
+
+names_upper_cased = map(change_to_upper, names)
+print(list(names_upper_cased))    # ['ASABENEH', 'LIDIYA', 'ERMIAS', 'ABRAHAM']
+
+# Let us apply it with a lambda function
+names_upper_cased = map(lambda name: name.upper(), names)
+print(list(names_upper_cased))    # ['ASABENEH', 'LIDIYA', 'ERMIAS', 'ABRAHAM']
+
+

What actually map does is iterating over a list. For instance, it changes the names to upper case and returns a new list.

+

Python - Filter Function⚓︎

+

The filter() function calls the specified function which returns boolean for each item of the specified iterable (list). It filters the items that satisfy the filtering criteria.

+
    # syntax
+    filter(function, iterable)
+
+

Example:1

+
# Lets filter only even nubers
+numbers = [1, 2, 3, 4, 5]  # iterable
+
+def is_even(num):
+    if num % 2 == 0:
+        return True
+    return False
+
+even_numbers = filter(is_even, numbers)
+print(list(even_numbers))       # [2, 4]
+
+

Example:2

+
numbers = [1, 2, 3, 4, 5]  # iterable
+
+def is_odd(num):
+    if num % 2 != 0:
+        return True
+    return False
+
+odd_numbers = filter(is_odd, numbers)
+print(list(odd_numbers))       # [1, 3, 5]
+
+
# Filter long name
+names = ['Asabeneh', 'Lidiya', 'Ermias', 'Abraham']  # iterable
+def is_name_long(name):
+    if len(name) > 7:
+        return True
+    return False
+
+long_names = filter(is_name_long, names)
+print(list(long_names))         # ['Asabeneh']
+
+

Python - Reduce Function⚓︎

+

The reduce() function is defined in the functools module and we should import it from this module. Like map and filter it takes two parameters, a function and an iterable. However, it does not return another iterable, instead it returns a single value. +Example:1

+
numbers_str = ['1', '2', '3', '4', '5']  # iterable
+def add_two_nums(x, y):
+    return int(x) + int(y)
+
+total = reduce(add_two_nums, numbers_str)
+print(total)    # 15
+
+

💻 Exercises: Day 14⚓︎

+
countries = ['Estonia', 'Finland', 'Sweden', 'Denmark', 'Norway', 'Iceland']
+names = ['Asabeneh', 'Lidiya', 'Ermias', 'Abraham']
+numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
+
+

Exercises: Level 1⚓︎

+
    +
  1. Explain the difference between map, filter, and reduce.
  2. +
  3. Explain the difference between higher order function, closure and decorator
  4. +
  5. Define a call function before map, filter or reduce, see examples.
  6. +
  7. Use for loop to print each country in the countries list.
  8. +
  9. Use for to print each name in the names list.
  10. +
  11. Use for to print each number in the numbers list.
  12. +
+

Exercises: Level 2⚓︎

+
    +
  1. Use map to create a new list by changing each country to uppercase in the countries list
  2. +
  3. Use map to create a new list by changing each number to its square in the numbers list
  4. +
  5. Use map to change each name to uppercase in the names list
  6. +
  7. Use filter to filter out countries containing 'land'.
  8. +
  9. Use filter to filter out countries having exactly six characters.
  10. +
  11. Use filter to filter out countries containing six letters and more in the country list.
  12. +
  13. Use filter to filter out countries starting with an 'E'
  14. +
  15. Chain two or more list iterators (eg. arr.map(callback).filter(callback).reduce(callback))
  16. +
  17. Declare a function called get_string_lists which takes a list as a parameter and then returns a list containing only string items.
  18. +
  19. Use reduce to sum all the numbers in the numbers list.
  20. +
  21. Use reduce to concatenate all the countries and to produce this sentence: Estonia, Finland, Sweden, Denmark, Norway, and Iceland are north European countries
  22. +
  23. Declare a function called categorize_countries that returns a list of countries with some common pattern (you can find the countries list in this repository as countries.js(eg 'land', 'ia', 'island', 'stan')).
  24. +
  25. Create a function returning a dictionary, where keys stand for starting letters of countries and values are the number of country names starting with that letter.
  26. +
  27. Declare a get_first_ten_countries function - it returns a list of first ten countries from the countries.js list in the data folder.
  28. +
  29. Declare a get_last_ten_countries function that returns the last ten countries in the countries list.
  30. +
+

Exercises: Level 3⚓︎

+
    +
  1. Use the countries_data.py (https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/countries-data.py) file and follow the tasks below:
  2. +
  3. Sort countries by name, by capital, by population
  4. +
  5. Sort out the ten most spoken languages by location.
  6. +
  7. Sort out the ten most populated countries.
  8. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 13 | Day 15>>

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/15_python_type_errors/15_python_type_errors.md b/15_python_type_errors/15_python_type_errors.md new file mode 100644 index 0000000..16c3e71 --- /dev/null +++ b/15_python_type_errors/15_python_type_errors.md @@ -0,0 +1,361 @@ +
+

30 Days Of Python: Day 15 - Python Type Errors

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ + +[<< Day 14](../14_Day_Higher_order_functions/14_higher_order_functions.md) | [Day 16 >>](../16_Day_Python_date_time/16_python_datetime.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) +- [📘 Day 15](#-day-15) + - [Python Error Types](#python-error-types) + - [SyntaxError](#syntaxerror) + - [NameError](#nameerror) + - [IndexError](#indexerror) + - [ModuleNotFoundError](#modulenotfounderror) + - [AttributeError](#attributeerror) + - [KeyError](#keyerror) + - [TypeError](#typeerror) + - [ImportError](#importerror) + - [ValueError](#valueerror) + - [ZeroDivisionError](#zerodivisionerror) + - [💻 Exercises: Day 15](#-exercises-day-15) + +# 📘 Day 15 + +## Python Error Types + +When we write code it is common that we make a typo or some other common error. If our code fails to run, the Python interpreter will display a message, containing feedback with information on where the problem occurs and the type of an error. It will also sometimes gives us suggestions on a possible fix. Understanding different types of errors in programming languages will help us to debug our code quickly and also it makes us better at what we do. + +Let us see the most common error types one by one. First let us open our Python interactive shell. Go to your you computer terminal and write 'python'. The python interactive shell will be opened. + +### SyntaxError + +**Example 1: SyntaxError** + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> print 'hello world' + File "", line 1 + print 'hello world' + ^ +SyntaxError: Missing parentheses in call to 'print'. Did you mean print('hello world')? +>>> +``` + +As you can see we made a syntax error because we forgot to enclose the string with parenthesis and Python already suggests the solution. Let us fix it. + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> print 'hello world' + File "", line 1 + print 'hello world' + ^ +SyntaxError: Missing parentheses in call to 'print'. Did you mean print('hello world')? +>>> print('hello world') +hello world +>>> +``` + +The error was a _SyntaxError_. After the fix our code was executed without a hitch. Let see more error types. + +### NameError + +**Example 1: NameError** + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> print(age) +Traceback (most recent call last): + File "", line 1, in +NameError: name 'age' is not defined +>>> +``` + +As you can see from the message above, name age is not defined. Yes, it is true that we did not define an age variable but we were trying to print it out as if we had had declared it. Now, lets fix this by declaring it and assigning with a value. + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> print(age) +Traceback (most recent call last): + File "", line 1, in +NameError: name 'age' is not defined +>>> age = 25 +>>> print(age) +25 +>>> +``` + +The type of error was a _NameError_. We debugged the error by defining the variable name. + +### IndexError + +**Example 1: IndexError** + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> numbers = [1, 2, 3, 4, 5] +>>> numbers[5] +Traceback (most recent call last): + File "", line 1, in +IndexError: list index out of range +>>> +``` + +In the example above, Python raised an _IndexError_, because the list has only indexes from 0 to 4 , so it was out of range. + +### ModuleNotFoundError + +**Example 1: ModuleNotFoundError** + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> import maths +Traceback (most recent call last): + File "", line 1, in +ModuleNotFoundError: No module named 'maths' +>>> +``` + +In the example above, I added an extra s to math deliberately and _ModuleNotFoundError_ was raised. Lets fix it by removing the extra s from math. + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> import maths +Traceback (most recent call last): + File "", line 1, in +ModuleNotFoundError: No module named 'maths' +>>> import math +>>> +``` + +We fixed it, so let's use some of the functions from the math module. + +### AttributeError + +**Example 1: AttributeError** + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> import maths +Traceback (most recent call last): + File "", line 1, in +ModuleNotFoundError: No module named 'maths' +>>> import math +>>> math.PI +Traceback (most recent call last): + File "", line 1, in +AttributeError: module 'math' has no attribute 'PI' +>>> +``` + +As you can see, I made a mistake again! Instead of pi, I tried to call a PI function from maths module. It raised an attribute error, it means, that the function does not exist in the module. Lets fix it by changing from PI to pi. + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> import maths +Traceback (most recent call last): + File "", line 1, in +ModuleNotFoundError: No module named 'maths' +>>> import math +>>> math.PI +Traceback (most recent call last): + File "", line 1, in +AttributeError: module 'math' has no attribute 'PI' +>>> math.pi +3.141592653589793 +>>> +``` + +Now, when we call pi from the math module we got the result. + +### KeyError + +**Example 1: KeyError** + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> users = {'name':'Asab', 'age':250, 'country':'Finland'} +>>> users['name'] +'Asab' +>>> users['county'] +Traceback (most recent call last): + File "", line 1, in +KeyError: 'county' +>>> +``` + +As you can see, there was a typo in the key used to get the dictionary value. so, this is a key error and the fix is quite straight forward. Let's do this! + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> user = {'name':'Asab', 'age':250, 'country':'Finland'} +>>> user['name'] +'Asab' +>>> user['county'] +Traceback (most recent call last): + File "", line 1, in +KeyError: 'county' +>>> user['country'] +'Finland' +>>> +``` + +We debugged the error, our code ran and we got the value. + +### TypeError + +**Example 1: TypeError** + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> 4 + '3' +Traceback (most recent call last): + File "", line 1, in +TypeError: unsupported operand type(s) for +: 'int' and 'str' +>>> +``` + +In the example above, a TypeError is raised because we cannot add a number to a string. First solution would be to convert the string to int or float. Another solution would be converting the number to a string (the result then would be '43'). Let us follow the first fix. + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> 4 + '3' +Traceback (most recent call last): + File "", line 1, in +TypeError: unsupported operand type(s) for +: 'int' and 'str' +>>> 4 + int('3') +7 +>>> 4 + float('3') +7.0 +>>> +``` + +Error removed and we got the result we expected. + +### ImportError + +**Example 1: TypeError** + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> from math import power +Traceback (most recent call last): + File "", line 1, in +ImportError: cannot import name 'power' from 'math' +>>> +``` + +There is no function called power in the math module, it goes with a different name: _pow_. Let's correct it: + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> from math import power +Traceback (most recent call last): + File "", line 1, in +ImportError: cannot import name 'power' from 'math' +>>> from math import pow +>>> pow(2,3) +8.0 +>>> +``` + +### ValueError + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> int('12a') +Traceback (most recent call last): + File "", line 1, in +ValueError: invalid literal for int() with base 10: '12a' +>>> +``` + +In this case we cannot change the given string to a number, because of the 'a' letter in it. + +### ZeroDivisionError + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> 1/0 +Traceback (most recent call last): + File "", line 1, in +ZeroDivisionError: division by zero +>>> +``` + +We cannot divide a number by zero. + +We have covered some of the python error types, if you want to check more about it check the python documentation about python error types. +If you are good at reading the error types then you will be able to fix your bugs fast and you will also become a better programmer. + +🌕 You are excelling. You made it to half way to your way to greatness. Now do some exercises for your brain and for your muscle. + +## 💻 Exercises: Day 15 + +1. Open you python interactive shell and try all the examples covered in this section. + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 14](../14_Day_Higher_order_functions/14_higher_order_functions.md) | [Day 16 >>](../16_Day_Python_date_time/16_python_datetime.md) \ No newline at end of file diff --git a/15_python_type_errors/index.html b/15_python_type_errors/index.html new file mode 100644 index 0000000..57102a0 --- /dev/null +++ b/15_python_type_errors/index.html @@ -0,0 +1,1646 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 15 python type errors - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+

<< Day 14 | Day 16 >>

+

30DaysOfPython +- 📘 Day 15 + - Python Error Types + - SyntaxError + - NameError + - IndexError + - ModuleNotFoundError + - AttributeError + - KeyError + - TypeError + - ImportError + - ValueError + - ZeroDivisionError + - 💻 Exercises: Day 15

+

📘 Day 15⚓︎

+

Python Error Types⚓︎

+

When we write code it is common that we make a typo or some other common error. If our code fails to run, the Python interpreter will display a message, containing feedback with information on where the problem occurs and the type of an error. It will also sometimes gives us suggestions on a possible fix. Understanding different types of errors in programming languages will help us to debug our code quickly and also it makes us better at what we do.

+

Let us see the most common error types one by one. First let us open our Python interactive shell. Go to your you computer terminal and write 'python'. The python interactive shell will be opened.

+

SyntaxError⚓︎

+

Example 1: SyntaxError

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> print 'hello world'
+  File "<stdin>", line 1
+    print 'hello world'
+                      ^
+SyntaxError: Missing parentheses in call to 'print'. Did you mean print('hello world')?
+>>>
+
+

As you can see we made a syntax error because we forgot to enclose the string with parenthesis and Python already suggests the solution. Let us fix it.

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> print 'hello world'
+  File "<stdin>", line 1
+    print 'hello world'
+                      ^
+SyntaxError: Missing parentheses in call to 'print'. Did you mean print('hello world')?
+>>> print('hello world')
+hello world
+>>>
+
+

The error was a SyntaxError. After the fix our code was executed without a hitch. Let see more error types.

+

NameError⚓︎

+

Example 1: NameError

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> print(age)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+NameError: name 'age' is not defined
+>>>
+
+

As you can see from the message above, name age is not defined. Yes, it is true that we did not define an age variable but we were trying to print it out as if we had had declared it. Now, lets fix this by declaring it and assigning with a value.

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> print(age)
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+NameError: name 'age' is not defined
+>>> age = 25
+>>> print(age)
+25
+>>>
+
+

The type of error was a NameError. We debugged the error by defining the variable name.

+

IndexError⚓︎

+

Example 1: IndexError

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> numbers = [1, 2, 3, 4, 5]
+>>> numbers[5]
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+IndexError: list index out of range
+>>>
+
+

In the example above, Python raised an IndexError, because the list has only indexes from 0 to 4 , so it was out of range.

+

ModuleNotFoundError⚓︎

+

Example 1: ModuleNotFoundError

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import maths
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ModuleNotFoundError: No module named 'maths'
+>>>
+
+

In the example above, I added an extra s to math deliberately and ModuleNotFoundError was raised. Lets fix it by removing the extra s from math.

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import maths
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ModuleNotFoundError: No module named 'maths'
+>>> import math
+>>>
+
+

We fixed it, so let's use some of the functions from the math module.

+

AttributeError⚓︎

+

Example 1: AttributeError

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import maths
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ModuleNotFoundError: No module named 'maths'
+>>> import math
+>>> math.PI
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+AttributeError: module 'math' has no attribute 'PI'
+>>>
+
+

As you can see, I made a mistake again! Instead of pi, I tried to call a PI function from maths module. It raised an attribute error, it means, that the function does not exist in the module. Lets fix it by changing from PI to pi.

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import maths
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ModuleNotFoundError: No module named 'maths'
+>>> import math
+>>> math.PI
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+AttributeError: module 'math' has no attribute 'PI'
+>>> math.pi
+3.141592653589793
+>>>
+
+

Now, when we call pi from the math module we got the result.

+

KeyError⚓︎

+

Example 1: KeyError

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> users = {'name':'Asab', 'age':250, 'country':'Finland'}
+>>> users['name']
+'Asab'
+>>> users['county']
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+KeyError: 'county'
+>>>
+
+

As you can see, there was a typo in the key used to get the dictionary value. so, this is a key error and the fix is quite straight forward. Let's do this!

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> user = {'name':'Asab', 'age':250, 'country':'Finland'}
+>>> user['name']
+'Asab'
+>>> user['county']
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+KeyError: 'county'
+>>> user['country']
+'Finland'
+>>>
+
+

We debugged the error, our code ran and we got the value.

+

TypeError⚓︎

+

Example 1: TypeError

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> 4 + '3'
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: unsupported operand type(s) for +: 'int' and 'str'
+>>>
+
+

In the example above, a TypeError is raised because we cannot add a number to a string. First solution would be to convert the string to int or float. Another solution would be converting the number to a string (the result then would be '43'). Let us follow the first fix.

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> 4 + '3'
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+TypeError: unsupported operand type(s) for +: 'int' and 'str'
+>>> 4 + int('3')
+7
+>>> 4 + float('3')
+7.0
+>>>
+
+

Error removed and we got the result we expected.

+

ImportError⚓︎

+

Example 1: TypeError

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> from math import power
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ImportError: cannot import name 'power' from 'math'
+>>>
+
+

There is no function called power in the math module, it goes with a different name: pow. Let's correct it:

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> from math import power
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ImportError: cannot import name 'power' from 'math'
+>>> from math import pow
+>>> pow(2,3)
+8.0
+>>>
+
+

ValueError⚓︎

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> int('12a')
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ValueError: invalid literal for int() with base 10: '12a'
+>>>
+
+

In this case we cannot change the given string to a number, because of the 'a' letter in it.

+

ZeroDivisionError⚓︎

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> 1/0
+Traceback (most recent call last):
+  File "<stdin>", line 1, in <module>
+ZeroDivisionError: division by zero
+>>>
+
+

We cannot divide a number by zero.

+

We have covered some of the python error types, if you want to check more about it check the python documentation about python error types. +If you are good at reading the error types then you will be able to fix your bugs fast and you will also become a better programmer.

+

🌕 You are excelling. You made it to half way to your way to greatness. Now do some exercises for your brain and for your muscle.

+

💻 Exercises: Day 15⚓︎

+
    +
  1. Open you python interactive shell and try all the examples covered in this section.
  2. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 14 | Day 16 >>

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/16_python_datetime/16_python_datetime.md b/16_python_datetime/16_python_datetime.md new file mode 100644 index 0000000..65172be --- /dev/null +++ b/16_python_datetime/16_python_datetime.md @@ -0,0 +1,208 @@ +
+

30 Days Of Python: Day 16 - Python Date time

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+ +
+ +[<< Day 15](../15_Day_Python_type_errors/15_python_type_errors.md) | [Day 17 >>](../17_Day_Exception_handling/17_exception_handling.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) +- [📘 Day 16](#-day-16) + - [Python *datetime*](#python-datetime) + - [Getting *datetime* Information](#getting-datetime-information) + - [Formatting Date Output Using *strftime*](#formatting-date-output-using-strftime) + - [String to Time Using *strptime*](#string-to-time-using-strptime) + - [Using *date* from *datetime*](#using-date-from-datetime) + - [Time Objects to Represent Time](#time-objects-to-represent-time) + - [Difference Between Two Points in Time Using](#difference-between-two-points-in-time-using) + - [Difference Between Two Points in Time Using *timedelata*](#difference-between-two-points-in-time-using-timedelata) + - [💻 Exercises: Day 16](#-exercises-day-16) +# 📘 Day 16 + +## Python *datetime* + +Python has got _datetime_ module to handle date and time. + +```py +import datetime +print(dir(datetime)) +['MAXYEAR', 'MINYEAR', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'date', 'datetime', 'datetime_CAPI', 'sys', 'time', 'timedelta', 'timezone', 'tzinfo'] +``` + +With dir or help built-in commands it is possible to know the available functions in a certain module. As you can see, in the datetime module there are many functions, but we will focus on _date_, _datetime_, _time_ and _timedelta_. Let se see them one by one. + +### Getting *datetime* Information + +```py +from datetime import datetime +now = datetime.now() +print(now) # 2021-07-08 07:34:46.549883 +day = now.day # 8 +month = now.month # 7 +year = now.year # 2021 +hour = now.hour # 7 +minute = now.minute # 38 +second = now.second +timestamp = now.timestamp() +print(day, month, year, hour, minute) +print('timestamp', timestamp) +print(f'{day}/{month}/{year}, {hour}:{minute}') # 8/7/2021, 7:38 +``` + +Timestamp or Unix timestamp is the number of seconds elapsed from 1st of January 1970 UTC. + +### Formatting Date Output Using *strftime* + +```py +from datetime import datetime +new_year = datetime(2020, 1, 1) +print(new_year) # 2020-01-01 00:00:00 +day = new_year.day +month = new_year.month +year = new_year.year +hour = new_year.hour +minute = new_year.minute +second = new_year.second +print(day, month, year, hour, minute) #1 1 2020 0 0 +print(f'{day}/{month}/{year}, {hour}:{minute}') # 1/1/2020, 0:0 + +``` + +Formatting date time using *strftime* method and the documentation can be found [here](https://strftime.org/). + +```py +from datetime import datetime +# current date and time +now = datetime.now() +t = now.strftime("%H:%M:%S") +print("time:", t) +time_one = now.strftime("%m/%d/%Y, %H:%M:%S") +# mm/dd/YY H:M:S format +print("time one:", time_one) +time_two = now.strftime("%d/%m/%Y, %H:%M:%S") +# dd/mm/YY H:M:S format +print("time two:", time_two) +``` + +```sh +time: 01:05:01 +time one: 12/05/2019, 01:05:01 +time two: 05/12/2019, 01:05:01 +``` + +Here are all the _strftime_ symbols we use to format time. An example of all the formats for this module. + +![strftime](../images/strftime.png) + +### String to Time Using *strptime* +Here is a [documentation](https://www.programiz.com/python-programming/datetime/strptimet) hat helps to understand the format. + +```py +from datetime import datetime +date_string = "5 December, 2019" +print("date_string =", date_string) +date_object = datetime.strptime(date_string, "%d %B, %Y") +print("date_object =", date_object) +``` + +```sh +date_string = 5 December, 2019 +date_object = 2019-12-05 00:00:00 +``` + +### Using *date* from *datetime* + +```py +from datetime import date +d = date(2020, 1, 1) +print(d) +print('Current date:', d.today()) # 2019-12-05 +# date object of today's date +today = date.today() +print("Current year:", today.year) # 2019 +print("Current month:", today.month) # 12 +print("Current day:", today.day) # 5 +``` + +### Time Objects to Represent Time + +```py +from datetime import time +# time(hour = 0, minute = 0, second = 0) +a = time() +print("a =", a) +# time(hour, minute and second) +b = time(10, 30, 50) +print("b =", b) +# time(hour, minute and second) +c = time(hour=10, minute=30, second=50) +print("c =", c) +# time(hour, minute, second, microsecond) +d = time(10, 30, 50, 200555) +print("d =", d) +``` + +output +a = 00:00:00 +b = 10:30:50 +c = 10:30:50 +d = 10:30:50.200555 + +### Difference Between Two Points in Time Using + +```py +today = date(year=2019, month=12, day=5) +new_year = date(year=2020, month=1, day=1) +time_left_for_newyear = new_year - today +# Time left for new year: 27 days, 0:00:00 +print('Time left for new year: ', time_left_for_newyear) + +t1 = datetime(year = 2019, month = 12, day = 5, hour = 0, minute = 59, second = 0) +t2 = datetime(year = 2020, month = 1, day = 1, hour = 0, minute = 0, second = 0) +diff = t2 - t1 +print('Time left for new year:', diff) # Time left for new year: 26 days, 23: 01: 00 +``` + +### Difference Between Two Points in Time Using *timedelata* + +```py +from datetime import timedelta +t1 = timedelta(weeks=12, days=10, hours=4, seconds=20) +t2 = timedelta(days=7, hours=5, minutes=3, seconds=30) +t3 = t1 - t2 +print("t3 =", t3) +``` + +```sh + date_string = 5 December, 2019 + date_object = 2019-12-05 00:00:00 + t3 = 86 days, 22:56:50 +``` + +🌕 You are an extraordinary. You are 16 steps a head to your way to greatness. Now do some exercises for your brain and muscles. + +## 💻 Exercises: Day 16 + +1. Get the current day, month, year, hour, minute and timestamp from datetime module +1. Format the current date using this format: "%m/%d/%Y, %H:%M:%S") +1. Today is 5 December, 2019. Change this time string to time. +1. Calculate the time difference between now and new year. +1. Calculate the time difference between 1 January 1970 and now. +1. Think, what can you use the datetime module for? Examples: + - Time series analysis + - To get a timestamp of any activities in an application + - Adding posts on a blog + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 15](../15_Day_Python_type_errors/15_python_type_errors.md) | [Day 17 >>](../17_Day_Exception_handling/17_exception_handling.md) \ No newline at end of file diff --git a/16_python_datetime/index.html b/16_python_datetime/index.html new file mode 100644 index 0000000..9ca7a4c --- /dev/null +++ b/16_python_datetime/index.html @@ -0,0 +1,1473 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 16 python datetime - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 16 - Python Date time

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+ +
+ +

<< Day 15 | Day 17 >>

+

30DaysOfPython +- 📘 Day 16 + - Python datetime + - Getting datetime Information + - Formatting Date Output Using strftime + - String to Time Using strptime + - Using date from datetime + - Time Objects to Represent Time + - Difference Between Two Points in Time Using + - Difference Between Two Points in Time Using timedelata + - 💻 Exercises: Day 16

+

📘 Day 16⚓︎

+

Python datetime⚓︎

+

Python has got datetime module to handle date and time.

+
import datetime
+print(dir(datetime))
+['MAXYEAR', 'MINYEAR', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'date', 'datetime', 'datetime_CAPI', 'sys', 'time', 'timedelta', 'timezone', 'tzinfo']
+
+

With dir or help built-in commands it is possible to know the available functions in a certain module. As you can see, in the datetime module there are many functions, but we will focus on date, datetime, time and timedelta. Let se see them one by one.

+

Getting datetime Information⚓︎

+
from datetime import datetime
+now = datetime.now()
+print(now)                      # 2021-07-08 07:34:46.549883
+day = now.day                   # 8
+month = now.month               # 7
+year = now.year                 # 2021
+hour = now.hour                 # 7
+minute = now.minute             # 38
+second = now.second
+timestamp = now.timestamp()
+print(day, month, year, hour, minute)
+print('timestamp', timestamp)
+print(f'{day}/{month}/{year}, {hour}:{minute}')  # 8/7/2021, 7:38
+
+

Timestamp or Unix timestamp is the number of seconds elapsed from 1st of January 1970 UTC.

+

Formatting Date Output Using strftime⚓︎

+
from datetime import datetime
+new_year = datetime(2020, 1, 1)
+print(new_year)      # 2020-01-01 00:00:00
+day = new_year.day
+month = new_year.month
+year = new_year.year
+hour = new_year.hour
+minute = new_year.minute
+second = new_year.second
+print(day, month, year, hour, minute) #1 1 2020 0 0
+print(f'{day}/{month}/{year}, {hour}:{minute}')  # 1/1/2020, 0:0
+
+

Formatting date time using strftime method and the documentation can be found here.

+
from datetime import datetime
+# current date and time
+now = datetime.now()
+t = now.strftime("%H:%M:%S")
+print("time:", t)
+time_one = now.strftime("%m/%d/%Y, %H:%M:%S")
+# mm/dd/YY H:M:S format
+print("time one:", time_one)
+time_two = now.strftime("%d/%m/%Y, %H:%M:%S")
+# dd/mm/YY H:M:S format
+print("time two:", time_two)
+
+
time: 01:05:01
+time one: 12/05/2019, 01:05:01
+time two: 05/12/2019, 01:05:01
+
+

Here are all the strftime symbols we use to format time. An example of all the formats for this module.

+

strftime

+

String to Time Using strptime⚓︎

+

Here is a documentation hat helps to understand the format.

+
from datetime import datetime
+date_string = "5 December, 2019"
+print("date_string =", date_string)
+date_object = datetime.strptime(date_string, "%d %B, %Y")
+print("date_object =", date_object)
+
+
date_string = 5 December, 2019
+date_object = 2019-12-05 00:00:00
+
+

Using date from datetime⚓︎

+
from datetime import date
+d = date(2020, 1, 1)
+print(d)
+print('Current date:', d.today())    # 2019-12-05
+# date object of today's date
+today = date.today()
+print("Current year:", today.year)   # 2019
+print("Current month:", today.month) # 12
+print("Current day:", today.day)     # 5
+
+

Time Objects to Represent Time⚓︎

+
from datetime import time
+# time(hour = 0, minute = 0, second = 0)
+a = time()
+print("a =", a)
+# time(hour, minute and second)
+b = time(10, 30, 50)
+print("b =", b)
+# time(hour, minute and second)
+c = time(hour=10, minute=30, second=50)
+print("c =", c)
+# time(hour, minute, second, microsecond)
+d = time(10, 30, 50, 200555)
+print("d =", d)
+
+

output
+a = 00:00:00
+b = 10:30:50
+c = 10:30:50
+d = 10:30:50.200555

+

Difference Between Two Points in Time Using⚓︎

+
today = date(year=2019, month=12, day=5)
+new_year = date(year=2020, month=1, day=1)
+time_left_for_newyear = new_year - today
+# Time left for new year:  27 days, 0:00:00
+print('Time left for new year: ', time_left_for_newyear)
+
+t1 = datetime(year = 2019, month = 12, day = 5, hour = 0, minute = 59, second = 0)
+t2 = datetime(year = 2020, month = 1, day = 1, hour = 0, minute = 0, second = 0)
+diff = t2 - t1
+print('Time left for new year:', diff) # Time left for new year: 26 days, 23: 01: 00
+
+

Difference Between Two Points in Time Using timedelata⚓︎

+
from datetime import timedelta
+t1 = timedelta(weeks=12, days=10, hours=4, seconds=20)
+t2 = timedelta(days=7, hours=5, minutes=3, seconds=30)
+t3 = t1 - t2
+print("t3 =", t3)
+
+
    date_string = 5 December, 2019
+    date_object = 2019-12-05 00:00:00
+    t3 = 86 days, 22:56:50
+
+

🌕 You are an extraordinary. You are 16 steps a head to your way to greatness. Now do some exercises for your brain and muscles.

+

💻 Exercises: Day 16⚓︎

+
    +
  1. Get the current day, month, year, hour, minute and timestamp from datetime module
  2. +
  3. Format the current date using this format: "%m/%d/%Y, %H:%M:%S")
  4. +
  5. Today is 5 December, 2019. Change this time string to time.
  6. +
  7. Calculate the time difference between now and new year.
  8. +
  9. Calculate the time difference between 1 January 1970 and now.
  10. +
  11. Think, what can you use the datetime module for? Examples:
  12. +
  13. Time series analysis
  14. +
  15. To get a timestamp of any activities in an application
  16. +
  17. Adding posts on a blog
  18. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 15 | Day 17 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/17_exception_handling/17_exception_handling.md b/17_exception_handling/17_exception_handling.md new file mode 100644 index 0000000..b9d5335 --- /dev/null +++ b/17_exception_handling/17_exception_handling.md @@ -0,0 +1,306 @@ +
+

30 Days Of Python: Day 17 - Exception Handling

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ +[<< Day 16](../16_Day_Python_date_time/16_python_datetime.md) | [Day 18 >>](../18_Day_Regular_expressions/18_regular_expressions.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 17](#-day-17) + - [Exception Handling](#exception-handling) + - [Packing and Unpacking Arguments in Python](#packing-and-unpacking-arguments-in-python) + - [Unpacking](#unpacking) + - [Unpacking Lists](#unpacking-lists) + - [Unpacking Dictionaries](#unpacking-dictionaries) + - [Packing](#packing) + - [Packing Lists](#packing-lists) + - [Packing Dictionaries](#packing-dictionaries) + - [Spreading in Python](#spreading-in-python) + - [Enumerate](#enumerate) + - [Zip](#zip) + - [Exercises: Day 17](#exercises-day-17) + +# 📘 Day 17 + +## Exception Handling + +Python uses _try_ and _except_ to handle errors gracefully. A graceful exit (or graceful handling) of errors is a simple programming idiom - a program detects a serious error condition and "exits gracefully", in a controlled manner as a result. Often the program prints a descriptive error message to a terminal or log as part of the graceful exit, this makes our application more robust. The cause of an exception is often external to the program itself. An example of exceptions could be an incorrect input, wrong file name, unable to find a file, a malfunctioning IO device. Graceful handling of errors prevents our applications from crashing. + +We have covered the different Python _error_ types in the previous section. If we use _try_ and _except_ in our program, then it will not raise errors in those blocks. + +![Try and Except](../images/try_except.png) + +```py +try: + code in this block if things go well +except: + code in this block run if things go wrong +``` + +**Example:** + +```py +try: + print(10 + '5') +except: + print('Something went wrong') +``` + +In the example above the second operand is a string. We could change it to float or int to add it with the number to make it work. But without any changes, the second block, _except_, will be executed. + +**Example:** + +```py +try: + name = input('Enter your name:') + year_born = input('Year you were born:') + age = 2019 - year_born + print(f'You are {name}. And your age is {age}.') +except: + print('Something went wrong') +``` + +```sh +Something went wrong +``` + +In the above example, the exception block will run and we do not know exactly the problem. To analyze the problem, we can use the different error types with except. + +In the following example, it will handle the error and will also tell us the kind of error raised. + +```py +try: + name = input('Enter your name:') + year_born = input('Year you were born:') + age = 2019 - year_born + print(f'You are {name}. And your age is {age}.') +except TypeError: + print('Type error occured') +except ValueError: + print('Value error occured') +except ZeroDivisionError: + print('zero division error occured') +``` + +```sh +Enter your name:Asabeneh +Year you born:1920 +Type error occured +``` + +In the code above the output is going to be _TypeError_. +Now, let's add an additional block: + +```py +try: + name = input('Enter your name:') + year_born = input('Year you born:') + age = 2019 - int(year_born) + print('You are {name}. And your age is {age}.') +except TypeError: + print('Type error occur') +except ValueError: + print('Value error occur') +except ZeroDivisionError: + print('zero division error occur') +else: + print('I usually run with the try block') +finally: + print('I alway run.') +``` + +```sh +Enter your name:Asabeneh +Year you born:1920 +You are Asabeneh. And your age is 99. +I usually run with the try block +I alway run. +``` + +It is also shorten the above code as follows: + +```py +try: + name = input('Enter your name:') + year_born = input('Year you born:') + age = 2019 - int(year_born) + print('You are {name}. And your age is {age}.') +except Exception as e: + print(e) + +``` + +## Packing and Unpacking Arguments in Python + +We use two operators: + +- \* for tuples +- \*\* for dictionaries + +Let us take as an example below. It takes only arguments but we have list. We can unpack the list and changes to argument. + +### Unpacking + +#### Unpacking Lists + +```py +def sum_of_five_nums(a, b, c, d, e): + return a + b + c + d + e + +lst = [1, 2, 3, 4, 5] +print(sum_of_five_nums(lst)) # TypeError: sum_of_five_nums() missing 4 required positional arguments: 'b', 'c', 'd', and 'e' +``` + +When we run the this code, it raises an error, because this function takes numbers (not a list) as arguments. Let us unpack/destructure the list. + +```py +def sum_of_five_nums(a, b, c, d, e): + return a + b + c + d + e + +lst = [1, 2, 3, 4, 5] +print(sum_of_five_nums(*lst)) # 15 +``` + +We can also use unpacking in the range built-in function that expects a start and an end. + +```py +numbers = range(2, 7) # normal call with separate arguments +print(list(numbers)) # [2, 3, 4, 5, 6] +args = [2, 7] +numbers = range(*args) # call with arguments unpacked from a list +print(numbers) # [2, 3, 4, 5,6] + +``` + +A list or a tuple can also be unpacked like this: + +```py +countries = ['Finland', 'Sweden', 'Norway', 'Denmark', 'Iceland'] +fin, sw, nor, *rest = countries +print(fin, sw, nor, rest) # Finland Sweden Norway ['Denmark', 'Iceland'] +numbers = [1, 2, 3, 4, 5, 6, 7] +one, *middle, last = numbers +print(one, middle, last) # 1 [2, 3, 4, 5, 6] 7 +``` + +#### Unpacking Dictionaries + +```py +def unpacking_person_info(name, country, city, age): + return f'{name} lives in {country}, {city}. He is {age} year old.' +dct = {'name':'Asabeneh', 'country':'Finland', 'city':'Helsinki', 'age':250} +print(unpacking_person_info(**dct)) # Asabeneh lives in Finland, Helsinki. He is 250 years old. +``` + +### Packing + +Sometimes we never know how many arguments need to be passed to a python function. We can use the packing method to allow our function to take unlimited number or arbitrary number of arguments. + +### Packing Lists + +```py +def sum_all(*args): + s = 0 + for i in args: + s += i + return s +print(sum_all(1, 2, 3)) # 6 +print(sum_all(1, 2, 3, 4, 5, 6, 7)) # 28 +``` + +#### Packing Dictionaries + +```py +def packing_person_info(**kwargs): + # check the type of kwargs and it is a dict type + # print(type(kwargs)) + # Printing dictionary items + for key in kwargs: + print(f"{key} = {kwargs[key]}") + return kwargs + +print(packing_person_info(name="Asabeneh", + country="Finland", city="Helsinki", age=250)) +``` + +```sh +name = Asabeneh +country = Finland +city = Helsinki +age = 250 +{'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250} +``` + +## Spreading in Python + +Like in JavaScript, spreading is possible in Python. Let us check it in an example below: + +```py +lst_one = [1, 2, 3] +lst_two = [4, 5, 6, 7] +lst = [0, *lst_one, *lst_two] +print(lst) # [0, 1, 2, 3, 4, 5, 6, 7] +country_lst_one = ['Finland', 'Sweden', 'Norway'] +country_lst_two = ['Denmark', 'Iceland'] +nordic_countries = [*country_lst_one, *country_lst_two] +print(nordic_countries) # ['Finland', 'Sweden', 'Norway', 'Denmark', 'Iceland'] +``` + +## Enumerate + +If we are interested in an index of a list, we use _enumerate_ built-in function to get the index of each item in the list. + +```py +for index, item in enumerate([20, 30, 40]): + print(index, item) +``` + +```py +for index, i in enumerate(countries): + print('hi') + if i == 'Finland': + print('The country {i} has been found at index {index}') +``` + +```sh +The country Finland has been found at index 1. +``` + +## Zip + +Sometimes we would like to combine lists when looping through them. See the example below: + +```py +fruits = ['banana', 'orange', 'mango', 'lemon', 'lime'] +vegetables = ['Tomato', 'Potato', 'Cabbage','Onion', 'Carrot'] +fruits_and_veges = [] +for f, v in zip(fruits, vegetables): + fruits_and_veges.append({'fruit':f, 'veg':v}) + +print(fruits_and_veges) +``` + +```sh +[{'fruit': 'banana', 'veg': 'Tomato'}, {'fruit': 'orange', 'veg': 'Potato'}, {'fruit': 'mango', 'veg': 'Cabbage'}, {'fruit': 'lemon', 'veg': 'Onion'}, {'fruit': 'lime', 'veg': 'Carrot'}] +``` + +🌕 You are determined. You are 17 steps a head to your way to greatness. Now do some exercises for your brain and muscles. + +## Exercises: Day 17 + +1. names = ['Finland', 'Sweden', 'Norway','Denmark','Iceland', 'Estonia','Russia']. Unpack the first five countries and store them in a variable nordic_countries, store Estonia and Russia in es, and ru respectively. + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 16](../16_Day_Python_date_time/16_python_datetime.md) | [Day 18 >>](../18_Day_Regular_expressions/18_regular_expressions.md) diff --git a/17_exception_handling/index.html b/17_exception_handling/index.html new file mode 100644 index 0000000..c1cd6a4 --- /dev/null +++ b/17_exception_handling/index.html @@ -0,0 +1,1614 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 17 exception handling - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 17 - Exception Handling

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ +

<< Day 16 | Day 18 >>

+

30DaysOfPython

+ +

📘 Day 17⚓︎

+

Exception Handling⚓︎

+

Python uses try and except to handle errors gracefully. A graceful exit (or graceful handling) of errors is a simple programming idiom - a program detects a serious error condition and "exits gracefully", in a controlled manner as a result. Often the program prints a descriptive error message to a terminal or log as part of the graceful exit, this makes our application more robust. The cause of an exception is often external to the program itself. An example of exceptions could be an incorrect input, wrong file name, unable to find a file, a malfunctioning IO device. Graceful handling of errors prevents our applications from crashing.

+

We have covered the different Python error types in the previous section. If we use try and except in our program, then it will not raise errors in those blocks.

+

Try and Except

+
try:
+    code in this block if things go well
+except:
+    code in this block run if things go wrong
+
+

Example:

+
try:
+    print(10 + '5')
+except:
+    print('Something went wrong')
+
+

In the example above the second operand is a string. We could change it to float or int to add it with the number to make it work. But without any changes, the second block, except, will be executed.

+

Example:

+
try:
+    name = input('Enter your name:')
+    year_born = input('Year you were born:')
+    age = 2019 - year_born
+    print(f'You are {name}. And your age is {age}.')
+except:
+    print('Something went wrong')
+
+
Something went wrong
+
+

In the above example, the exception block will run and we do not know exactly the problem. To analyze the problem, we can use the different error types with except.

+

In the following example, it will handle the error and will also tell us the kind of error raised.

+
try:
+    name = input('Enter your name:')
+    year_born = input('Year you were born:')
+    age = 2019 - year_born
+    print(f'You are {name}. And your age is {age}.')
+except TypeError:
+    print('Type error occured')
+except ValueError:
+    print('Value error occured')
+except ZeroDivisionError:
+    print('zero division error occured')
+
+
Enter your name:Asabeneh
+Year you born:1920
+Type error occured
+
+

In the code above the output is going to be TypeError. +Now, let's add an additional block:

+
try:
+    name = input('Enter your name:')
+    year_born = input('Year you born:')
+    age = 2019 - int(year_born)
+    print('You are {name}. And your age is {age}.')
+except TypeError:
+    print('Type error occur')
+except ValueError:
+    print('Value error occur')
+except ZeroDivisionError:
+    print('zero division error occur')
+else:
+    print('I usually run with the try block')
+finally:
+    print('I alway run.')
+
+
Enter your name:Asabeneh
+Year you born:1920
+You are Asabeneh. And your age is 99.
+I usually run with the try block
+I alway run.
+
+

It is also shorten the above code as follows:

+
try:
+    name = input('Enter your name:')
+    year_born = input('Year you born:')
+    age = 2019 - int(year_born)
+    print('You are {name}. And your age is {age}.')
+except Exception as e:
+    print(e)
+
+

Packing and Unpacking Arguments in Python⚓︎

+

We use two operators:

+
    +
  • * for tuples
  • +
  • ** for dictionaries
  • +
+

Let us take as an example below. It takes only arguments but we have list. We can unpack the list and changes to argument.

+

Unpacking⚓︎

+

Unpacking Lists⚓︎

+
def sum_of_five_nums(a, b, c, d, e):
+    return a + b + c + d + e
+
+lst = [1, 2, 3, 4, 5]
+print(sum_of_five_nums(lst)) # TypeError: sum_of_five_nums() missing 4 required positional arguments: 'b', 'c', 'd', and 'e'
+
+

When we run the this code, it raises an error, because this function takes numbers (not a list) as arguments. Let us unpack/destructure the list.

+
def sum_of_five_nums(a, b, c, d, e):
+    return a + b + c + d + e
+
+lst = [1, 2, 3, 4, 5]
+print(sum_of_five_nums(*lst))  # 15
+
+

We can also use unpacking in the range built-in function that expects a start and an end.

+
numbers = range(2, 7)  # normal call with separate arguments
+print(list(numbers)) # [2, 3, 4, 5, 6]
+args = [2, 7]
+numbers = range(*args)  # call with arguments unpacked from a list
+print(numbers)      # [2, 3, 4, 5,6]
+
+

A list or a tuple can also be unpacked like this:

+
countries = ['Finland', 'Sweden', 'Norway', 'Denmark', 'Iceland']
+fin, sw, nor, *rest = countries
+print(fin, sw, nor, rest)   # Finland Sweden Norway ['Denmark', 'Iceland']
+numbers = [1, 2, 3, 4, 5, 6, 7]
+one, *middle, last = numbers
+print(one, middle, last)      #  1 [2, 3, 4, 5, 6] 7
+
+

Unpacking Dictionaries⚓︎

+
def unpacking_person_info(name, country, city, age):
+    return f'{name} lives in {country}, {city}. He is {age} year old.'
+dct = {'name':'Asabeneh', 'country':'Finland', 'city':'Helsinki', 'age':250}
+print(unpacking_person_info(**dct)) # Asabeneh lives in Finland, Helsinki. He is 250 years old.
+
+

Packing⚓︎

+

Sometimes we never know how many arguments need to be passed to a python function. We can use the packing method to allow our function to take unlimited number or arbitrary number of arguments.

+

Packing Lists⚓︎

+
def sum_all(*args):
+    s = 0
+    for i in args:
+        s += i
+    return s
+print(sum_all(1, 2, 3))             # 6
+print(sum_all(1, 2, 3, 4, 5, 6, 7)) # 28
+
+

Packing Dictionaries⚓︎

+
def packing_person_info(**kwargs):
+    # check the type of kwargs and it is a dict type
+    # print(type(kwargs))
+    # Printing dictionary items
+    for key in kwargs:
+        print(f"{key} = {kwargs[key]}")
+    return kwargs
+
+print(packing_person_info(name="Asabeneh",
+      country="Finland", city="Helsinki", age=250))
+
+
name = Asabeneh
+country = Finland
+city = Helsinki
+age = 250
+{'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
+
+

Spreading in Python⚓︎

+

Like in JavaScript, spreading is possible in Python. Let us check it in an example below:

+
lst_one = [1, 2, 3]
+lst_two = [4, 5, 6, 7]
+lst = [0, *lst_one, *lst_two]
+print(lst)          # [0, 1, 2, 3, 4, 5, 6, 7]
+country_lst_one = ['Finland', 'Sweden', 'Norway']
+country_lst_two = ['Denmark', 'Iceland']
+nordic_countries = [*country_lst_one, *country_lst_two]
+print(nordic_countries)  # ['Finland', 'Sweden', 'Norway', 'Denmark', 'Iceland']
+
+

Enumerate⚓︎

+

If we are interested in an index of a list, we use enumerate built-in function to get the index of each item in the list.

+
for index, item in enumerate([20, 30, 40]):
+    print(index, item)
+
+
for index, i in enumerate(countries):
+    print('hi')
+    if i == 'Finland':
+        print('The country {i} has been found at index {index}')
+
+
The country Finland has been found at index 1.
+
+

Zip⚓︎

+

Sometimes we would like to combine lists when looping through them. See the example below:

+
fruits = ['banana', 'orange', 'mango', 'lemon', 'lime']                    
+vegetables = ['Tomato', 'Potato', 'Cabbage','Onion', 'Carrot']
+fruits_and_veges = []
+for f, v in zip(fruits, vegetables):
+    fruits_and_veges.append({'fruit':f, 'veg':v})
+
+print(fruits_and_veges)
+
+
[{'fruit': 'banana', 'veg': 'Tomato'}, {'fruit': 'orange', 'veg': 'Potato'}, {'fruit': 'mango', 'veg': 'Cabbage'}, {'fruit': 'lemon', 'veg': 'Onion'}, {'fruit': 'lime', 'veg': 'Carrot'}]
+
+

🌕 You are determined. You are 17 steps a head to your way to greatness. Now do some exercises for your brain and muscles.

+

Exercises: Day 17⚓︎

+
    +
  1. names = ['Finland', 'Sweden', 'Norway','Denmark','Iceland', 'Estonia','Russia']. Unpack the first five countries and store them in a variable nordic_countries, store Estonia and Russia in es, and ru respectively.
  2. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 16 | Day 18 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/18_regular_expressions/18_regular_expressions.md b/18_regular_expressions/18_regular_expressions.md new file mode 100644 index 0000000..4492c91 --- /dev/null +++ b/18_regular_expressions/18_regular_expressions.md @@ -0,0 +1,459 @@ +
+

30 Days Of Python: Day 18 - Regular Expressions

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ First Edition: Nov 22 - Dec 22, 2019 +
+
+ + +[<< Day 17](../17_Day_Exception_handling/17_exception_handling.md) | [Day 19>>](../19_Day_File_handling/19_file_handling.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 18](#-day-18) + - [Regular Expressions](#regular-expressions) + - [The *re* Module](#the-re-module) + - [Methods in *re* Module](#methods-in-re-module) + - [Match](#match) + - [Search](#search) + - [Searching for All Matches Using *findall*](#searching-for-all-matches-using-findall) + - [Replacing a Substring](#replacing-a-substring) + - [Splitting Text Using RegEx Split](#splitting-text-using-regex-split) + - [Writing RegEx Patterns](#writing-regex-patterns) + - [Square Bracket](#square-bracket) + - [Escape character(\\) in RegEx](#escape-character-in-regex) + - [One or more times(+)](#one-or-more-times) + - [Period(.)](#period) + - [Zero or more times(\*)](#zero-or-more-times) + - [Zero or one time(?)](#zero-or-one-time) + - [Quantifier in RegEx](#quantifier-in-regex) + - [Cart ^](#cart-) + - [💻 Exercises: Day 18](#-exercises-day-18) + - [Exercises: Level 1](#exercises-level-1) + - [Exercises: Level 2](#exercises-level-2) + - [Exercises: Level 3](#exercises-level-3) + +# 📘 Day 18 + +## Regular Expressions + +A regular expression or RegEx is a special text string that helps to find patterns in data. A RegEx can be used to check if some pattern exists in a different data type. To use RegEx in python first we should import the RegEx module which is called *re*. + +### The *re* Module + +After importing the module we can use it to detect or find patterns. + +```py +import re +``` + +### Methods in *re* Module + +To find a pattern we use different set of *re* character sets that allows to search for a match in a string. + +- *re.match()*: searches only in the beginning of the first line of the string and returns matched objects if found, else returns None. +- *re.search*: Returns a match object if there is one anywhere in the string, including multiline strings. +- *re.findall*: Returns a list containing all matches +- *re.split*: Takes a string, splits it at the match points, returns a list +- *re.sub*: Replaces one or many matches within a string + +#### Match + +```py +# syntac +re.match(substring, string, re.I) +# substring is a string or a pattern, string is the text we look for a pattern , re.I is case ignore +``` + +```py +import re + +txt = 'I love to teach python and javaScript' +# It returns an object with span, and match +match = re.match('I love to teach', txt, re.I) +print(match) # +# We can get the starting and ending position of the match as tuple using span +span = match.span() +print(span) # (0, 15) +# Lets find the start and stop position from the span +start, end = span +print(start, end) # 0, 15 +substring = txt[start:end] +print(substring) # I love to teach +``` + +As you can see from the example above, the pattern we are looking for (or the substring we are looking for) is *I love to teach*. The match function returns an object **only** if the text starts with the pattern. + +```py +import re + +txt = 'I love to teach python and javaScript' +match = re.match('I like to teach', txt, re.I) +print(match) # None +``` + +The string does not string with *I like to teach*, therefore there was no match and the match method returned None. + +#### Search + +```py +# syntax +re.match(substring, string, re.I) +# substring is a pattern, string is the text we look for a pattern , re.I is case ignore flag +``` + +```py +import re + +txt = '''Python is the most beautiful language that a human being has ever created. +I recommend python for a first programming language''' + +# It returns an object with span and match +match = re.search('first', txt, re.I) +print(match) # +# We can get the starting and ending position of the match as tuple using span +span = match.span() +print(span) # (100, 105) +# Lets find the start and stop position from the span +start, end = span +print(start, end) # 100 105 +substring = txt[start:end] +print(substring) # first +``` + +As you can see, search is much better than match because it can look for the pattern throughout the text. Search returns a match object with a first match that was found, otherwise it returns *None*. A much better *re* function is *findall*. This function checks for the pattern through the whole string and returns all the matches as a list. + +#### Searching for All Matches Using *findall* + +*findall()* returns all the matches as a list + +```py +txt = '''Python is the most beautiful language that a human being has ever created. +I recommend python for a first programming language''' + +# It return a list +matches = re.findall('language', txt, re.I) +print(matches) # ['language', 'language'] +``` + +As you can see, the word *language* was found two times in the string. Let us practice some more. +Now we will look for both Python and python words in the string: + +```py +txt = '''Python is the most beautiful language that a human being has ever created. +I recommend python for a first programming language''' + +# It returns list +matches = re.findall('python', txt, re.I) +print(matches) # ['Python', 'python'] + +``` + +Since we are using *re.I* both lowercase and uppercase letters are included. If we do not have the re.I flag, then we will have to write our pattern differently. Let us check it out: + +```py +txt = '''Python is the most beautiful language that a human being has ever created. +I recommend python for a first programming language''' + +matches = re.findall('Python|python', txt) +print(matches) # ['Python', 'python'] + +# +matches = re.findall('[Pp]ython', txt) +print(matches) # ['Python', 'python'] + +``` + +#### Replacing a Substring + +```py +txt = '''Python is the most beautiful language that a human being has ever created. +I recommend python for a first programming language''' + +match_replaced = re.sub('Python|python', 'JavaScript', txt, re.I) +print(match_replaced) # JavaScript is the most beautiful language that a human being has ever created. +# OR +match_replaced = re.sub('[Pp]ython', 'JavaScript', txt, re.I) +print(match_replaced) # JavaScript is the most beautiful language that a human being has ever created. +``` + +Let us add one more example. The following string is really hard to read unless we remove the % symbol. Replacing the % with an empty string will clean the text. + +```py + +txt = '''%I a%m te%%a%%che%r% a%n%d %% I l%o%ve te%ach%ing. +T%he%re i%s n%o%th%ing as r%ewarding a%s e%duc%at%i%ng a%n%d e%m%p%ow%er%ing p%e%o%ple. +I fo%und te%a%ching m%ore i%n%t%er%%es%ting t%h%an any other %jobs. +D%o%es thi%s m%ot%iv%a%te %y%o%u to b%e a t%e%a%cher?''' + +matches = re.sub('%', '', txt) +print(matches) +``` + +```sh +I am teacher and I love teaching. +There is nothing as rewarding as educating and empowering people. +I found teaching more interesting than any other jobs. Does this motivate you to be a teacher? +``` + +## Splitting Text Using RegEx Split + +```py +txt = '''I am teacher and I love teaching. +There is nothing as rewarding as educating and empowering people. +I found teaching more interesting than any other jobs. +Does this motivate you to be a teacher?''' +print(re.split('\n', txt)) # splitting using \n - end of line symbol +``` + +```sh +['I am teacher and I love teaching.', 'There is nothing as rewarding as educating and empowering people.', 'I found teaching more interesting than any other jobs.', 'Does this motivate you to be a teacher?'] +``` + +## Writing RegEx Patterns + +To declare a string variable we use a single or double quote. To declare RegEx variable *r''*. +The following pattern only identifies apple with lowercase, to make it case insensitive either we should rewrite our pattern or we should add a flag. + +```py +import re + +regex_pattern = r'apple' +txt = 'Apple and banana are fruits. An old cliche says an apple a day a doctor way has been replaced by a banana a day keeps the doctor far far away. ' +matches = re.findall(regex_pattern, txt) +print(matches) # ['apple'] + +# To make case insensitive adding flag ' +matches = re.findall(regex_pattern, txt, re.I) +print(matches) # ['Apple', 'apple'] +# or we can use a set of characters method +regex_pattern = r'[Aa]pple' # this mean the first letter could be Apple or apple +matches = re.findall(regex_pattern, txt) +print(matches) # ['Apple', 'apple'] + +``` + +* []: A set of characters + - [a-c] means, a or b or c + - [a-z] means, any letter from a to z + - [A-Z] means, any character from A to Z + - [0-3] means, 0 or 1 or 2 or 3 + - [0-9] means any number from 0 to 9 + - [A-Za-z0-9] any single character, that is a to z, A to Z or 0 to 9 +- \\: uses to escape special characters + - \d means: match where the string contains digits (numbers from 0-9) + - \D means: match where the string does not contain digits +- . : any character except new line character(\n) +- ^: starts with + - r'^substring' eg r'^love', a sentence that starts with a word love + - r'[^abc] means not a, not b, not c. +- $: ends with + - r'substring$' eg r'love$', sentence that ends with a word love +- *: zero or more times + - r'[a]*' means a optional or it can occur many times. +- +: one or more times + - r'[a]+' means at least once (or more) +- ?: zero or one time + - r'[a]?' means zero times or once +- {3}: Exactly 3 characters +- {3,}: At least 3 characters +- {3,8}: 3 to 8 characters +- |: Either or + - r'apple|banana' means either apple or a banana +- (): Capture and group + +![Regular Expression cheat sheet](../images/regex.png) + +Let us use examples to clarify the meta characters above + +### Square Bracket + +Let us use square bracket to include lower and upper case + +```py +regex_pattern = r'[Aa]pple' # this square bracket mean either A or a +txt = 'Apple and banana are fruits. An old cliche says an apple a day a doctor way has been replaced by a banana a day keeps the doctor far far away.' +matches = re.findall(regex_pattern, txt) +print(matches) # ['Apple', 'apple'] +``` + +If we want to look for the banana, we write the pattern as follows: + +```py +regex_pattern = r'[Aa]pple|[Bb]anana' # this square bracket means either A or a +txt = 'Apple and banana are fruits. An old cliche says an apple a day a doctor way has been replaced by a banana a day keeps the doctor far far away.' +matches = re.findall(regex_pattern, txt) +print(matches) # ['Apple', 'banana', 'apple', 'banana'] +``` + +Using the square bracket and or operator , we manage to extract Apple, apple, Banana and banana. + +### Escape character(\\) in RegEx + +```py +regex_pattern = r'\d' # d is a special character which means digits +txt = 'This regular expression example was made on December 6, 2019 and revised on July 8, 2021' +matches = re.findall(regex_pattern, txt) +print(matches) # ['6', '2', '0', '1', '9', '8', '2', '0', '2', '1'], this is not what we want +``` + +### One or more times(+) + +```py +regex_pattern = r'\d+' # d is a special character which means digits, + mean one or more times +txt = 'This regular expression example was made on December 6, 2019 and revised on July 8, 2021' +matches = re.findall(regex_pattern, txt) +print(matches) # ['6', '2019', '8', '2021'] - now, this is better! +``` + +### Period(.) + +```py +regex_pattern = r'[a].' # this square bracket means a and . means any character except new line +txt = '''Apple and banana are fruits''' +matches = re.findall(regex_pattern, txt) +print(matches) # ['an', 'an', 'an', 'a ', 'ar'] + +regex_pattern = r'[a].+' # . any character, + any character one or more times +matches = re.findall(regex_pattern, txt) +print(matches) # ['and banana are fruits'] +``` + +### Zero or more times(\*) + +Zero or many times. The pattern could may not occur or it can occur many times. + +```py +regex_pattern = r'[a].*' # . any character, * any character zero or more times +txt = '''Apple and banana are fruits''' +matches = re.findall(regex_pattern, txt) +print(matches) # ['and banana are fruits'] +``` + +### Zero or one time(?) + +Zero or one time. The pattern may not occur or it may occur once. + +```py +txt = '''I am not sure if there is a convention how to write the word e-mail. +Some people write it as email others may write it as Email or E-mail.''' +regex_pattern = r'[Ee]-?mail' # ? means here that '-' is optional +matches = re.findall(regex_pattern, txt) +print(matches) # ['e-mail', 'email', 'Email', 'E-mail'] +``` + +### Quantifier in RegEx + +We can specify the length of the substring we are looking for in a text, using a curly bracket. Let us imagine, we are interested in a substring with a length of 4 characters: + +```py +txt = 'This regular expression example was made on December 6, 2019 and revised on July 8, 2021' +regex_pattern = r'\d{4}' # exactly four times +matches = re.findall(regex_pattern, txt) +print(matches) # ['2019', '2021'] + +txt = 'This regular expression example was made on December 6, 2019 and revised on July 8, 2021' +regex_pattern = r'\d{1, 4}' # 1 to 4 +matches = re.findall(regex_pattern, txt) +print(matches) # ['6', '2019', '8', '2021'] +``` + +### Cart ^ + +- Starts with + +```py +txt = 'This regular expression example was made on December 6, 2019 and revised on July 8, 2021' +regex_pattern = r'^This' # ^ means starts with +matches = re.findall(regex_pattern, txt) +print(matches) # ['This'] +``` + +- Negation + +```py +txt = 'This regular expression example was made on December 6, 2019 and revised on July 8, 2021' +regex_pattern = r'[^A-Za-z ]+' # ^ in set character means negation, not A to Z, not a to z, no space +matches = re.findall(regex_pattern, txt) +print(matches) # ['6,', '2019', '8', '2021'] +``` + +## 💻 Exercises: Day 18 + +### Exercises: Level 1 + + 1. What is the most frequent word in the following paragraph? + +```py + paragraph = 'I love teaching. If you do not love teaching what else can you love. I love Python if you do not love something which can give you all the capabilities to develop an application what else can you love. +``` + +```sh + [ + (6, 'love'), + (5, 'you'), + (3, 'can'), + (2, 'what'), + (2, 'teaching'), + (2, 'not'), + (2, 'else'), + (2, 'do'), + (2, 'I'), + (1, 'which'), + (1, 'to'), + (1, 'the'), + (1, 'something'), + (1, 'if'), + (1, 'give'), + (1, 'develop'), + (1, 'capabilities'), + (1, 'application'), + (1, 'an'), + (1, 'all'), + (1, 'Python'), + (1, 'If') + ] +``` + +2. The position of some particles on the horizontal x-axis are -12, -4, -3 and -1 in the negative direction, 0 at origin, 4 and 8 in the positive direction. Extract these numbers from this whole text and find the distance between the two furthest particles. + +```py +points = ['-12', '-4', '-3', '-1', '0', '4', '8'] +sorted_points = [-12, -4, -3, -1, -1, 0, 2, 4, 8] +distance = 8 -(-12) # 20 +``` + +### Exercises: Level 2 + +1. Write a pattern which identifies if a string is a valid python variable + + ```sh + is_valid_variable('first_name') # True + is_valid_variable('first-name') # False + is_valid_variable('1first_name') # False + is_valid_variable('firstname') # True + ``` + +### Exercises: Level 3 + +1. Clean the following text. After cleaning, count three most frequent words in the string. + + ```py + sentence = '''%I $am@% a %tea@cher%, &and& I lo%#ve %tea@ching%;. There $is nothing; &as& mo@re rewarding as educa@ting &and& @emp%o@wering peo@ple. ;I found tea@ching m%o@re interesting tha@n any other %jo@bs. %Do@es thi%s mo@tivate yo@u to be a tea@cher!?''' + + print(clean_text(sentence)); + I am a teacher and I love teaching There is nothing as more rewarding as educating and empowering people I found teaching more interesting than any other jobs Does this motivate you to be a teacher + print(most_frequent_words(cleaned_text)) # [(3, 'I'), (2, 'teaching'), (2, 'teacher')] + ``` + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 17](../17_Day_Exception_handling/17_exception_handling.md) | [Day 19>>](../19_Day_File_handling/19_file_handling.md) diff --git a/18_regular_expressions/index.html b/18_regular_expressions/index.html new file mode 100644 index 0000000..aae1507 --- /dev/null +++ b/18_regular_expressions/index.html @@ -0,0 +1,1930 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 18 regular expressions - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+

<< Day 17 | Day 19>>

+

30DaysOfPython

+ +

📘 Day 18⚓︎

+

Regular Expressions⚓︎

+

A regular expression or RegEx is a special text string that helps to find patterns in data. A RegEx can be used to check if some pattern exists in a different data type. To use RegEx in python first we should import the RegEx module which is called re.

+

The re Module⚓︎

+

After importing the module we can use it to detect or find patterns.

+
import re
+
+

Methods in re Module⚓︎

+

To find a pattern we use different set of re character sets that allows to search for a match in a string.

+
    +
  • re.match(): searches only in the beginning of the first line of the string and returns matched objects if found, else returns None.
  • +
  • re.search: Returns a match object if there is one anywhere in the string, including multiline strings.
  • +
  • re.findall: Returns a list containing all matches
  • +
  • re.split: Takes a string, splits it at the match points, returns a list
  • +
  • re.sub: Replaces one or many matches within a string
  • +
+

Match⚓︎

+
# syntac
+re.match(substring, string, re.I)
+# substring is a string or a pattern, string is the text we look for a pattern , re.I is case ignore
+
+
import re
+
+txt = 'I love to teach python and javaScript'
+# It returns an object with span, and match
+match = re.match('I love to teach', txt, re.I)
+print(match)  # <re.Match object; span=(0, 15), match='I love to teach'>
+# We can get the starting and ending position of the match as tuple using span
+span = match.span()
+print(span)     # (0, 15)
+# Lets find the start and stop position from the span
+start, end = span
+print(start, end)  # 0, 15
+substring = txt[start:end]
+print(substring)       # I love to teach
+
+

As you can see from the example above, the pattern we are looking for (or the substring we are looking for) is I love to teach. The match function returns an object only if the text starts with the pattern.

+
import re
+
+txt = 'I love to teach python and javaScript'
+match = re.match('I like to teach', txt, re.I)
+print(match)  # None
+
+

The string does not string with I like to teach, therefore there was no match and the match method returned None.

+ +
# syntax
+re.match(substring, string, re.I)
+# substring is a pattern, string is the text we look for a pattern , re.I is case ignore flag
+
+
import re
+
+txt = '''Python is the most beautiful language that a human being has ever created.
+I recommend python for a first programming language'''
+
+# It returns an object with span and match
+match = re.search('first', txt, re.I)
+print(match)  # <re.Match object; span=(100, 105), match='first'>
+# We can get the starting and ending position of the match as tuple using span
+span = match.span()
+print(span)     # (100, 105)
+# Lets find the start and stop position from the span
+start, end = span
+print(start, end)  # 100 105
+substring = txt[start:end]
+print(substring)       # first
+
+

As you can see, search is much better than match because it can look for the pattern throughout the text. Search returns a match object with a first match that was found, otherwise it returns None. A much better re function is findall. This function checks for the pattern through the whole string and returns all the matches as a list.

+

Searching for All Matches Using findall⚓︎

+

findall() returns all the matches as a list

+
txt = '''Python is the most beautiful language that a human being has ever created.
+I recommend python for a first programming language'''
+
+# It return a list
+matches = re.findall('language', txt, re.I)
+print(matches)  # ['language', 'language']
+
+

As you can see, the word language was found two times in the string. Let us practice some more. +Now we will look for both Python and python words in the string:

+
txt = '''Python is the most beautiful language that a human being has ever created.
+I recommend python for a first programming language'''
+
+# It returns list
+matches = re.findall('python', txt, re.I)
+print(matches)  # ['Python', 'python']
+
+

Since we are using re.I both lowercase and uppercase letters are included. If we do not have the re.I flag, then we will have to write our pattern differently. Let us check it out:

+
txt = '''Python is the most beautiful language that a human being has ever created.
+I recommend python for a first programming language'''
+
+matches = re.findall('Python|python', txt)
+print(matches)  # ['Python', 'python']
+
+#
+matches = re.findall('[Pp]ython', txt)
+print(matches)  # ['Python', 'python']
+
+

Replacing a Substring⚓︎

+
txt = '''Python is the most beautiful language that a human being has ever created.
+I recommend python for a first programming language'''
+
+match_replaced = re.sub('Python|python', 'JavaScript', txt, re.I)
+print(match_replaced)  # JavaScript is the most beautiful language that a human being has ever created.
+# OR
+match_replaced = re.sub('[Pp]ython', 'JavaScript', txt, re.I)
+print(match_replaced)  # JavaScript is the most beautiful language that a human being has ever created.
+
+

Let us add one more example. The following string is really hard to read unless we remove the % symbol. Replacing the % with an empty string will clean the text.

+
txt = '''%I a%m te%%a%%che%r% a%n%d %% I l%o%ve te%ach%ing. 
+T%he%re i%s n%o%th%ing as r%ewarding a%s e%duc%at%i%ng a%n%d e%m%p%ow%er%ing p%e%o%ple.
+I fo%und te%a%ching m%ore i%n%t%er%%es%ting t%h%an any other %jobs. 
+D%o%es thi%s m%ot%iv%a%te %y%o%u to b%e a t%e%a%cher?'''
+
+matches = re.sub('%', '', txt)
+print(matches)
+
+
I am teacher and I love teaching.
+There is nothing as rewarding as educating and empowering people. 
+I found teaching more interesting than any other jobs. Does this motivate you to be a teacher?
+
+

Splitting Text Using RegEx Split⚓︎

+
txt = '''I am teacher and  I love teaching.
+There is nothing as rewarding as educating and empowering people.
+I found teaching more interesting than any other jobs.
+Does this motivate you to be a teacher?'''
+print(re.split('\n', txt)) # splitting using \n - end of line symbol
+
+
['I am teacher and  I love teaching.', 'There is nothing as rewarding as educating and empowering people.', 'I found teaching more interesting than any other jobs.', 'Does this motivate you to be a teacher?']
+
+

Writing RegEx Patterns⚓︎

+

To declare a string variable we use a single or double quote. To declare RegEx variable r''. +The following pattern only identifies apple with lowercase, to make it case insensitive either we should rewrite our pattern or we should add a flag.

+
import re
+
+regex_pattern = r'apple'
+txt = 'Apple and banana are fruits. An old cliche says an apple a day a doctor way has been replaced by a banana a day keeps the doctor far far away. '
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['apple']
+
+# To make case insensitive adding flag '
+matches = re.findall(regex_pattern, txt, re.I)
+print(matches)  # ['Apple', 'apple']
+# or we can use a set of characters method
+regex_pattern = r'[Aa]pple'  # this mean the first letter could be Apple or apple
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['Apple', 'apple']
+
+
    +
  • []: A set of characters
  • +
  • [a-c] means, a or b or c
  • +
  • [a-z] means, any letter from a to z
  • +
  • [A-Z] means, any character from A to Z
  • +
  • [0-3] means, 0 or 1 or 2 or 3
  • +
  • [0-9] means any number from 0 to 9
  • +
  • [A-Za-z0-9] any single character, that is a to z, A to Z or 0 to 9
  • +
  • \: uses to escape special characters
  • +
  • \d means: match where the string contains digits (numbers from 0-9)
  • +
  • \D means: match where the string does not contain digits
  • +
  • . : any character except new line character(\n)
  • +
  • ^: starts with
  • +
  • r'^substring' eg r'^love', a sentence that starts with a word love
  • +
  • r'[^abc] means not a, not b, not c.
  • +
  • $: ends with
  • +
  • r'substring\(' eg r'love\)', sentence that ends with a word love
  • +
  • *: zero or more times
  • +
  • r'[a]*' means a optional or it can occur many times.
  • +
  • +: one or more times
  • +
  • r'[a]+' means at least once (or more)
  • +
  • ?: zero or one time
  • +
  • r'[a]?' means zero times or once
  • +
  • {3}: Exactly 3 characters
  • +
  • {3,}: At least 3 characters
  • +
  • {3,8}: 3 to 8 characters
  • +
  • |: Either or
  • +
  • r'apple|banana' means either apple or a banana
  • +
  • (): Capture and group
  • +
+

Regular Expression cheat sheet

+

Let us use examples to clarify the meta characters above

+

Square Bracket⚓︎

+

Let us use square bracket to include lower and upper case

+
regex_pattern = r'[Aa]pple' # this square bracket mean either A or a
+txt = 'Apple and banana are fruits. An old cliche says an apple a day a doctor way has been replaced by a banana a day keeps the doctor far far away.'
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['Apple', 'apple']
+
+

If we want to look for the banana, we write the pattern as follows:

+
regex_pattern = r'[Aa]pple|[Bb]anana' # this square bracket means either A or a
+txt = 'Apple and banana are fruits. An old cliche says an apple a day a doctor way has been replaced by a banana a day keeps the doctor far far away.'
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['Apple', 'banana', 'apple', 'banana']
+
+

Using the square bracket and or operator , we manage to extract Apple, apple, Banana and banana.

+

Escape character(\) in RegEx⚓︎

+
regex_pattern = r'\d'  # d is a special character which means digits
+txt = 'This regular expression example was made on December 6,  2019 and revised on July 8, 2021'
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['6', '2', '0', '1', '9', '8', '2', '0', '2', '1'], this is not what we want
+
+

One or more times(+)⚓︎

+
regex_pattern = r'\d+'  # d is a special character which means digits, + mean one or more times
+txt = 'This regular expression example was made on December 6,  2019 and revised on July 8, 2021'
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['6', '2019', '8', '2021'] - now, this is better!
+
+

Period(.)⚓︎

+
regex_pattern = r'[a].'  # this square bracket means a and . means any character except new line
+txt = '''Apple and banana are fruits'''
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['an', 'an', 'an', 'a ', 'ar']
+
+regex_pattern = r'[a].+'  # . any character, + any character one or more times 
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['and banana are fruits']
+
+

Zero or more times(*)⚓︎

+

Zero or many times. The pattern could may not occur or it can occur many times.

+
regex_pattern = r'[a].*'  # . any character, * any character zero or more times 
+txt = '''Apple and banana are fruits'''
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['and banana are fruits']
+
+

Zero or one time(?)⚓︎

+

Zero or one time. The pattern may not occur or it may occur once.

+
txt = '''I am not sure if there is a convention how to write the word e-mail.
+Some people write it as email others may write it as Email or E-mail.'''
+regex_pattern = r'[Ee]-?mail'  # ? means here that '-' is optional
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['e-mail', 'email', 'Email', 'E-mail']
+
+

Quantifier in RegEx⚓︎

+

We can specify the length of the substring we are looking for in a text, using a curly bracket. Let us imagine, we are interested in a substring with a length of 4 characters:

+
txt = 'This regular expression example was made on December 6,  2019 and revised on July 8, 2021'
+regex_pattern = r'\d{4}'  # exactly four times
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['2019', '2021']
+
+txt = 'This regular expression example was made on December 6,  2019 and revised on July 8, 2021'
+regex_pattern = r'\d{1, 4}'   # 1 to 4
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['6', '2019', '8', '2021']
+
+

Cart ^⚓︎

+
    +
  • Starts with
  • +
+
txt = 'This regular expression example was made on December 6,  2019 and revised on July 8, 2021'
+regex_pattern = r'^This'  # ^ means starts with
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['This']
+
+
    +
  • Negation
  • +
+
txt = 'This regular expression example was made on December 6,  2019 and revised on July 8, 2021'
+regex_pattern = r'[^A-Za-z ]+'  # ^ in set character means negation, not A to Z, not a to z, no space
+matches = re.findall(regex_pattern, txt)
+print(matches)  # ['6,', '2019', '8', '2021']
+
+

💻 Exercises: Day 18⚓︎

+

Exercises: Level 1⚓︎

+
    +
  1. What is the most frequent word in the following paragraph?
  2. +
+
    paragraph = 'I love teaching. If you do not love teaching what else can you love. I love Python if you do not love something which can give you all the capabilities to develop an application what else can you love.
+
+
    [
+    (6, 'love'),
+    (5, 'you'),
+    (3, 'can'),
+    (2, 'what'),
+    (2, 'teaching'),
+    (2, 'not'),
+    (2, 'else'),
+    (2, 'do'),
+    (2, 'I'),
+    (1, 'which'),
+    (1, 'to'),
+    (1, 'the'),
+    (1, 'something'),
+    (1, 'if'),
+    (1, 'give'),
+    (1, 'develop'),
+    (1, 'capabilities'),
+    (1, 'application'),
+    (1, 'an'),
+    (1, 'all'),
+    (1, 'Python'),
+    (1, 'If')
+    ]
+
+
    +
  1. The position of some particles on the horizontal x-axis are -12, -4, -3 and -1 in the negative direction, 0 at origin, 4 and 8 in the positive direction. Extract these numbers from this whole text and find the distance between the two furthest particles.
  2. +
+
points = ['-12', '-4', '-3', '-1', '0', '4', '8']
+sorted_points =  [-12, -4, -3, -1, -1, 0, 2, 4, 8]
+distance = 8 -(-12) # 20
+
+

Exercises: Level 2⚓︎

+
    +
  1. +

    Write a pattern which identifies if a string is a valid python variable

    +
    is_valid_variable('first_name') # True
    +is_valid_variable('first-name') # False
    +is_valid_variable('1first_name') # False
    +is_valid_variable('firstname') # True
    +
    +
  2. +
+

Exercises: Level 3⚓︎

+
    +
  1. +

    Clean the following text. After cleaning, count three most frequent words in the string.

    +
    sentence = '''%I $am@% a %tea@cher%, &and& I lo%#ve %tea@ching%;. There $is nothing; &as& mo@re rewarding as educa@ting &and& @emp%o@wering peo@ple. ;I found tea@ching m%o@re interesting tha@n any other %jo@bs. %Do@es thi%s mo@tivate yo@u to be a tea@cher!?'''
    +
    +print(clean_text(sentence));
    +I am a teacher and I love teaching There is nothing as more rewarding as educating and empowering people I found teaching more interesting than any other jobs Does this motivate you to be a teacher
    +print(most_frequent_words(cleaned_text)) # [(3, 'I'), (2, 'teaching'), (2, 'teacher')]
    +
    +
  2. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 17 | Day 19>>

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/19_file_handling/19_file_handling.md b/19_file_handling/19_file_handling.md new file mode 100644 index 0000000..de51b9b --- /dev/null +++ b/19_file_handling/19_file_handling.md @@ -0,0 +1,517 @@ +
+

30 Days Of Python: Day 19 - File Handling

+ + + + + Twitter Follow + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+
+ +[<< Day 18](../18_Day_Regular_expressions/18_regular_expressions.md) | [Day 20 >>](../20_Day_Python_package_manager/20_python_package_manager.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 19](#-day-19) + - [File Handling](#file-handling) + - [Opening Files for Reading](#opening-files-for-reading) + - [Opening Files for Writing and Updating](#opening-files-for-writing-and-updating) + - [Deleting Files](#deleting-files) + - [File Types](#file-types) + - [File with txt Extension](#file-with-txt-extension) + - [File with json Extension](#file-with-json-extension) + - [Changing JSON to Dictionary](#changing-json-to-dictionary) + - [Changing Dictionary to JSON](#changing-dictionary-to-json) + - [Saving as JSON File](#saving-as-json-file) + - [File with csv Extension](#file-with-csv-extension) + - [File with xlsx Extension](#file-with-xlsx-extension) + - [File with xml Extension](#file-with-xml-extension) + - [💻 Exercises: Day 19](#-exercises-day-19) + - [Exercises: Level 1](#exercises-level-1) + - [Exercises: Level 2](#exercises-level-2) + - [Exercises: Level 3](#exercises-level-3) + +# 📘 Day 19 + +## File Handling + +So far we have seen different Python data types. We usually store our data in different file formats. In addition to handling files, we will also see different file formats(.txt, .json, .xml, .csv, .tsv, .excel) in this section. First, let us get familiar with handling files with common file format(.txt). + +File handling is an import part of programming which allows us to create, read, update and delete files. In Python to handle data we use _open()_ built-in function. + +```py +# Syntax +open('filename', mode) # mode(r, a, w, x, t,b) could be to read, write, update +``` + +- "r" - Read - Default value. Opens a file for reading, it returns an error if the file does not exist +- "a" - Append - Opens a file for appending, creates the file if it does not exist +- "w" - Write - Opens a file for writing, creates the file if it does not exist +- "x" - Create - Creates the specified file, returns an error if the file exists +- "t" - Text - Default value. Text mode +- "b" - Binary - Binary mode (e.g. images) + +### Opening Files for Reading + +The default mode of _open_ is reading, so we do not have to specify 'r' or 'rt'. I have created and saved a file named reading_file_example.txt in the files directory. Let us see how it is done: + +```py +f = open('./files/reading_file_example.txt') +print(f) # <_io.TextIOWrapper name='./files/reading_file_example.txt' mode='r' encoding='UTF-8'> +``` + +As you can see in the example above, I printed the opened file and it gave some information about it. Opened file has different reading methods: _read()_, _readline_, _readlines_. An opened file has to be closed with _close()_ method. + +- _read()_: read the whole text as string. If we want to limit the number of characters we want to read, we can limit it by passing int value to the *read(number)* method. + +```py +f = open('./files/reading_file_example.txt') +txt = f.read() +print(type(txt)) +print(txt) +f.close() +``` + +```sh +# output + +This is an example to show how to open a file and read. +This is the second line of the text. +``` + +Instead of printing all the text, let us print the first 10 characters of the text file. + +```py +f = open('./files/reading_file_example.txt') +txt = f.read(10) +print(type(txt)) +print(txt) +f.close() +``` + +```sh +# output + +This is an +``` + +- _readline()_: read only the first line + +```py +f = open('./files/reading_file_example.txt') +line = f.readline() +print(type(line)) +print(line) +f.close() +``` + +```sh +# output + +This is an example to show how to open a file and read. +``` + +- _readlines()_: read all the text line by line and returns a list of lines + +```py +f = open('./files/reading_file_example.txt') +lines = f.readlines() +print(type(lines)) +print(lines) +f.close() +``` + +```sh +# output + +['This is an example to show how to open a file and read.\n', 'This is the second line of the text.'] +``` + +Another way to get all the lines as a list is using _splitlines()_: + +```py +f = open('./files/reading_file_example.txt') +lines = f.read().splitlines() +print(type(lines)) +print(lines) +f.close() +``` + +```sh +# output + +['This is an example to show how to open a file and read.', 'This is the second line of the text.'] +``` + +After we open a file, we should close it. There is a high tendency of forgetting to close them. There is a new way of opening files using _with_ - closes the files by itself. Let us rewrite the the previous example with the _with_ method: + +```py +with open('./files/reading_file_example.txt') as f: + lines = f.read().splitlines() + print(type(lines)) + print(lines) +``` + +```sh +# output + +['This is an example to show how to open a file and read.', 'This is the second line of the text.'] +``` + +### Opening Files for Writing and Updating + +To write to an existing file, we must add a mode as parameter to the _open()_ function: + +- "a" - append - will append to the end of the file, if the file does not it creates a new file. +- "w" - write - will overwrite any existing content, if the file does not exist it creates. + +Let us append some text to the file we have been reading: + +```py +with open('./files/reading_file_example.txt','a') as f: + f.write('This text has to be appended at the end') +``` + +The method below creates a new file, if the file does not exist: + +```py +with open('./files/writing_file_example.txt','w') as f: + f.write('This text will be written in a newly created file') +``` + +### Deleting Files + +We have seen in previous section, how to make and remove a directory using _os_ module. Again now, if we want to remove a file we use _os_ module. + +```py +import os +os.remove('./files/example.txt') + +``` + +If the file does not exist, the remove method will raise an error, so it is good to use a condition like this: + +```py +import os +if os.path.exists('./files/example.txt'): + os.remove('./files/example.txt') +else: + print('The file does not exist') +``` + +## File Types + +### File with txt Extension + +File with _txt_ extension is a very common form of data and we have covered it in the previous section. Let us move to the JSON file + +### File with json Extension + +JSON stands for JavaScript Object Notation. Actually, it is a stringified JavaScript object or Python dictionary. + +_Example:_ + +```py +# dictionary +person_dct= { + "name":"Asabeneh", + "country":"Finland", + "city":"Helsinki", + "skills":["JavaScrip", "React","Python"] +} +# JSON: A string form a dictionary +person_json = "{'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'skills': ['JavaScrip', 'React', 'Python']}" + +# we use three quotes and make it multiple line to make it more readable +person_json = '''{ + "name":"Asabeneh", + "country":"Finland", + "city":"Helsinki", + "skills":["JavaScrip", "React","Python"] +}''' +``` + +### Changing JSON to Dictionary + +To change a JSON to a dictionary, first we import the json module and then we use _loads_ method. + +```py +import json +# JSON +person_json = '''{ + "name": "Asabeneh", + "country": "Finland", + "city": "Helsinki", + "skills": ["JavaScrip", "React", "Python"] +}''' +# let's change JSON to dictionary +person_dct = json.loads(person_json) +print(type(person_dct)) +print(person_dct) +print(person_dct['name']) +``` + +```sh +# output + +{'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'skills': ['JavaScrip', 'React', 'Python']} +Asabeneh +``` + +### Changing Dictionary to JSON + +To change a dictionary to a JSON we use _dumps_ method from the json module. + +```py +import json +# python dictionary +person = { + "name": "Asabeneh", + "country": "Finland", + "city": "Helsinki", + "skills": ["JavaScrip", "React", "Python"] +} +# let's convert it to json +person_json = json.dumps(person, indent=4) # indent could be 2, 4, 8. It beautifies the json +print(type(person_json)) +print(person_json) +``` + +```sh +# output +# when you print it, it does not have the quote, but actually it is a string +# JSON does not have type, it is a string type. + +{ + "name": "Asabeneh", + "country": "Finland", + "city": "Helsinki", + "skills": [ + "JavaScrip", + "React", + "Python" + ] +} +``` + +### Saving as JSON File + +We can also save our data as a json file. Let us save it as a json file using the following steps. For writing a json file, we use the json.dump() method, it can take dictionary, output file, ensure_ascii and indent. + +```py +import json +# python dictionary +person = { + "name": "Asabeneh", + "country": "Finland", + "city": "Helsinki", + "skills": ["JavaScrip", "React", "Python"] +} +with open('./files/json_example.json', 'w', encoding='utf-8') as f: + json.dump(person, f, ensure_ascii=False, indent=4) +``` + +In the code above, we use encoding and indentation. Indentation makes the json file easy to read. + +### File with csv Extension + +CSV stands for comma separated values. CSV is a simple file format used to store tabular data, such as a spreadsheet or database. CSV is a very common data format in data science. + +**Example:** + +```csv +"name","country","city","skills" +"Asabeneh","Finland","Helsinki","JavaScript" +``` + +**Example:** + +```py +import csv +with open('./files/csv_example.csv') as f: + csv_reader = csv.reader(f, delimiter=',') # w use, reader method to read csv + line_count = 0 + for row in csv_reader: + if line_count == 0: + print(f'Column names are :{", ".join(row)}') + line_count += 1 + else: + print( + f'\t{row[0]} is a teachers. He lives in {row[1]}, {row[2]}.') + line_count += 1 + print(f'Number of lines: {line_count}') +``` + +```sh +# output: +Column names are :name, country, city, skills + Asabeneh is a teacher. He lives in Finland, Helsinki. +Number of lines: 2 +``` + +### File with xlsx Extension + +To read excel files we need to install _xlrd_ package. We will cover this after we cover package installing using pip. + +```py +import xlrd +excel_book = xlrd.open_workbook('sample.xls) +print(excel_book.nsheets) +print(excel_book.sheet_names) +``` + +### File with xml Extension + +XML is another structured data format which looks like HTML. In XML the tags are not predefined. The first line is an XML declaration. The person tag is the root of the XML. The person has a gender attribute. +**Example:XML** + +```xml + + + Asabeneh + Finland + Helsinki + + JavaScrip + React + Python + + +``` + +For more information on how to read an XML file check the [documentation](https://docs.python.org/2/library/xml.etree.elementtree.html) + +```py +import xml.etree.ElementTree as ET +tree = ET.parse('./files/xml_example.xml') +root = tree.getroot() +print('Root tag:', root.tag) +print('Attribute:', root.attrib) +for child in root: + print('field: ', child.tag) +``` + +```sh +# output +Root tag: person +Attribute: {'gender': 'male'} +field: name +field: country +field: city +field: skills +``` + +🌕 You are making a big progress. Maintain your momentum, keep the good work. Now do some exercises for your brain and muscles. + +## 💻 Exercises: Day 19 + +### Exercises: Level 1 + +1. Write a function which count number of lines and number of words in a text. All the files are in the data the folder: + a) Read obama_speech.txt file and count number of lines and words + b) Read michelle_obama_speech.txt file and count number of lines and words + c) Read donald_speech.txt file and count number of lines and words + d) Read melina_trump_speech.txt file and count number of lines and words +2. Read the countries_data.json data file in data directory, create a function that finds the ten most spoken languages + + ```py + # Your output should look like this + print(most_spoken_languages(filename='./data/countries_data.json', 10)) + [(91, 'English'), + (45, 'French'), + (25, 'Arabic'), + (24, 'Spanish'), + (9, 'Russian'), + (9, 'Portuguese'), + (8, 'Dutch'), + (7, 'German'), + (5, 'Chinese'), + (4, 'Swahili'), + (4, 'Serbian')] + + # Your output should look like this + print(most_spoken_languages(filename='./data/countries_data.json', 3)) + [(91, 'English'), + (45, 'French'), + (25, 'Arabic')] + ``` + +3. Read the countries_data.json data file in data directory, create a function that creates a list of the ten most populated countries + + ```py + # Your output should look like this + print(most_populated_countries(filename='./data/countries_data.json', 10)) + + [ + {'country': 'China', 'population': 1377422166}, + {'country': 'India', 'population': 1295210000}, + {'country': 'United States of America', 'population': 323947000}, + {'country': 'Indonesia', 'population': 258705000}, + {'country': 'Brazil', 'population': 206135893}, + {'country': 'Pakistan', 'population': 194125062}, + {'country': 'Nigeria', 'population': 186988000}, + {'country': 'Bangladesh', 'population': 161006790}, + {'country': 'Russian Federation', 'population': 146599183}, + {'country': 'Japan', 'population': 126960000} + ] + + # Your output should look like this + + print(most_populated_countries(filename='./data/countries_data.json', 3)) + [ + {'country': 'China', 'population': 1377422166}, + {'country': 'India', 'population': 1295210000}, + {'country': 'United States of America', 'population': 323947000} + ] + ``` + +### Exercises: Level 2 + +4. Extract all incoming email addresses as a list from the email_exchange_big.txt file. +5. Find the most common words in the English language. Call the name of your function find_most_common_words, it will take two parameters - a string or a file and a positive integer, indicating the number of words. Your function will return an array of tuples in descending order. Check the output + +```py + # Your output should look like this + print(find_most_common_words('sample.txt', 10)) + [(10, 'the'), + (8, 'be'), + (6, 'to'), + (6, 'of'), + (5, 'and'), + (4, 'a'), + (4, 'in'), + (3, 'that'), + (2, 'have'), + (2, 'I')] + + # Your output should look like this + print(find_most_common_words('sample.txt', 5)) + + [(10, 'the'), + (8, 'be'), + (6, 'to'), + (6, 'of'), + (5, 'and')] +``` + +6. Use the function, find_most_frequent_words to find: + a) The ten most frequent words used in [Obama's speech](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/obama_speech.txt) + b) The ten most frequent words used in [Michelle's speech](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/michelle_obama_speech.txt) + c) The ten most frequent words used in [Trump's speech](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/donald_speech.txt) + d) The ten most frequent words used in [Melina's speech](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/melina_trump_speech.txt) +7. Write a python application that checks similarity between two texts. It takes a file or a string as a parameter and it will evaluate the similarity of the two texts. For instance check the similarity between the transcripts of [Michelle's](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/michelle_obama_speech.txt) and [Melina's](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/melina_trump_speech.txt) speech. You may need a couple of functions, function to clean the text(clean_text), function to remove support words(remove_support_words) and finally to check the similarity(check_text_similarity). List of [stop words](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/stop_words.py) are in the data directory +8. Find the 10 most repeated words in the romeo_and_juliet.txt +9. Read the [hacker news csv](https://github.com/Asabeneh/30-Days-Of-Python/blob/master/data/hacker_news.csv) file and find out: + a) Count the number of lines containing python or Python + b) Count the number lines containing JavaScript, javascript or Javascript + c) Count the number lines containing Java and not JavaScript + +### Exercises: Level 3 + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 18](../18_Day_Regular_expressions/18_regular_expressions.md) | [Day 20 >>](../20_Day_Python_package_manager/20_python_package_manager.md) diff --git a/19_file_handling/index.html b/19_file_handling/index.html new file mode 100644 index 0000000..5ba7ffc --- /dev/null +++ b/19_file_handling/index.html @@ -0,0 +1,1894 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 19 file handling - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 19 - File Handling

+ + + + + Twitter Follow + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+
+ +

<< Day 18 | Day 20 >>

+

30DaysOfPython

+ +

📘 Day 19⚓︎

+

File Handling⚓︎

+

So far we have seen different Python data types. We usually store our data in different file formats. In addition to handling files, we will also see different file formats(.txt, .json, .xml, .csv, .tsv, .excel) in this section. First, let us get familiar with handling files with common file format(.txt).

+

File handling is an import part of programming which allows us to create, read, update and delete files. In Python to handle data we use open() built-in function.

+
# Syntax
+open('filename', mode) # mode(r, a, w, x, t,b)  could be to read, write, update
+
+
    +
  • "r" - Read - Default value. Opens a file for reading, it returns an error if the file does not exist
  • +
  • "a" - Append - Opens a file for appending, creates the file if it does not exist
  • +
  • "w" - Write - Opens a file for writing, creates the file if it does not exist
  • +
  • "x" - Create - Creates the specified file, returns an error if the file exists
  • +
  • "t" - Text - Default value. Text mode
  • +
  • "b" - Binary - Binary mode (e.g. images)
  • +
+

Opening Files for Reading⚓︎

+

The default mode of open is reading, so we do not have to specify 'r' or 'rt'. I have created and saved a file named reading_file_example.txt in the files directory. Let us see how it is done:

+
f = open('./files/reading_file_example.txt')
+print(f) # <_io.TextIOWrapper name='./files/reading_file_example.txt' mode='r' encoding='UTF-8'>
+
+

As you can see in the example above, I printed the opened file and it gave some information about it. Opened file has different reading methods: read(), readline, readlines. An opened file has to be closed with close() method.

+
    +
  • read(): read the whole text as string. If we want to limit the number of characters we want to read, we can limit it by passing int value to the read(number) method.
  • +
+
f = open('./files/reading_file_example.txt')
+txt = f.read()
+print(type(txt))
+print(txt)
+f.close()
+
+
# output
+<class 'str'>
+This is an example to show how to open a file and read.
+This is the second line of the text.
+
+

Instead of printing all the text, let us print the first 10 characters of the text file.

+
f = open('./files/reading_file_example.txt')
+txt = f.read(10)
+print(type(txt))
+print(txt)
+f.close()
+
+
# output
+<class 'str'>
+This is an
+
+
    +
  • readline(): read only the first line
  • +
+
f = open('./files/reading_file_example.txt')
+line = f.readline()
+print(type(line))
+print(line)
+f.close()
+
+
# output
+<class 'str'>
+This is an example to show how to open a file and read.
+
+
    +
  • readlines(): read all the text line by line and returns a list of lines
  • +
+
f = open('./files/reading_file_example.txt')
+lines = f.readlines()
+print(type(lines))
+print(lines)
+f.close()
+
+
# output
+<class 'list'>
+['This is an example to show how to open a file and read.\n', 'This is the second line of the text.']
+
+

Another way to get all the lines as a list is using splitlines():

+
f = open('./files/reading_file_example.txt')
+lines = f.read().splitlines()
+print(type(lines))
+print(lines)
+f.close()
+
+
# output
+<class 'list'>
+['This is an example to show how to open a file and read.', 'This is the second line of the text.']
+
+

After we open a file, we should close it. There is a high tendency of forgetting to close them. There is a new way of opening files using with - closes the files by itself. Let us rewrite the the previous example with the with method:

+
with open('./files/reading_file_example.txt') as f:
+    lines = f.read().splitlines()
+    print(type(lines))
+    print(lines)
+
+
# output
+<class 'list'>
+['This is an example to show how to open a file and read.', 'This is the second line of the text.']
+
+

Opening Files for Writing and Updating⚓︎

+

To write to an existing file, we must add a mode as parameter to the open() function:

+
    +
  • "a" - append - will append to the end of the file, if the file does not it creates a new file.
  • +
  • "w" - write - will overwrite any existing content, if the file does not exist it creates.
  • +
+

Let us append some text to the file we have been reading:

+
with open('./files/reading_file_example.txt','a') as f:
+    f.write('This text has to be appended at the end')
+
+

The method below creates a new file, if the file does not exist:

+
with open('./files/writing_file_example.txt','w') as f:
+    f.write('This text will be written in a newly created file')
+
+

Deleting Files⚓︎

+

We have seen in previous section, how to make and remove a directory using os module. Again now, if we want to remove a file we use os module.

+
import os
+os.remove('./files/example.txt')
+
+

If the file does not exist, the remove method will raise an error, so it is good to use a condition like this:

+
import os
+if os.path.exists('./files/example.txt'):
+    os.remove('./files/example.txt')
+else:
+    print('The file does not exist')
+
+

File Types⚓︎

+

File with txt Extension⚓︎

+

File with txt extension is a very common form of data and we have covered it in the previous section. Let us move to the JSON file

+

File with json Extension⚓︎

+

JSON stands for JavaScript Object Notation. Actually, it is a stringified JavaScript object or Python dictionary.

+

Example:

+
# dictionary
+person_dct= {
+    "name":"Asabeneh",
+    "country":"Finland",
+    "city":"Helsinki",
+    "skills":["JavaScrip", "React","Python"]
+}
+# JSON: A string form a dictionary
+person_json = "{'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'skills': ['JavaScrip', 'React', 'Python']}"
+
+# we use three quotes and make it multiple line to make it more readable
+person_json = '''{
+    "name":"Asabeneh",
+    "country":"Finland",
+    "city":"Helsinki",
+    "skills":["JavaScrip", "React","Python"]
+}'''
+
+

Changing JSON to Dictionary⚓︎

+

To change a JSON to a dictionary, first we import the json module and then we use loads method.

+
import json
+# JSON
+person_json = '''{
+    "name": "Asabeneh",
+    "country": "Finland",
+    "city": "Helsinki",
+    "skills": ["JavaScrip", "React", "Python"]
+}'''
+# let's change JSON to dictionary
+person_dct = json.loads(person_json)
+print(type(person_dct))
+print(person_dct)
+print(person_dct['name'])
+
+
# output
+<class 'dict'>
+{'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'skills': ['JavaScrip', 'React', 'Python']}
+Asabeneh
+
+

Changing Dictionary to JSON⚓︎

+

To change a dictionary to a JSON we use dumps method from the json module.

+
import json
+# python dictionary
+person = {
+    "name": "Asabeneh",
+    "country": "Finland",
+    "city": "Helsinki",
+    "skills": ["JavaScrip", "React", "Python"]
+}
+# let's convert it to  json
+person_json = json.dumps(person, indent=4) # indent could be 2, 4, 8. It beautifies the json
+print(type(person_json))
+print(person_json)
+
+
# output
+# when you print it, it does not have the quote, but actually it is a string
+# JSON does not have type, it is a string type.
+<class 'str'>
+{
+    "name": "Asabeneh",
+    "country": "Finland",
+    "city": "Helsinki",
+    "skills": [
+        "JavaScrip",
+        "React",
+        "Python"
+    ]
+}
+
+

Saving as JSON File⚓︎

+

We can also save our data as a json file. Let us save it as a json file using the following steps. For writing a json file, we use the json.dump() method, it can take dictionary, output file, ensure_ascii and indent.

+
import json
+# python dictionary
+person = {
+    "name": "Asabeneh",
+    "country": "Finland",
+    "city": "Helsinki",
+    "skills": ["JavaScrip", "React", "Python"]
+}
+with open('./files/json_example.json', 'w', encoding='utf-8') as f:
+    json.dump(person, f, ensure_ascii=False, indent=4)
+
+

In the code above, we use encoding and indentation. Indentation makes the json file easy to read.

+

File with csv Extension⚓︎

+

CSV stands for comma separated values. CSV is a simple file format used to store tabular data, such as a spreadsheet or database. CSV is a very common data format in data science.

+

Example:

+
"name","country","city","skills"
+"Asabeneh","Finland","Helsinki","JavaScript"
+
+

Example:

+
import csv
+with open('./files/csv_example.csv') as f:
+    csv_reader = csv.reader(f, delimiter=',') # w use, reader method to read csv
+    line_count = 0
+    for row in csv_reader:
+        if line_count == 0:
+            print(f'Column names are :{", ".join(row)}')
+            line_count += 1
+        else:
+            print(
+                f'\t{row[0]} is a teachers. He lives in {row[1]}, {row[2]}.')
+            line_count += 1
+    print(f'Number of lines:  {line_count}')
+
+
# output:
+Column names are :name, country, city, skills
+        Asabeneh is a teacher. He lives in Finland, Helsinki.
+Number of lines:  2
+
+

File with xlsx Extension⚓︎

+

To read excel files we need to install xlrd package. We will cover this after we cover package installing using pip.

+
import xlrd
+excel_book = xlrd.open_workbook('sample.xls)
+print(excel_book.nsheets)
+print(excel_book.sheet_names)
+
+

File with xml Extension⚓︎

+

XML is another structured data format which looks like HTML. In XML the tags are not predefined. The first line is an XML declaration. The person tag is the root of the XML. The person has a gender attribute. +Example:XML

+
<?xml version="1.0"?>
+<person gender="female">
+  <name>Asabeneh</name>
+  <country>Finland</country>
+  <city>Helsinki</city>
+  <skills>
+    <skill>JavaScrip</skill>
+    <skill>React</skill>
+    <skill>Python</skill>
+  </skills>
+</person>
+
+

For more information on how to read an XML file check the documentation

+
import xml.etree.ElementTree as ET
+tree = ET.parse('./files/xml_example.xml')
+root = tree.getroot()
+print('Root tag:', root.tag)
+print('Attribute:', root.attrib)
+for child in root:
+    print('field: ', child.tag)
+
+
# output
+Root tag: person
+Attribute: {'gender': 'male'}
+field: name
+field: country
+field: city
+field: skills
+
+

🌕 You are making a big progress. Maintain your momentum, keep the good work. Now do some exercises for your brain and muscles.

+

💻 Exercises: Day 19⚓︎

+

Exercises: Level 1⚓︎

+
    +
  1. Write a function which count number of lines and number of words in a text. All the files are in the data the folder: + a) Read obama_speech.txt file and count number of lines and words + b) Read michelle_obama_speech.txt file and count number of lines and words + c) Read donald_speech.txt file and count number of lines and words + d) Read melina_trump_speech.txt file and count number of lines and words
  2. +
  3. Read the countries_data.json data file in data directory, create a function that finds the ten most spoken languages
  4. +
+
# Your output should look like this
+print(most_spoken_languages(filename='./data/countries_data.json', 10))
+[(91, 'English'),
+(45, 'French'),
+(25, 'Arabic'),
+(24, 'Spanish'),
+(9, 'Russian'),
+(9, 'Portuguese'),
+(8, 'Dutch'),
+(7, 'German'),
+(5, 'Chinese'),
+(4, 'Swahili'),
+(4, 'Serbian')]
+
+# Your output should look like this
+print(most_spoken_languages(filename='./data/countries_data.json', 3))
+[(91, 'English'),
+(45, 'French'),
+(25, 'Arabic')]
+
+
    +
  1. Read the countries_data.json data file in data directory, create a function that creates a list of the ten most populated countries
  2. +
+
# Your output should look like this
+print(most_populated_countries(filename='./data/countries_data.json', 10))
+
+[
+{'country': 'China', 'population': 1377422166},
+{'country': 'India', 'population': 1295210000},
+{'country': 'United States of America', 'population': 323947000},
+{'country': 'Indonesia', 'population': 258705000},
+{'country': 'Brazil', 'population': 206135893},
+{'country': 'Pakistan', 'population': 194125062},
+{'country': 'Nigeria', 'population': 186988000},
+{'country': 'Bangladesh', 'population': 161006790},
+{'country': 'Russian Federation', 'population': 146599183},
+{'country': 'Japan', 'population': 126960000}
+]
+
+# Your output should look like this
+
+print(most_populated_countries(filename='./data/countries_data.json', 3))
+[
+{'country': 'China', 'population': 1377422166},
+{'country': 'India', 'population': 1295210000},
+{'country': 'United States of America', 'population': 323947000}
+]
+
+

Exercises: Level 2⚓︎

+
    +
  1. Extract all incoming email addresses as a list from the email_exchange_big.txt file.
  2. +
  3. Find the most common words in the English language. Call the name of your function find_most_common_words, it will take two parameters - a string or a file and a positive integer, indicating the number of words. Your function will return an array of tuples in descending order. Check the output
  4. +
+
    # Your output should look like this
+    print(find_most_common_words('sample.txt', 10))
+    [(10, 'the'),
+    (8, 'be'),
+    (6, 'to'),
+    (6, 'of'),
+    (5, 'and'),
+    (4, 'a'),
+    (4, 'in'),
+    (3, 'that'),
+    (2, 'have'),
+    (2, 'I')]
+
+    # Your output should look like this
+    print(find_most_common_words('sample.txt', 5))
+
+    [(10, 'the'),
+    (8, 'be'),
+    (6, 'to'),
+    (6, 'of'),
+    (5, 'and')]
+
+
    +
  1. Use the function, find_most_frequent_words to find: + a) The ten most frequent words used in Obama's speech + b) The ten most frequent words used in Michelle's speech + c) The ten most frequent words used in Trump's speech + d) The ten most frequent words used in Melina's speech
  2. +
  3. Write a python application that checks similarity between two texts. It takes a file or a string as a parameter and it will evaluate the similarity of the two texts. For instance check the similarity between the transcripts of Michelle's and Melina's speech. You may need a couple of functions, function to clean the text(clean_text), function to remove support words(remove_support_words) and finally to check the similarity(check_text_similarity). List of stop words are in the data directory
  4. +
  5. Find the 10 most repeated words in the romeo_and_juliet.txt
  6. +
  7. Read the hacker news csv file and find out: + a) Count the number of lines containing python or Python + b) Count the number lines containing JavaScript, javascript or Javascript + c) Count the number lines containing Java and not JavaScript
  8. +
+

Exercises: Level 3⚓︎

+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 18 | Day 20 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/20_python_package_manager/20_python_package_manager.md b/20_python_package_manager/20_python_package_manager.md new file mode 100644 index 0000000..37dc691 --- /dev/null +++ b/20_python_package_manager/20_python_package_manager.md @@ -0,0 +1,459 @@ +
+

30 Days Of Python: Day 20 - PIP

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+
+ +[<< Day 19](../19_Day_File_handling/19_file_handling.md) | [Day 21 >>](../21_Day_Classes_and_objects/21_classes_and_objects.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 20](#-day-20) + - [Python PIP - Python Package Manager](#python-pip---python-package-manager) + - [What is PIP ?](#what-is-pip-) + - [Installing PIP](#installing-pip) + - [Installing packages using pip](#installing-packages-using-pip) + - [Uninstalling Packages](#uninstalling-packages) + - [List of Packages](#list-of-packages) + - [Show Package](#show-package) + - [PIP Freeze](#pip-freeze) + - [Reading from URL](#reading-from-url) + - [Creating a Package](#creating-a-package) + - [Further Information About Packages](#further-information-about-packages) + - [Exercises: Day 20](#exercises-day-20) + +# 📘 Day 20 + +## Python PIP - Python Package Manager + +### What is PIP ? + +PIP stands for Preferred installer program. We use _pip_ to install different Python packages. +Package is a Python module that can contain one or more modules or other packages. A module or modules that we can install to our application is a package. +In programming, we do not have to write every utility program, instead we install packages and import them to our applications. + +### Installing PIP + +If you did not install pip, let us install it now. Go to your terminal or command prompt and copy and paste this: + +```sh +asabeneh@Asabeneh:~$ pip install pip +``` + +Check if pip is installed by writing + +```sh +pip --version +``` + +```py +asabeneh@Asabeneh:~$ pip --version +pip 21.1.3 from /usr/local/lib/python3.7/site-packages/pip (python 3.9.6) +``` + +As you can see, I am using pip version 21.1.3, if you see some number a bit below or above that, means you have pip installed. + +Let us check some of the packages used in the Python community for different purposes. Just to let you know that there are lots of packages available for use with different applications. + +### Installing packages using pip + +Let us try to install _numpy_, called numeric python. It is one of the most popular packages in machine learning and data science community. + +- NumPy is the fundamental package for scientific computing with Python. It contains among other things: + - a powerful N-dimensional array object + - sophisticated (broadcasting) functions + - tools for integrating C/C++ and Fortran code + - useful linear algebra, Fourier transform, and random number capabilities + +```sh +asabeneh@Asabeneh:~$ pip install numpy +``` + +Let us start using numpy. Open your python interactive shell, write python and then import numpy as follows: + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> import numpy +>>> numpy.version.version +'1.20.1' +>>> lst = [1, 2, 3,4, 5] +>>> np_arr = numpy.array(lst) +>>> np_arr +array([1, 2, 3, 4, 5]) +>>> len(np_arr) +5 +>>> np_arr * 2 +array([ 2, 4, 6, 8, 10]) +>>> np_arr + 2 +array([3, 4, 5, 6, 7]) +>>> +``` + +Pandas is an open source, BSD-licensed library providing high-performance, easy-to-use data structures and data analysis tools for the Python programming language. Let us install the big brother of numpy, _pandas_: + +```sh +asabeneh@Asabeneh:~$ pip install pandas +``` + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> import pandas +``` + +This section is not about numpy nor pandas, here we are trying to learn how to install packages and how to import them. If it is needed, we will talk about different packages in other sections. + +Let us import a web browser module, which can help us to open any website. We do not need to install this module, it is already installed by default with Python 3. For instance if you like to open any number of websites at any time or if you like to schedule something, this _webbrowser_ module can be used. + +```py +import webbrowser # web browser module to open websites + +# list of urls: python +url_lists = [ + 'http://www.python.org', + 'https://www.linkedin.com/in/asabeneh/', + 'https://github.com/Asabeneh', + 'https://twitter.com/Asabeneh', +] + +# opens the above list of websites in a different tab +for url in url_lists: + webbrowser.open_new_tab(url) +``` + +### Uninstalling Packages + +If you do not like to keep the installed packages, you can remove them using the following command. + +```sh +pip uninstall packagename +``` + +### List of Packages + +To see the installed packages on our machine. We can use pip followed by list. + +```sh +pip list +``` + +### Show Package + +To show information about a package + +```sh +pip show packagename +``` + +```sh +asabeneh@Asabeneh:~$ pip show pandas +Name: pandas +Version: 1.2.3 +Summary: Powerful data structures for data analysis, time series, and statistics +Home-page: http://pandas.pydata.org +Author: None +Author-email: None +License: BSD +Location: /usr/local/lib/python3.7/site-packages +Requires: python-dateutil, pytz, numpy +Required-by: +``` + +If we want even more details, just add --verbose + +```sh +asabeneh@Asabeneh:~$ pip show --verbose pandas +Name: pandas +Version: 1.2.3 +Summary: Powerful data structures for data analysis, time series, and statistics +Home-page: http://pandas.pydata.org +Author: None +Author-email: None +License: BSD +Location: /usr/local/lib/python3.7/site-packages +Requires: numpy, pytz, python-dateutil +Required-by: +Metadata-Version: 2.1 +Installer: pip +Classifiers: + Development Status :: 5 - Production/Stable + Environment :: Console + Operating System :: OS Independent + Intended Audience :: Science/Research + Programming Language :: Python + Programming Language :: Python :: 3 + Programming Language :: Python :: 3.5 + Programming Language :: Python :: 3.6 + Programming Language :: Python :: 3.7 + Programming Language :: Python :: 3.8 + Programming Language :: Cython + Topic :: Scientific/Engineering +Entry-points: + [pandas_plotting_backends] + matplotlib = pandas:plotting._matplotlib +``` + +### PIP Freeze + +Generate installed Python packages with their version and the output is suitable to use it in a requirements file. A requirements.txt file is a file that should contain all the installed Python packages in a Python project. + +```sh +asabeneh@Asabeneh:~$ pip freeze +docutils==0.11 +Jinja2==2.7.2 +MarkupSafe==0.19 +Pygments==1.6 +Sphinx==1.2.2 +``` + +The pip freeze gave us the packages used, installed and their version. We use it with requirements.txt file for deployment. + +### Reading from URL + +By now you are familiar with how to read or write on a file located on you local machine. Sometimes, we would like to read from a website using url or from an API. +API stands for Application Program Interface. It is a means to exchange structured data between servers primarily as json data. To open a network connection, we need a package called _requests_ - it allows to open a network connection and to implement CRUD(create, read, update and delete) operations. In this section, we will cover only reading ore getting part of a CRUD. + +Let us install _requests_: + +```py +asabeneh@Asabeneh:~$ pip install requests +``` + +We will see _get_, _status_code_, _headers_, _text_ and _json_ methods in _requests_ module: + - _get()_: to open a network and fetch data from url - it returns a response object + - _status_code_: After we fetched data, we can check the status of the operation (success, error, etc) + - _headers_: To check the header types + - _text_: to extract the text from the fetched response object + - _json_: to extract json data +Let's read a txt file from this website, https://www.w3.org/TR/PNG/iso_8859-1.txt. + +```py +import requests # importing the request module + +url = 'https://www.w3.org/TR/PNG/iso_8859-1.txt' # text from a website + +response = requests.get(url) # opening a network and fetching a data +print(response) +print(response.status_code) # status code, success:200 +print(response.headers) # headers information +print(response.text) # gives all the text from the page +``` + +```sh + +200 +{'date': 'Sun, 08 Dec 2019 18:00:31 GMT', 'last-modified': 'Fri, 07 Nov 2003 05:51:11 GMT', 'etag': '"17e9-3cb82080711c0;50c0b26855880-gzip"', 'accept-ranges': 'bytes', 'cache-control': 'max-age=31536000', 'expires': 'Mon, 07 Dec 2020 18:00:31 GMT', 'vary': 'Accept-Encoding', 'content-encoding': 'gzip', 'access-control-allow-origin': '*', 'content-length': '1616', 'content-type': 'text/plain', 'strict-transport-security': 'max-age=15552000; includeSubdomains; preload', 'content-security-policy': 'upgrade-insecure-requests'} +``` + +- Let us read from an API. API stands for Application Program Interface. It is a means to exchange structure data between servers primarily a json data. An example of an API:https://restcountries.eu/rest/v2/all. Let us read this API using _requests_ module. + +```py +import requests +url = 'https://restcountries.eu/rest/v2/all' # countries api +response = requests.get(url) # opening a network and fetching a data +print(response) # response object +print(response.status_code) # status code, success:200 +countries = response.json() +print(countries[:1]) # we sliced only the first country, remove the slicing to see all countries +``` + +```sh + +200 +[{'alpha2Code': 'AF', + 'alpha3Code': 'AFG', + 'altSpellings': ['AF', 'Afġānistān'], + 'area': 652230.0, + 'borders': ['IRN', 'PAK', 'TKM', 'UZB', 'TJK', 'CHN'], + 'callingCodes': ['93'], + 'capital': 'Kabul', + 'cioc': 'AFG', + 'currencies': [{'code': 'AFN', 'name': 'Afghan afghani', 'symbol': '؋'}], + 'demonym': 'Afghan', + 'flag': 'https://restcountries.eu/data/afg.svg', + 'gini': 27.8, + 'languages': [{'iso639_1': 'ps', + 'iso639_2': 'pus', + 'name': 'Pashto', + 'nativeName': 'پښتو'}, + {'iso639_1': 'uz', + 'iso639_2': 'uzb', + 'name': 'Uzbek', + 'nativeName': 'Oʻzbek'}, + {'iso639_1': 'tk', + 'iso639_2': 'tuk', + 'name': 'Turkmen', + 'nativeName': 'Türkmen'}], + 'latlng': [33.0, 65.0], + 'name': 'Afghanistan', + 'nativeName': 'افغانستان', + 'numericCode': '004', + 'population': 27657145, + 'region': 'Asia', + 'regionalBlocs': [{'acronym': 'SAARC', + 'name': 'South Asian Association for Regional Cooperation', + 'otherAcronyms': [], + 'otherNames': []}], + 'subregion': 'Southern Asia', + 'timezones': ['UTC+04:30'], + 'topLevelDomain': ['.af'], + 'translations': {'br': 'Afeganistão', + 'de': 'Afghanistan', + 'es': 'Afganistán', + 'fa': 'افغانستان', + 'fr': 'Afghanistan', + 'hr': 'Afganistan', + 'it': 'Afghanistan', + 'ja': 'アフガニスタン', + 'nl': 'Afghanistan', + 'pt': 'Afeganistão'}}] +``` + +We use _json()_ method from response object, if the we are fetching JSON data. For txt, html, xml and other file formats we can use _text_. + +### Creating a Package + +We organize a large number of files in different folders and sub-folders based on some criteria, so that we can find and manage them easily. As you know, a module can contain multiple objects, such as classes, functions, etc. A package can contain one or more relevant modules. A package is actually a folder containing one or more module files. Let us create a package named mypackage, using the following steps: + +Create a new folder named mypacakge inside 30DaysOfPython folder +Create an empty **__init__**.py file in the mypackage folder. +Create modules arithmetic.py and greet.py with following code: + +```py +# mypackage/arithmetics.py +# arithmetics.py +def add_numbers(*args): + total = 0 + for num in args: + total += num + return total + + +def subtract(a, b): + return (a - b) + + +def multiple(a, b): + return a * b + + +def division(a, b): + return a / b + + +def remainder(a, b): + return a % b + + +def power(a, b): + return a ** b +``` + +```py +# mypackage/greet.py +# greet.py +def greet_person(firstname, lastname): + return f'{firstname} {lastname}, welcome to 30DaysOfPython Challenge!' +``` + +The folder structure of your package should look like this: + +```sh +─ mypackage + ├── __init__.py + ├── arithmetic.py + └── greet.py +``` + +Now let's open the python interactive shell and try the package we have created: + +```sh +asabeneh@Asabeneh:~/Desktop/30DaysOfPython$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> from mypackage import arithmetics +>>> arithmetics.add_numbers(1, 2, 3, 5) +11 +>>> arithmetics.subtract(5, 3) +2 +>>> arithmetics.multiple(5, 3) +15 +>>> arithmetics.division(5, 3) +1.6666666666666667 +>>> arithmetics.remainder(5, 3) +2 +>>> arithmetics.power(5, 3) +125 +>>> from mypackage import greet +>>> greet.greet_person('Asabeneh', 'Yetayeh') +'Asabeneh Yetayeh, welcome to 30DaysOfPython Challenge!' +>>> +``` + +As you can see our package works perfectly. The package folder contains a special file called **__init__**.py - it stores the package's content. If we put **__init__**.py in the package folder, python start recognizes it as a package. +The **__init__**.py exposes specified resources from its modules to be imported to other python files. An empty **__init__**.py file makes all functions available when a package is imported. The **__init__**.py is essential for the folder to be recognized by Python as a package. + +### Further Information About Packages + +- Database + - SQLAlchemy or SQLObject - Object oriented access to several different database systems + - _pip install SQLAlchemy_ +- Web Development + - Django - High-level web framework. + - _pip install django_ + - Flask - micro framework for Python based on Werkzeug, Jinja 2. (It's BSD licensed) + - _pip install flask_ +- HTML Parser + - [Beautiful Soup](https://www.crummy.com/software/BeautifulSoup/bs4/doc/) - HTML/XML parser designed for quick turnaround projects like screen-scraping, will accept bad markup. + - _pip install beautifulsoup4_ + - PyQuery - implements jQuery in Python; faster than BeautifulSoup, apparently. + +- XML Processing + - ElementTree - The Element type is a simple but flexible container object, designed to store hierarchical data structures, such as simplified XML infosets, in memory. --Note: Python 2.5 and up has ElementTree in the Standard Library +- GUI + - PyQt - Bindings for the cross-platform Qt framework. + - TkInter - The traditional Python user interface toolkit. +- Data Analysis, Data Science and Machine learning + - Numpy: Numpy(numeric python) is known as one of the most popular machine learning library in Python. + - Pandas: is a data analysis, data science and a machine learning library in Python that provides data structures of high-level and a wide variety of tools for analysis. + - SciPy: SciPy is a machine learning library for application developers and engineers. SciPy library contains modules for optimization, linear algebra, integration, image processing, and statistics. + - Scikit-Learn: It is NumPy and SciPy. It is considered as one of the best libraries for working with complex data. + - TensorFlow: is a machine learning library built by Google. + - Keras: is considered as one of the coolest machine learning libraries in Python. It provides an easier mechanism to express neural networks. Keras also provides some of the best utilities for compiling models, processing data-sets, visualization of graphs, and much more. +- Network: + - requests: is a package which we can use to send requests to a server(GET, POST, DELETE, PUT) + - _pip install requests_ + +🌕 You are always progressing and you are a head of 20 steps to your way to greatness. Now do some exercises for your brain and muscles. + +## Exercises: Day 20 + +1. Read this url and find the 10 most frequent words. romeo_and_juliet = 'http://www.gutenberg.org/files/1112/1112.txt' +2. Read the cats API and cats_api = 'https://api.thecatapi.com/v1/breeds' and find : + 1. the min, max, mean, median, standard deviation of cats' weight in metric units. + 2. the min, max, mean, median, standard deviation of cats' lifespan in years. + 3. Create a frequency table of country and breed of cats +3. Read the [countries API](https://restcountries.eu/rest/v2/all) and find + 1. the 10 largest countries + 2. the 10 most spoken languages + 3. the total number of languages in the countries API +4. UCI is one of the most common places to get data sets for data science and machine learning. Read the content of UCL (https://archive.ics.uci.edu/ml/datasets.php). Without additional libraries it will be difficult, so you may try it with BeautifulSoup4 + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 19](../19_Day_File_handling/19_file_handling.md) | [Day 21 >>](../21_Day_Classes_and_objects/21_classes_and_objects.md) diff --git a/20_python_package_manager/index.html b/20_python_package_manager/index.html new file mode 100644 index 0000000..1b4081f --- /dev/null +++ b/20_python_package_manager/index.html @@ -0,0 +1,1754 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 20 python package manager - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 20 - PIP

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+
+ +

<< Day 19 | Day 21 >>

+

30DaysOfPython

+ +

📘 Day 20⚓︎

+

Python PIP - Python Package Manager⚓︎

+

What is PIP ?⚓︎

+

PIP stands for Preferred installer program. We use pip to install different Python packages. +Package is a Python module that can contain one or more modules or other packages. A module or modules that we can install to our application is a package. +In programming, we do not have to write every utility program, instead we install packages and import them to our applications.

+

Installing PIP⚓︎

+

If you did not install pip, let us install it now. Go to your terminal or command prompt and copy and paste this:

+
asabeneh@Asabeneh:~$ pip install pip
+
+

Check if pip is installed by writing

+
pip --version
+
+
asabeneh@Asabeneh:~$ pip --version
+pip 21.1.3 from /usr/local/lib/python3.7/site-packages/pip (python 3.9.6)
+
+

As you can see, I am using pip version 21.1.3, if you see some number a bit below or above that, means you have pip installed.

+

Let us check some of the packages used in the Python community for different purposes. Just to let you know that there are lots of packages available for use with different applications.

+

Installing packages using pip⚓︎

+

Let us try to install numpy, called numeric python. It is one of the most popular packages in machine learning and data science community.

+
    +
  • NumPy is the fundamental package for scientific computing with Python. It contains among other things:
  • +
  • a powerful N-dimensional array object
  • +
  • sophisticated (broadcasting) functions
  • +
  • tools for integrating C/C++ and Fortran code
  • +
  • useful linear algebra, Fourier transform, and random number capabilities
  • +
+
asabeneh@Asabeneh:~$ pip install numpy
+
+

Let us start using numpy. Open your python interactive shell, write python and then import numpy as follows:

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import numpy
+>>> numpy.version.version
+'1.20.1'
+>>> lst = [1, 2, 3,4, 5]
+>>> np_arr = numpy.array(lst)
+>>> np_arr
+array([1, 2, 3, 4, 5])
+>>> len(np_arr)
+5
+>>> np_arr * 2
+array([ 2,  4,  6,  8, 10])
+>>> np_arr  + 2
+array([3, 4, 5, 6, 7])
+>>>
+
+

Pandas is an open source, BSD-licensed library providing high-performance, easy-to-use data structures and data analysis tools for the Python programming language. Let us install the big brother of numpy, pandas:

+
asabeneh@Asabeneh:~$ pip install pandas
+
+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> import pandas
+
+

This section is not about numpy nor pandas, here we are trying to learn how to install packages and how to import them. If it is needed, we will talk about different packages in other sections.

+

Let us import a web browser module, which can help us to open any website. We do not need to install this module, it is already installed by default with Python 3. For instance if you like to open any number of websites at any time or if you like to schedule something, this webbrowser module can be used.

+
import webbrowser # web browser module to open websites
+
+# list of urls: python
+url_lists = [
+    'http://www.python.org',
+    'https://www.linkedin.com/in/asabeneh/',
+    'https://github.com/Asabeneh',
+    'https://twitter.com/Asabeneh',
+]
+
+# opens the above list of websites in a different tab
+for url in url_lists:
+    webbrowser.open_new_tab(url)
+
+

Uninstalling Packages⚓︎

+

If you do not like to keep the installed packages, you can remove them using the following command.

+
pip uninstall packagename
+
+

List of Packages⚓︎

+

To see the installed packages on our machine. We can use pip followed by list.

+
pip list
+
+

Show Package⚓︎

+

To show information about a package

+
pip show packagename
+
+
asabeneh@Asabeneh:~$ pip show pandas
+Name: pandas
+Version: 1.2.3
+Summary: Powerful data structures for data analysis, time series, and statistics
+Home-page: http://pandas.pydata.org
+Author: None
+Author-email: None
+License: BSD
+Location: /usr/local/lib/python3.7/site-packages
+Requires: python-dateutil, pytz, numpy
+Required-by:
+
+

If we want even more details, just add --verbose

+
asabeneh@Asabeneh:~$ pip show --verbose pandas
+Name: pandas
+Version: 1.2.3
+Summary: Powerful data structures for data analysis, time series, and statistics
+Home-page: http://pandas.pydata.org
+Author: None
+Author-email: None
+License: BSD
+Location: /usr/local/lib/python3.7/site-packages
+Requires: numpy, pytz, python-dateutil
+Required-by:
+Metadata-Version: 2.1
+Installer: pip
+Classifiers:
+  Development Status :: 5 - Production/Stable
+  Environment :: Console
+  Operating System :: OS Independent
+  Intended Audience :: Science/Research
+  Programming Language :: Python
+  Programming Language :: Python :: 3
+  Programming Language :: Python :: 3.5
+  Programming Language :: Python :: 3.6
+  Programming Language :: Python :: 3.7
+  Programming Language :: Python :: 3.8
+  Programming Language :: Cython
+  Topic :: Scientific/Engineering
+Entry-points:
+  [pandas_plotting_backends]
+  matplotlib = pandas:plotting._matplotlib
+
+

PIP Freeze⚓︎

+

Generate installed Python packages with their version and the output is suitable to use it in a requirements file. A requirements.txt file is a file that should contain all the installed Python packages in a Python project.

+
asabeneh@Asabeneh:~$ pip freeze
+docutils==0.11
+Jinja2==2.7.2
+MarkupSafe==0.19
+Pygments==1.6
+Sphinx==1.2.2
+
+

The pip freeze gave us the packages used, installed and their version. We use it with requirements.txt file for deployment.

+

Reading from URL⚓︎

+

By now you are familiar with how to read or write on a file located on you local machine. Sometimes, we would like to read from a website using url or from an API. +API stands for Application Program Interface. It is a means to exchange structured data between servers primarily as json data. To open a network connection, we need a package called requests - it allows to open a network connection and to implement CRUD(create, read, update and delete) operations. In this section, we will cover only reading ore getting part of a CRUD.

+

Let us install requests:

+
asabeneh@Asabeneh:~$ pip install requests
+
+

We will see get, status_code, headers, text and json methods in requests module: + - get(): to open a network and fetch data from url - it returns a response object + - status_code: After we fetched data, we can check the status of the operation (success, error, etc) + - headers: To check the header types + - text: to extract the text from the fetched response object + - json: to extract json data +Let's read a txt file from this website, https://www.w3.org/TR/PNG/iso_8859-1.txt.

+
import requests # importing the request module
+
+url = 'https://www.w3.org/TR/PNG/iso_8859-1.txt' # text from a website
+
+response = requests.get(url) # opening a network and fetching a data
+print(response)
+print(response.status_code) # status code, success:200
+print(response.headers)     # headers information
+print(response.text) # gives all the text from the page
+
+
<Response [200]>
+200
+{'date': 'Sun, 08 Dec 2019 18:00:31 GMT', 'last-modified': 'Fri, 07 Nov 2003 05:51:11 GMT', 'etag': '"17e9-3cb82080711c0;50c0b26855880-gzip"', 'accept-ranges': 'bytes', 'cache-control': 'max-age=31536000', 'expires': 'Mon, 07 Dec 2020 18:00:31 GMT', 'vary': 'Accept-Encoding', 'content-encoding': 'gzip', 'access-control-allow-origin': '*', 'content-length': '1616', 'content-type': 'text/plain', 'strict-transport-security': 'max-age=15552000; includeSubdomains; preload', 'content-security-policy': 'upgrade-insecure-requests'}
+
+
    +
  • Let us read from an API. API stands for Application Program Interface. It is a means to exchange structure data between servers primarily a json data. An example of an API:https://restcountries.eu/rest/v2/all. Let us read this API using requests module.
  • +
+
import requests
+url = 'https://restcountries.eu/rest/v2/all'  # countries api
+response = requests.get(url)  # opening a network and fetching a data
+print(response) # response object
+print(response.status_code)  # status code, success:200
+countries = response.json()
+print(countries[:1])  # we sliced only the first country, remove the slicing to see all countries
+
+
<Response [200]>
+200
+[{'alpha2Code': 'AF',
+  'alpha3Code': 'AFG',
+  'altSpellings': ['AF', 'Afġānistān'],
+  'area': 652230.0,
+  'borders': ['IRN', 'PAK', 'TKM', 'UZB', 'TJK', 'CHN'],
+  'callingCodes': ['93'],
+  'capital': 'Kabul',
+  'cioc': 'AFG',
+  'currencies': [{'code': 'AFN', 'name': 'Afghan afghani', 'symbol': '؋'}],
+  'demonym': 'Afghan',
+  'flag': 'https://restcountries.eu/data/afg.svg',
+  'gini': 27.8,
+  'languages': [{'iso639_1': 'ps',
+                 'iso639_2': 'pus',
+                 'name': 'Pashto',
+                 'nativeName': 'پښتو'},
+                {'iso639_1': 'uz',
+                 'iso639_2': 'uzb',
+                 'name': 'Uzbek',
+                 'nativeName': 'Oʻzbek'},
+                {'iso639_1': 'tk',
+                 'iso639_2': 'tuk',
+                 'name': 'Turkmen',
+                 'nativeName': 'Türkmen'}],
+  'latlng': [33.0, 65.0],
+  'name': 'Afghanistan',
+  'nativeName': 'افغانستان',
+  'numericCode': '004',
+  'population': 27657145,
+  'region': 'Asia',
+  'regionalBlocs': [{'acronym': 'SAARC',
+                     'name': 'South Asian Association for Regional Cooperation',
+                     'otherAcronyms': [],
+                     'otherNames': []}],
+  'subregion': 'Southern Asia',
+  'timezones': ['UTC+04:30'],
+  'topLevelDomain': ['.af'],
+  'translations': {'br': 'Afeganistão',
+                   'de': 'Afghanistan',
+                   'es': 'Afganistán',
+                   'fa': 'افغانستان',
+                   'fr': 'Afghanistan',
+                   'hr': 'Afganistan',
+                   'it': 'Afghanistan',
+                   'ja': 'アフガニスタン',
+                   'nl': 'Afghanistan',
+                   'pt': 'Afeganistão'}}]
+
+

We use json() method from response object, if the we are fetching JSON data. For txt, html, xml and other file formats we can use text.

+

Creating a Package⚓︎

+

We organize a large number of files in different folders and sub-folders based on some criteria, so that we can find and manage them easily. As you know, a module can contain multiple objects, such as classes, functions, etc. A package can contain one or more relevant modules. A package is actually a folder containing one or more module files. Let us create a package named mypackage, using the following steps:

+

Create a new folder named mypacakge inside 30DaysOfPython folder +Create an empty init.py file in the mypackage folder. +Create modules arithmetic.py and greet.py with following code:

+
# mypackage/arithmetics.py
+# arithmetics.py
+def add_numbers(*args):
+    total = 0
+    for num in args:
+        total += num
+    return total
+
+
+def subtract(a, b):
+    return (a - b)
+
+
+def multiple(a, b):
+    return a * b
+
+
+def division(a, b):
+    return a / b
+
+
+def remainder(a, b):
+    return a % b
+
+
+def power(a, b):
+    return a ** b
+
+
# mypackage/greet.py
+# greet.py
+def greet_person(firstname, lastname):
+    return f'{firstname} {lastname}, welcome to 30DaysOfPython Challenge!'
+
+

The folder structure of your package should look like this:

+
 mypackage
+    ├── __init__.py
+    ├── arithmetic.py
+    └── greet.py
+
+

Now let's open the python interactive shell and try the package we have created:

+
asabeneh@Asabeneh:~/Desktop/30DaysOfPython$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> from mypackage import arithmetics
+>>> arithmetics.add_numbers(1, 2, 3, 5)
+11
+>>> arithmetics.subtract(5, 3)
+2
+>>> arithmetics.multiple(5, 3)
+15
+>>> arithmetics.division(5, 3)
+1.6666666666666667
+>>> arithmetics.remainder(5, 3)
+2
+>>> arithmetics.power(5, 3)
+125
+>>> from mypackage import greet
+>>> greet.greet_person('Asabeneh', 'Yetayeh')
+'Asabeneh Yetayeh, welcome to 30DaysOfPython Challenge!'
+>>>
+
+

As you can see our package works perfectly. The package folder contains a special file called init.py - it stores the package's content. If we put init.py in the package folder, python start recognizes it as a package. +The init.py exposes specified resources from its modules to be imported to other python files. An empty init.py file makes all functions available when a package is imported. The init.py is essential for the folder to be recognized by Python as a package.

+

Further Information About Packages⚓︎

+
    +
  • Database
  • +
  • SQLAlchemy or SQLObject - Object oriented access to several different database systems
      +
    • pip install SQLAlchemy
    • +
    +
  • +
  • Web Development
  • +
  • Django - High-level web framework.
      +
    • pip install django
    • +
    +
  • +
  • Flask - micro framework for Python based on Werkzeug, Jinja 2. (It's BSD licensed)
      +
    • pip install flask
    • +
    +
  • +
  • HTML Parser
  • +
  • Beautiful Soup - HTML/XML parser designed for quick turnaround projects like screen-scraping, will accept bad markup.
      +
    • pip install beautifulsoup4
    • +
    +
  • +
  • +

    PyQuery - implements jQuery in Python; faster than BeautifulSoup, apparently.

    +
  • +
  • +

    XML Processing

    +
  • +
  • ElementTree - The Element type is a simple but flexible container object, designed to store hierarchical data structures, such as simplified XML infosets, in memory. --Note: Python 2.5 and up has ElementTree in the Standard Library
  • +
  • GUI
  • +
  • PyQt - Bindings for the cross-platform Qt framework.
  • +
  • TkInter - The traditional Python user interface toolkit.
  • +
  • Data Analysis, Data Science and Machine learning
  • +
  • Numpy: Numpy(numeric python) is known as one of the most popular machine learning library in Python.
  • +
  • Pandas: is a data analysis, data science and a machine learning library in Python that provides data structures of high-level and a wide variety of tools for analysis.
  • +
  • SciPy: SciPy is a machine learning library for application developers and engineers. SciPy library contains modules for optimization, linear algebra, integration, image processing, and statistics.
  • +
  • Scikit-Learn: It is NumPy and SciPy. It is considered as one of the best libraries for working with complex data.
  • +
  • TensorFlow: is a machine learning library built by Google.
  • +
  • Keras: is considered as one of the coolest machine learning libraries in Python. It provides an easier mechanism to express neural networks. Keras also provides some of the best utilities for compiling models, processing data-sets, visualization of graphs, and much more.
  • +
  • Network:
  • +
  • requests: is a package which we can use to send requests to a server(GET, POST, DELETE, PUT)
      +
    • pip install requests
    • +
    +
  • +
+

🌕 You are always progressing and you are a head of 20 steps to your way to greatness. Now do some exercises for your brain and muscles.

+

Exercises: Day 20⚓︎

+
    +
  1. Read this url and find the 10 most frequent words. romeo_and_juliet = 'http://www.gutenberg.org/files/1112/1112.txt'
  2. +
  3. Read the cats API and cats_api = 'https://api.thecatapi.com/v1/breeds' and find :
  4. +
  5. the min, max, mean, median, standard deviation of cats' weight in metric units.
  6. +
  7. the min, max, mean, median, standard deviation of cats' lifespan in years.
  8. +
  9. Create a frequency table of country and breed of cats
  10. +
  11. Read the countries API and find
  12. +
  13. the 10 largest countries
  14. +
  15. the 10 most spoken languages
  16. +
  17. the total number of languages in the countries API
  18. +
  19. UCI is one of the most common places to get data sets for data science and machine learning. Read the content of UCL (https://archive.ics.uci.edu/ml/datasets.php). Without additional libraries it will be difficult, so you may try it with BeautifulSoup4
  20. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 19 | Day 21 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/21_classes_and_objects/21_classes_and_objects.md b/21_classes_and_objects/21_classes_and_objects.md new file mode 100644 index 0000000..9876cfb --- /dev/null +++ b/21_classes_and_objects/21_classes_and_objects.md @@ -0,0 +1,370 @@ +
+

30 Days Of Python: Day 21 - Classes and Objects

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+ +
+ +[<< Day 20](../20_Day_Python_package_manager/20_python_package_manager.md) | [Day 22 >>](../22_Day_Web_scraping/22_web_scraping.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 21](#-day-21) + - [Classes and Objects](#classes-and-objects) + - [Creating a Class](#creating-a-class) + - [Creating an Object](#creating-an-object) + - [Class Constructor](#class-constructor) + - [Object Methods](#object-methods) + - [Object Default Methods](#object-default-methods) + - [Method to Modify Class Default Values](#method-to-modify-class-default-values) + - [Inheritance](#inheritance) + - [Overriding parent method](#overriding-parent-method) + - [💻 Exercises: Day 21](#-exercises-day-21) + - [Exercises: Level 1](#exercises-level-1) + - [Exercises: Level 2](#exercises-level-2) + - [Exercises: Level 3](#exercises-level-3) + +# 📘 Day 21 + +## Classes and Objects + +Python is an object oriented programming language. Everything in Python is an object, with its properties and methods. A number, string, list, dictionary, tuple, set etc. used in a program is an object of a corresponding built-in class. We create class to create an object. A class is like an object constructor, or a "blueprint" for creating objects. We instantiate a class to create an object. The class defines attributes and the behavior of the object, while the object, on the other hand, represents the class. + +We have been working with classes and objects right from the beginning of this challenge unknowingly. Every element in a Python program is an object of a class. +Let us check if everything in python is a class: + +```py +asabeneh@Asabeneh:~$ python +Python 3.9.6 (default, Jun 28 2021, 15:26:21) +[Clang 11.0.0 (clang-1100.0.33.8)] on darwin +Type "help", "copyright", "credits" or "license" for more information. +>>> num = 10 +>>> type(num) + +>>> string = 'string' +>>> type(string) + +>>> boolean = True +>>> type(boolean) + +>>> lst = [] +>>> type(lst) + +>>> tpl = () +>>> type(tpl) + +>>> set1 = set() +>>> type(set1) + +>>> dct = {} +>>> type(dct) + +``` + +### Creating a Class + +To create a class we need the key word **class** followed by the name and colon. Class name should be **CamelCase**. + +```sh +# syntax +class ClassName: + code goes here +``` + +**Example:** + +```py +class Person: + pass +print(Person) +``` + +```sh +<__main__.Person object at 0x10804e510> +``` + +### Creating an Object + +We can create an object by calling the class. + +```py +p = Person() +print(p) +``` + +### Class Constructor + +In the examples above, we have created an object from the Person class. However, a class without a constructor is not really useful in real applications. Let us use constructor function to make our class more useful. Like the constructor function in Java or JavaScript, Python has also a built-in **__init__**() constructor function. The **__init__** constructor function has self parameter which is a reference to the current instance of the class +**Examples:** + +```py +class Person: + def __init__ (self, name): + # self allows to attach parameter to the class + self.name =name + +p = Person('Asabeneh') +print(p.name) +print(p) +``` + +```sh +# output +Asabeneh +<__main__.Person object at 0x2abf46907e80> +``` + +Let us add more parameters to the constructor function. + +```py +class Person: + def __init__(self, firstname, lastname, age, country, city): + self.firstname = firstname + self.lastname = lastname + self.age = age + self.country = country + self.city = city + + +p = Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki') +print(p.firstname) +print(p.lastname) +print(p.age) +print(p.country) +print(p.city) +``` + +```sh +# output +Asabeneh +Yetayeh +250 +Finland +Helsinki +``` + +### Object Methods + +Objects can have methods. The methods are functions which belong to the object. + +**Example:** + +```py +class Person: + def __init__(self, firstname, lastname, age, country, city): + self.firstname = firstname + self.lastname = lastname + self.age = age + self.country = country + self.city = city + def person_info(self): + return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}' + +p = Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki') +print(p.person_info()) +``` + +```sh +# output +Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland +``` + +### Object Default Methods + +Sometimes, you may want to have a default values for your object methods. If we give default values for the parameters in the constructor, we can avoid errors when we call or instantiate our class without parameters. Let's see how it looks: + +**Example:** + +```py +class Person: + def __init__(self, firstname='Asabeneh', lastname='Yetayeh', age=250, country='Finland', city='Helsinki'): + self.firstname = firstname + self.lastname = lastname + self.age = age + self.country = country + self.city = city + + def person_info(self): + return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}.' + +p1 = Person() +print(p1.person_info()) +p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city') +print(p2.person_info()) +``` + +```sh +# output +Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland. +John Doe is 30 years old. He lives in Noman city, Nomanland. +``` + +### Method to Modify Class Default Values + +In the example below, the person class, all the constructor parameters have default values. In addition to that, we have skills parameter, which we can access using a method. Let us create add_skill method to add skills to the skills list. + +```py +class Person: + def __init__(self, firstname='Asabeneh', lastname='Yetayeh', age=250, country='Finland', city='Helsinki'): + self.firstname = firstname + self.lastname = lastname + self.age = age + self.country = country + self.city = city + self.skills = [] + + def person_info(self): + return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}.' + def add_skill(self, skill): + self.skills.append(skill) + +p1 = Person() +print(p1.person_info()) +p1.add_skill('HTML') +p1.add_skill('CSS') +p1.add_skill('JavaScript') +p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city') +print(p2.person_info()) +print(p1.skills) +print(p2.skills) +``` + +```sh +# output +Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland. +John Doe is 30 years old. He lives in Noman city, Nomanland. +['HTML', 'CSS', 'JavaScript'] +[] +``` + +### Inheritance + +Using inheritance we can reuse parent class code. Inheritance allows us to define a class that inherits all the methods and properties from parent class. The parent class or super or base class is the class which gives all the methods and properties. Child class is the class that inherits from another or parent class. +Let us create a student class by inheriting from person class. + +```py +class Student(Person): + pass + + +s1 = Student('Eyob', 'Yetayeh', 30, 'Finland', 'Helsinki') +s2 = Student('Lidiya', 'Teklemariam', 28, 'Finland', 'Espoo') +print(s1.person_info()) +s1.add_skill('JavaScript') +s1.add_skill('React') +s1.add_skill('Python') +print(s1.skills) + +print(s2.person_info()) +s2.add_skill('Organizing') +s2.add_skill('Marketing') +s2.add_skill('Digital Marketing') +print(s2.skills) + +``` + +```sh +output +Eyob Yetayeh is 30 years old. He lives in Helsinki, Finland. +['JavaScript', 'React', 'Python'] +Lidiya Teklemariam is 28 years old. He lives in Espoo, Finland. +['Organizing', 'Marketing', 'Digital Marketing'] +``` + +We did not call the **__init__**() constructor in the child class. If we didn't call it then we can still access all the properties from the parent. But if we do call the constructor we can access the parent properties by calling _super_. +We can add a new method to the child or we can override the parent class methods by creating the same method name in the child class. When we add the **__init__**() function, the child class will no longer inherit the parent's **__init__**() function. + +### Overriding parent method + +```py +class Student(Person): + def __init__ (self, firstname='Asabeneh', lastname='Yetayeh',age=250, country='Finland', city='Helsinki', gender='male'): + self.gender = gender + super().__init__(firstname, lastname,age, country, city) + def person_info(self): + gender = 'He' if self.gender =='male' else 'She' + return f'{self.firstname} {self.lastname} is {self.age} years old. {gender} lives in {self.city}, {self.country}.' + +s1 = Student('Eyob', 'Yetayeh', 30, 'Finland', 'Helsinki','male') +s2 = Student('Lidiya', 'Teklemariam', 28, 'Finland', 'Espoo', 'female') +print(s1.person_info()) +s1.add_skill('JavaScript') +s1.add_skill('React') +s1.add_skill('Python') +print(s1.skills) + +print(s2.person_info()) +s2.add_skill('Organizing') +s2.add_skill('Marketing') +s2.add_skill('Digital Marketing') +print(s2.skills) +``` + +```sh +Eyob Yetayeh is 30 years old. He lives in Helsinki, Finland. +['JavaScript', 'React', 'Python'] +Lidiya Teklemariam is 28 years old. She lives in Espoo, Finland. +['Organizing', 'Marketing', 'Digital Marketing'] +``` + +We can use super() built-in function or the parent name Person to automatically inherit the methods and properties from its parent. In the example above we override the parent method. The child method has a different feature, it can identify, if the gender is male or female and assign the proper pronoun(He/She). + +🌕 Now, you are fully charged with a super power of programming. Now do some exercises for your brain and muscles. + +## 💻 Exercises: Day 21 + +### Exercises: Level 1 + +1. Python has the module called _statistics_ and we can use this module to do all the statistical calculations. However, to learn how to make function and reuse function let us try to develop a program, which calculates the measure of central tendency of a sample (mean, median, mode) and measure of variability (range, variance, standard deviation). In addition to those measures, find the min, max, count, percentile, and frequency distribution of the sample. You can create a class called Statistics and create all the functions that do statistical calculations as methods for the Statistics class. Check the output below. + +```py +ages = [31, 26, 34, 37, 27, 26, 32, 32, 26, 27, 27, 24, 32, 33, 27, 25, 26, 38, 37, 31, 34, 24, 33, 29, 26] + +print('Count:', data.count()) # 25 +print('Sum: ', data.sum()) # 744 +print('Min: ', data.min()) # 24 +print('Max: ', data.max()) # 38 +print('Range: ', data.range() # 14 +print('Mean: ', data.mean()) # 30 +print('Median: ', data.median()) # 29 +print('Mode: ', data.mode()) # {'mode': 26, 'count': 5} +print('Standard Deviation: ', data.std()) # 4.2 +print('Variance: ', data.var()) # 17.5 +print('Frequency Distribution: ', data.freq_dist()) # [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)] +``` + +```sh +# you output should look like this +print(data.describe()) +Count: 25 +Sum: 744 +Min: 24 +Max: 38 +Range: 14 +Mean: 30 +Median: 29 +Mode: (26, 5) +Variance: 17.5 +Standard Deviation: 4.2 +Frequency Distribution: [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)] +``` + +### Exercises: Level 2 + +1. Create a class called PersonAccount. It has firstname, lastname, incomes, expenses properties and it has total_income, total_expense, account_info, add_income, add_expense and account_balance methods. Incomes is a set of incomes and its description. The same goes for expenses. + +### Exercises: Level 3 + + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 20](../20_Day_Python_package_manager/20_python_package_manager.md) | [Day 22 >>](../22_Day_Web_scraping/22_web_scraping.md) diff --git a/21_classes_and_objects/index.html b/21_classes_and_objects/index.html new file mode 100644 index 0000000..4f7fd77 --- /dev/null +++ b/21_classes_and_objects/index.html @@ -0,0 +1,1693 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 21 classes and objects - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 21 - Classes and Objects

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+ +
+ +

<< Day 20 | Day 22 >>

+

30DaysOfPython

+ +

📘 Day 21⚓︎

+

Classes and Objects⚓︎

+

Python is an object oriented programming language. Everything in Python is an object, with its properties and methods. A number, string, list, dictionary, tuple, set etc. used in a program is an object of a corresponding built-in class. We create class to create an object. A class is like an object constructor, or a "blueprint" for creating objects. We instantiate a class to create an object. The class defines attributes and the behavior of the object, while the object, on the other hand, represents the class.

+

We have been working with classes and objects right from the beginning of this challenge unknowingly. Every element in a Python program is an object of a class. +Let us check if everything in python is a class:

+
asabeneh@Asabeneh:~$ python
+Python 3.9.6 (default, Jun 28 2021, 15:26:21)
+[Clang 11.0.0 (clang-1100.0.33.8)] on darwin
+Type "help", "copyright", "credits" or "license" for more information.
+>>> num = 10
+>>> type(num)
+<class 'int'>
+>>> string = 'string'
+>>> type(string)
+<class 'str'>
+>>> boolean = True
+>>> type(boolean)
+<class 'bool'>
+>>> lst = []
+>>> type(lst)
+<class 'list'>
+>>> tpl = ()
+>>> type(tpl)
+<class 'tuple'>
+>>> set1 = set()
+>>> type(set1)
+<class 'set'>
+>>> dct = {}
+>>> type(dct)
+<class 'dict'>
+
+

Creating a Class⚓︎

+

To create a class we need the key word class followed by the name and colon. Class name should be CamelCase.

+
# syntax
+class ClassName:
+  code goes here
+
+

Example:

+
class Person:
+  pass
+print(Person)
+
+
<__main__.Person object at 0x10804e510>
+
+

Creating an Object⚓︎

+

We can create an object by calling the class.

+
p = Person()
+print(p)
+
+

Class Constructor⚓︎

+

In the examples above, we have created an object from the Person class. However, a class without a constructor is not really useful in real applications. Let us use constructor function to make our class more useful. Like the constructor function in Java or JavaScript, Python has also a built-in init() constructor function. The init constructor function has self parameter which is a reference to the current instance of the class +Examples:

+
class Person:
+      def __init__ (self, name):
+        # self allows to attach parameter to the class
+          self.name =name
+
+p = Person('Asabeneh')
+print(p.name)
+print(p)
+
+
# output
+Asabeneh
+<__main__.Person object at 0x2abf46907e80>
+
+

Let us add more parameters to the constructor function.

+
class Person:
+      def __init__(self, firstname, lastname, age, country, city):
+          self.firstname = firstname
+          self.lastname = lastname
+          self.age = age
+          self.country = country
+          self.city = city
+
+
+p = Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
+print(p.firstname)
+print(p.lastname)
+print(p.age)
+print(p.country)
+print(p.city)
+
+
# output
+Asabeneh
+Yetayeh
+250
+Finland
+Helsinki
+
+

Object Methods⚓︎

+

Objects can have methods. The methods are functions which belong to the object.

+

Example:

+
class Person:
+      def __init__(self, firstname, lastname, age, country, city):
+          self.firstname = firstname
+          self.lastname = lastname
+          self.age = age
+          self.country = country
+          self.city = city
+      def person_info(self):
+        return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}'
+
+p = Person('Asabeneh', 'Yetayeh', 250, 'Finland', 'Helsinki')
+print(p.person_info())
+
+
# output
+Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland
+
+

Object Default Methods⚓︎

+

Sometimes, you may want to have a default values for your object methods. If we give default values for the parameters in the constructor, we can avoid errors when we call or instantiate our class without parameters. Let's see how it looks:

+

Example:

+
class Person:
+      def __init__(self, firstname='Asabeneh', lastname='Yetayeh', age=250, country='Finland', city='Helsinki'):
+          self.firstname = firstname
+          self.lastname = lastname
+          self.age = age
+          self.country = country
+          self.city = city
+
+      def person_info(self):
+        return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}.'
+
+p1 = Person()
+print(p1.person_info())
+p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city')
+print(p2.person_info())
+
+
# output
+Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland.
+John Doe is 30 years old. He lives in Noman city, Nomanland.
+
+

Method to Modify Class Default Values⚓︎

+

In the example below, the person class, all the constructor parameters have default values. In addition to that, we have skills parameter, which we can access using a method. Let us create add_skill method to add skills to the skills list.

+
class Person:
+      def __init__(self, firstname='Asabeneh', lastname='Yetayeh', age=250, country='Finland', city='Helsinki'):
+          self.firstname = firstname
+          self.lastname = lastname
+          self.age = age
+          self.country = country
+          self.city = city
+          self.skills = []
+
+      def person_info(self):
+        return f'{self.firstname} {self.lastname} is {self.age} years old. He lives in {self.city}, {self.country}.'
+      def add_skill(self, skill):
+          self.skills.append(skill)
+
+p1 = Person()
+print(p1.person_info())
+p1.add_skill('HTML')
+p1.add_skill('CSS')
+p1.add_skill('JavaScript')
+p2 = Person('John', 'Doe', 30, 'Nomanland', 'Noman city')
+print(p2.person_info())
+print(p1.skills)
+print(p2.skills)
+
+
# output
+Asabeneh Yetayeh is 250 years old. He lives in Helsinki, Finland.
+John Doe is 30 years old. He lives in Noman city, Nomanland.
+['HTML', 'CSS', 'JavaScript']
+[]
+
+

Inheritance⚓︎

+

Using inheritance we can reuse parent class code. Inheritance allows us to define a class that inherits all the methods and properties from parent class. The parent class or super or base class is the class which gives all the methods and properties. Child class is the class that inherits from another or parent class. +Let us create a student class by inheriting from person class.

+
class Student(Person):
+    pass
+
+
+s1 = Student('Eyob', 'Yetayeh', 30, 'Finland', 'Helsinki')
+s2 = Student('Lidiya', 'Teklemariam', 28, 'Finland', 'Espoo')
+print(s1.person_info())
+s1.add_skill('JavaScript')
+s1.add_skill('React')
+s1.add_skill('Python')
+print(s1.skills)
+
+print(s2.person_info())
+s2.add_skill('Organizing')
+s2.add_skill('Marketing')
+s2.add_skill('Digital Marketing')
+print(s2.skills)
+
+
output
+Eyob Yetayeh is 30 years old. He lives in Helsinki, Finland.
+['JavaScript', 'React', 'Python']
+Lidiya Teklemariam is 28 years old. He lives in Espoo, Finland.
+['Organizing', 'Marketing', 'Digital Marketing']
+
+

We did not call the init() constructor in the child class. If we didn't call it then we can still access all the properties from the parent. But if we do call the constructor we can access the parent properties by calling super.
+We can add a new method to the child or we can override the parent class methods by creating the same method name in the child class. When we add the init() function, the child class will no longer inherit the parent's init() function.

+

Overriding parent method⚓︎

+
class Student(Person):
+    def __init__ (self, firstname='Asabeneh', lastname='Yetayeh',age=250, country='Finland', city='Helsinki', gender='male'):
+        self.gender = gender
+        super().__init__(firstname, lastname,age, country, city)
+    def person_info(self):
+        gender = 'He' if self.gender =='male' else 'She'
+        return f'{self.firstname} {self.lastname} is {self.age} years old. {gender} lives in {self.city}, {self.country}.'
+
+s1 = Student('Eyob', 'Yetayeh', 30, 'Finland', 'Helsinki','male')
+s2 = Student('Lidiya', 'Teklemariam', 28, 'Finland', 'Espoo', 'female')
+print(s1.person_info())
+s1.add_skill('JavaScript')
+s1.add_skill('React')
+s1.add_skill('Python')
+print(s1.skills)
+
+print(s2.person_info())
+s2.add_skill('Organizing')
+s2.add_skill('Marketing')
+s2.add_skill('Digital Marketing')
+print(s2.skills)
+
+
Eyob Yetayeh is 30 years old. He lives in Helsinki, Finland.
+['JavaScript', 'React', 'Python']
+Lidiya Teklemariam is 28 years old. She lives in Espoo, Finland.
+['Organizing', 'Marketing', 'Digital Marketing']
+
+

We can use super() built-in function or the parent name Person to automatically inherit the methods and properties from its parent. In the example above we override the parent method. The child method has a different feature, it can identify, if the gender is male or female and assign the proper pronoun(He/She).

+

🌕 Now, you are fully charged with a super power of programming. Now do some exercises for your brain and muscles.

+

💻 Exercises: Day 21⚓︎

+

Exercises: Level 1⚓︎

+
    +
  1. Python has the module called statistics and we can use this module to do all the statistical calculations. However, to learn how to make function and reuse function let us try to develop a program, which calculates the measure of central tendency of a sample (mean, median, mode) and measure of variability (range, variance, standard deviation). In addition to those measures, find the min, max, count, percentile, and frequency distribution of the sample. You can create a class called Statistics and create all the functions that do statistical calculations as methods for the Statistics class. Check the output below.
  2. +
+
ages = [31, 26, 34, 37, 27, 26, 32, 32, 26, 27, 27, 24, 32, 33, 27, 25, 26, 38, 37, 31, 34, 24, 33, 29, 26]
+
+print('Count:', data.count()) # 25
+print('Sum: ', data.sum()) # 744
+print('Min: ', data.min()) # 24
+print('Max: ', data.max()) # 38
+print('Range: ', data.range() # 14
+print('Mean: ', data.mean()) # 30
+print('Median: ', data.median()) # 29
+print('Mode: ', data.mode()) # {'mode': 26, 'count': 5}
+print('Standard Deviation: ', data.std()) # 4.2
+print('Variance: ', data.var()) # 17.5
+print('Frequency Distribution: ', data.freq_dist()) # [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)]
+
+
# you output should look like this
+print(data.describe())
+Count: 25
+Sum:  744
+Min:  24
+Max:  38
+Range:  14
+Mean:  30
+Median:  29
+Mode:  (26, 5)
+Variance:  17.5
+Standard Deviation:  4.2
+Frequency Distribution: [(20.0, 26), (16.0, 27), (12.0, 32), (8.0, 37), (8.0, 34), (8.0, 33), (8.0, 31), (8.0, 24), (4.0, 38), (4.0, 29), (4.0, 25)]
+
+

Exercises: Level 2⚓︎

+
    +
  1. Create a class called PersonAccount. It has firstname, lastname, incomes, expenses properties and it has total_income, total_expense, account_info, add_income, add_expense and account_balance methods. Incomes is a set of incomes and its description. The same goes for expenses.
  2. +
+

Exercises: Level 3⚓︎

+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 20 | Day 22 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/22_web_scraping/22_web_scraping.md b/22_web_scraping/22_web_scraping.md new file mode 100644 index 0000000..5c6a69b --- /dev/null +++ b/22_web_scraping/22_web_scraping.md @@ -0,0 +1,108 @@ +
+

30 Days Of Python: Day 22 - Web Scraping

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ +[<< Day 21](../21_Day_Classes_and_objects/21_classes_and_objects.md) | [Day 23 >>](../23_Day_Virtual_environment/23_virtual_environment.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 22](#-day-22) + - [Python Web Scraping](#python-web-scraping) + - [What is Web Scrapping](#what-is-web-scrapping) + - [💻 Exercises: Day 22](#-exercises-day-22) + +# 📘 Day 22 + +## Python Web Scraping + +### What is Web Scrapping + +The internet is full of huge amount of data which can be used for different purposes. To collect this data we need to know how to scrape data from a website. + +Web scraping is the process of extracting and collecting data from websites and storing it on a local machine or in a database. + +In this section, we will use beautifulsoup and requests package to scrape data. The package version we are using is beautifulsoup 4. + +To start scraping websites you need _requests_, _beautifoulSoup4_ and a _website_. + +```sh +pip install requests +pip install beautifulsoup4 +``` + +To scrape data from websites, basic understanding of HTML tags and CSS selectors is needed. We target content from a website using HTML tags, classes or/and ids. +Let us import the requests and BeautifulSoup module + +```py +import requests +from bs4 import BeautifulSoup +``` + +Let us declare url variable for the website which we are going to scrape. + +```py + +import requests +from bs4 import BeautifulSoup +url = 'https://archive.ics.uci.edu/ml/datasets.php' + +# Lets use the requests get method to fetch the data from url + +response = requests.get(url) +# lets check the status +status = response.status_code +print(status) # 200 means the fetching was successful +``` + +```sh +200 +``` + +Using beautifulSoup to parse content from the page + +```py +import requests +from bs4 import BeautifulSoup +url = 'https://archive.ics.uci.edu/ml/datasets.php' + +response = requests.get(url) +content = response.content # we get all the content from the website +soup = BeautifulSoup(content, 'html.parser') # beautiful soup will give a chance to parse +print(soup.title) # UCI Machine Learning Repository: Data Sets +print(soup.title.get_text()) # UCI Machine Learning Repository: Data Sets +print(soup.body) # gives the whole page on the website +print(response.status_code) + +tables = soup.find_all('table', {'cellpadding':'3'}) +# We are targeting the table with cellpadding attribute with the value of 3 +# We can select using id, class or HTML tag , for more information check the beautifulsoup doc +table = tables[0] # the result is a list, we are taking out data from it +for td in table.find('tr').find_all('td'): + print(td.text) +``` + +If you run this code, you can see that the extraction is half done. You can continue doing it because it is part of exercise 1. +For reference check the [beautifulsoup documentation](https://www.crummy.com/software/BeautifulSoup/bs4/doc/#quick-start) + +🌕 You are so special, you are progressing everyday. You are left with only eight days to your way to greatness. Now do some exercises for your brain and muscles. + +## 💻 Exercises: Day 22 + +1. Scrape the following website and store the data as json file(url = 'http://www.bu.edu/president/boston-university-facts-stats/'). +1. Extract the table in this url (https://archive.ics.uci.edu/ml/datasets.php) and change it to a json file +2. Scrape the presidents table and store the data as json(https://en.wikipedia.org/wiki/List_of_presidents_of_the_United_States). The table is not very structured and the scrapping may take very long time. + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 21](../21_Day_Web_scraping/21_class_and_object.md) | [Day 23 >>](../23_Day_Virtual_environment/23_virtual_environment.md) diff --git a/22_web_scraping/index.html b/22_web_scraping/index.html new file mode 100644 index 0000000..e9483c1 --- /dev/null +++ b/22_web_scraping/index.html @@ -0,0 +1,1286 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 22 web scraping - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 22 - Web Scraping

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ +

<< Day 21 | Day 23 >>

+

30DaysOfPython

+ +

📘 Day 22⚓︎

+

Python Web Scraping⚓︎

+

What is Web Scrapping⚓︎

+

The internet is full of huge amount of data which can be used for different purposes. To collect this data we need to know how to scrape data from a website.

+

Web scraping is the process of extracting and collecting data from websites and storing it on a local machine or in a database.

+

In this section, we will use beautifulsoup and requests package to scrape data. The package version we are using is beautifulsoup 4.

+

To start scraping websites you need requests, beautifoulSoup4 and a website.

+
pip install requests
+pip install beautifulsoup4
+
+

To scrape data from websites, basic understanding of HTML tags and CSS selectors is needed. We target content from a website using HTML tags, classes or/and ids. +Let us import the requests and BeautifulSoup module

+
import requests
+from bs4 import BeautifulSoup
+
+

Let us declare url variable for the website which we are going to scrape.

+
import requests
+from bs4 import BeautifulSoup
+url = 'https://archive.ics.uci.edu/ml/datasets.php'
+
+# Lets use the requests get method to fetch the data from url
+
+response = requests.get(url)
+# lets check the status
+status = response.status_code
+print(status) # 200 means the fetching was successful
+
+
200
+
+

Using beautifulSoup to parse content from the page

+
import requests
+from bs4 import BeautifulSoup
+url = 'https://archive.ics.uci.edu/ml/datasets.php'
+
+response = requests.get(url)
+content = response.content # we get all the content from the website
+soup = BeautifulSoup(content, 'html.parser') # beautiful soup will give a chance to parse
+print(soup.title) # <title>UCI Machine Learning Repository: Data Sets</title>
+print(soup.title.get_text()) # UCI Machine Learning Repository: Data Sets
+print(soup.body) # gives the whole page on the website
+print(response.status_code)
+
+tables = soup.find_all('table', {'cellpadding':'3'})
+# We are targeting the table with cellpadding attribute with the value of 3
+# We can select using id, class or HTML tag , for more information check the beautifulsoup doc
+table = tables[0] # the result is a list, we are taking out data from it
+for td in table.find('tr').find_all('td'):
+    print(td.text)
+
+

If you run this code, you can see that the extraction is half done. You can continue doing it because it is part of exercise 1. +For reference check the beautifulsoup documentation

+

🌕 You are so special, you are progressing everyday. You are left with only eight days to your way to greatness. Now do some exercises for your brain and muscles.

+

💻 Exercises: Day 22⚓︎

+
    +
  1. Scrape the following website and store the data as json file(url = 'http://www.bu.edu/president/boston-university-facts-stats/').
  2. +
  3. Extract the table in this url (https://archive.ics.uci.edu/ml/datasets.php) and change it to a json file
  4. +
  5. Scrape the presidents table and store the data as json(https://en.wikipedia.org/wiki/List_of_presidents_of_the_United_States). The table is not very structured and the scrapping may take very long time.
  6. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 21 | Day 23 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/23_virtual_environment/23_virtual_environment.md b/23_virtual_environment/23_virtual_environment.md new file mode 100644 index 0000000..d23b45c --- /dev/null +++ b/23_virtual_environment/23_virtual_environment.md @@ -0,0 +1,114 @@ +
+

30 Days Of Python: Day 23 - Virtual Environment

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ +[<< Day 22](../22_Day_Web_scraping/22_web_scraping.md) | [Day 24 >>](../24_Day_Statistics/24_statistics.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 23](#-day-23) + - [Setting up Virtual Environments](#setting-up-virtual-environments) + - [💻 Exercises: Day 23](#-exercises-day-23) + +# 📘 Day 23 + +## Setting up Virtual Environments + +To start with project, it would be better to have a virtual environment. Virtual environment can help us to create an isolated or separate environment. This will help us to avoid conflicts in dependencies across projects. If you write pip freeze on your terminal you will see all the installed packages on your computer. If we use virtualenv, we will access only packages which are specific for that project. Open your terminal and install virtualenv + +```sh +asabeneh@Asabeneh:~$ pip install virtualenv +``` + +Inside the 30DaysOfPython folder create a flask_project folder. + +After installing the virtualenv package go to your project folder and create a virtual env by writing: + +For Mac/Linux: +```sh +asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project\$ virtualenv venv + +``` + +For Windows: +```sh +C:\Users\User\Documents\30DaysOfPython\flask_project>python -m venv venv +``` + +I prefer to call the new project venv, but feel free to name it differently. Let us check if the the venv was created by using ls (or dir for windows command prompt) command. + +```sh +asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ ls +venv/ +``` + +Let us activate the virtual environment by writing the following command at our project folder. + +For Mac/Linux: +```sh +asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ source venv/bin/activate +``` +Activation of the virtual environment in Windows may very on Windows Power shell and git bash. + +For Windows Power Shell: +```sh +C:\Users\User\Documents\30DaysOfPython\flask_project> venv\Scripts\activate +``` + +For Windows Git bash: +```sh +C:\Users\User\Documents\30DaysOfPython\flask_project> venv\Scripts\. activate +``` + +After you write the activation command, your project directory will start with venv. See the example below. + +```sh +(venv) asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ +``` + +Now, lets check the available packages in this project by writing pip freeze. You will not see any packages. + +We are going to do a small flask project so let us install flask package to this project. + +```sh +(venv) asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ pip install Flask +``` + +Now, let us write pip freeze to see a list of installed packages in the project: + +```sh +(venv) asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ pip freeze +Click==7.0 +Flask==1.1.1 +itsdangerous==1.1.0 +Jinja2==2.10.3 +MarkupSafe==1.1.1 +Werkzeug==0.16.0 +``` + +When you finish you should dactivate active project using _deactivate_. + +```sh +(venv) asabeneh@Asabeneh:~/Desktop/30DaysOfPython$ deactivate +``` + +The necessary modules to work with flask are installed. Now, your project directory is ready for a flask project. You should include the venv to your .gitignore file not to push it to github. + +## 💻 Exercises: Day 23 + +1. Create a project directory with a virtual environment based on the example given above. + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 22](../22_Day_Web_scraping/22_web_scraping.md) | [Day 24 >>](../24_Day_Statistics/24_statistics.md) diff --git a/23_virtual_environment/index.html b/23_virtual_environment/index.html new file mode 100644 index 0000000..12fe7fe --- /dev/null +++ b/23_virtual_environment/index.html @@ -0,0 +1,1247 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 23 virtual environment - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 23 - Virtual Environment

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ +

<< Day 22 | Day 24 >>

+

30DaysOfPython

+ +

📘 Day 23⚓︎

+

Setting up Virtual Environments⚓︎

+

To start with project, it would be better to have a virtual environment. Virtual environment can help us to create an isolated or separate environment. This will help us to avoid conflicts in dependencies across projects. If you write pip freeze on your terminal you will see all the installed packages on your computer. If we use virtualenv, we will access only packages which are specific for that project. Open your terminal and install virtualenv

+
asabeneh@Asabeneh:~$ pip install virtualenv
+
+

Inside the 30DaysOfPython folder create a flask_project folder.

+

After installing the virtualenv package go to your project folder and create a virtual env by writing:

+

For Mac/Linux: +

asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project\$ virtualenv venv
+

+

For Windows: +

C:\Users\User\Documents\30DaysOfPython\flask_project>python -m venv venv
+

+

I prefer to call the new project venv, but feel free to name it differently. Let us check if the the venv was created by using ls (or dir for windows command prompt) command.

+
asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ ls
+venv/
+
+

Let us activate the virtual environment by writing the following command at our project folder.

+

For Mac/Linux: +

asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ source venv/bin/activate
+
+Activation of the virtual environment in Windows may very on Windows Power shell and git bash.

+

For Windows Power Shell: +

C:\Users\User\Documents\30DaysOfPython\flask_project> venv\Scripts\activate
+

+

For Windows Git bash: +

C:\Users\User\Documents\30DaysOfPython\flask_project> venv\Scripts\. activate
+

+

After you write the activation command, your project directory will start with venv. See the example below.

+
(venv) asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$
+
+

Now, lets check the available packages in this project by writing pip freeze. You will not see any packages.

+

We are going to do a small flask project so let us install flask package to this project.

+
(venv) asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ pip install Flask
+
+

Now, let us write pip freeze to see a list of installed packages in the project:

+
(venv) asabeneh@Asabeneh:~/Desktop/30DaysOfPython/flask_project$ pip freeze
+Click==7.0
+Flask==1.1.1
+itsdangerous==1.1.0
+Jinja2==2.10.3
+MarkupSafe==1.1.1
+Werkzeug==0.16.0
+
+

When you finish you should dactivate active project using deactivate.

+
(venv) asabeneh@Asabeneh:~/Desktop/30DaysOfPython$ deactivate
+
+

The necessary modules to work with flask are installed. Now, your project directory is ready for a flask project. You should include the venv to your .gitignore file not to push it to github.

+

💻 Exercises: Day 23⚓︎

+
    +
  1. Create a project directory with a virtual environment based on the example given above.
  2. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 22 | Day 24 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/24_statistics/24_statistics.md b/24_statistics/24_statistics.md new file mode 100644 index 0000000..4978e3c --- /dev/null +++ b/24_statistics/24_statistics.md @@ -0,0 +1,1237 @@ +
+

30 Days Of Python: Day 24 - Statistics

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+
+ +[<< Day 23](../23_Day_Virtual_environment/23_virtual_environment.md) | [Day 25 >>](../25_Day_Pandas/25_pandas.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 24](#-day-24) + - [Python for Statistical Analysis](#python-for-statistical-analysis) + - [Statistics](#statistics) + - [Data](#data) + - [Statistics Module](#statistics-module) +- [NumPy](#numpy) + +# 📘 Day 24 + +## Python for Statistical Analysis + +## Statistics + +Statistics is the discipline that studies the _collection_, _organization_, _displaying_, _analysing_, _interpretation_ and _presentation_ of data. +Statistics is a branch of Mathematics that is recommended to be a prerequisite for data science and machine learning. Statistics is a very broad field but we will focus in this section only on the most relevant part. +After completing this challenge, you may go onto the web development, data analysis, machine learning and data science path. Whatever path you may follow, at some point in your career you will get data which you may work on. Having some statistical knowledge will help you to make decisions based on data, _data tells as they say_. + +## Data + +What is data? Data is any set of characters that is gathered and translated for some purpose, usually analysis. It can be any character, including text and numbers, pictures, sound, or video. If data is not put in a context, it doesn't make any sense to a human or computer. To make sense from data we need to work on the data using different tools. + +The work flow of data analysis, data science or machine learning starts from data. Data can be provided from some data source or it can be created. There are structured and unstructured data. + +Data can be found in small or big format. Most of the data types we will get have been covered in the file handling section. + +## Statistics Module + +The Python _statistics_ module provides functions for calculating mathematical statistics of numerical data. The module is not intended to be a competitor to third-party libraries such as NumPy, SciPy, or proprietary full-featured statistics packages aimed at professional statisticians such as Minitab, SAS and Matlab. It is aimed at the level of graphing and scientific calculators. + +# NumPy + +In the first section we defined Python as a great general-purpose programming language on its own, but with the help of other popular libraries as(numpy, scipy, matplotlib, pandas etc) it becomes a powerful environment for scientific computing. + +NumPy is the core library for scientific computing in Python. It provides a high-performance multidimensional array object, and tools for working with arrays. + +So far, we have been using vscode but from now on I would recommend using Jupyter Notebook. To access jupyter notebook let's install [anaconda](https://www.anaconda.com/). If you are using anaconda most of the common packages are included and you don't have install packages if you installed anaconda. + +```sh +asabeneh@Asabeneh:~/Desktop/30DaysOfPython$ pip install numpy +``` + +## Importing NumPy + +Jupyter notebook is available if your are in favor of [jupyter notebook](https://github.com/Asabeneh/data-science-for-everyone/blob/master/numpy/numpy.ipynb) + +```py + # How to import numpy + import numpy as np + # How to check the version of the numpy package + print('numpy:', np.__version__) + # Checking the available methods + print(dir(np)) +``` + +## Creating numpy array using + +### Creating int numpy arrays + +```py + # Creating python List + python_list = [1,2,3,4,5] + + # Checking data types + print('Type:', type (python_list)) # + # + print(python_list) # [1, 2, 3, 4, 5] + + two_dimensional_list = [[0,1,2], [3,4,5], [6,7,8]] + + print(two_dimensional_list) # [[0, 1, 2], [3, 4, 5], [6, 7, 8]] + + # Creating Numpy(Numerical Python) array from python list + + numpy_array_from_list = np.array(python_list) + print(type (numpy_array_from_list)) # + print(numpy_array_from_list) # array([1, 2, 3, 4, 5]) +``` + +### Creating float numpy arrays + +Creating a float numpy array from list with a float data type parameter + +```py + # Python list + python_list = [1,2,3,4,5] + + numy_array_from_list2 = np.array(python_list, dtype=float) + print(numy_array_from_list2) # array([1., 2., 3., 4., 5.]) +``` + +### Creating boolean numpy arrays + +Creating a boolean a numpy array from list + +```py + numpy_bool_array = np.array([0, 1, -1, 0, 0], dtype=bool) + print(numpy_bool_array) # array([False, True, True, False, False]) +``` + +### Creating multidimensional array using numpy + +A numpy array may have one or multiple rows and columns + +```py + two_dimensional_list = [[0,1,2], [3,4,5], [6,7,8]] + numpy_two_dimensional_list = np.array(two_dimensional_list) + print(type (numpy_two_dimensional_list)) + print(numpy_two_dimensional_list) +``` + +```sh + + [[0 1 2] + [3 4 5] + [6 7 8]] +``` + +### Converting numpy array to list + +```python +# We can always convert an array back to a python list using tolist(). +np_to_list = numpy_array_from_list.tolist() +print(type (np_to_list)) +print('one dimensional array:', np_to_list) +print('two dimensional array: ', numpy_two_dimensional_list.tolist()) +``` + +```sh + + one dimensional array: [1, 2, 3, 4, 5] + two dimensional array: [[0, 1, 2], [3, 4, 5], [6, 7, 8]] +``` + +### Creating numpy array from tuple + +```py +# Numpy array from tuple +# Creating tuple in Python +python_tuple = (1,2,3,4,5) +print(type (python_tuple)) # +print('python_tuple: ', python_tuple) # python_tuple: (1, 2, 3, 4, 5) + +numpy_array_from_tuple = np.array(python_tuple) +print(type (numpy_array_from_tuple)) # +print('numpy_array_from_tuple: ', numpy_array_from_tuple) # numpy_array_from_tuple: [1 2 3 4 5] +``` + +### Shape of numpy array + +The shape method provide the shape of the array as a tuple. The first is the row and the second is the column. If the array is just one dimensional it returns the size of the array. + +```py + nums = np.array([1, 2, 3, 4, 5]) + print(nums) + print('shape of nums: ', nums.shape) + print(numpy_two_dimensional_list) + print('shape of numpy_two_dimensional_list: ', numpy_two_dimensional_list.shape) + three_by_four_array = np.array([[0, 1, 2, 3], + [4,5,6,7], + [8,9,10, 11]]) + print(three_by_four_array.shape) +``` + +```sh + [1 2 3 4 5] + shape of nums: (5,) + [[0 1 2] + [3 4 5] + [6 7 8]] + shape of numpy_two_dimensional_list: (3, 3) + (3, 4) +``` + +### Data type of numpy array + +Type of data types: str, int, float, complex, bool, list, None + +```py +int_lists = [-3, -2, -1, 0, 1, 2,3] +int_array = np.array(int_lists) +float_array = np.array(int_lists, dtype=float) + +print(int_array) +print(int_array.dtype) +print(float_array) +print(float_array.dtype) +``` + +```sh + [-3 -2 -1 0 1 2 3] + int64 + [-3. -2. -1. 0. 1. 2. 3.] + float64 +``` + +### Size of a numpy array + +In numpy to know the number of items in a numpy array list we use size + +```py +numpy_array_from_list = np.array([1, 2, 3, 4, 5]) +two_dimensional_list = np.array([[0, 1, 2], + [3, 4, 5], + [6, 7, 8]]) + +print('The size:', numpy_array_from_list.size) # 5 +print('The size:', two_dimensional_list.size) # 3 + +``` + +```sh + The size: 5 + The size: 9 +``` + +## Mathematical Operation using numpy + +NumPy array is not like exactly like python list. To do mathematical operation in Python list we have to loop through the items but numpy can allow to do any mathematical operation without looping. +Mathematical Operation: + +- Addition (+) +- Subtraction (-) +- Multiplication (\*) +- Division (/) +- Modules (%) +- Floor Division(//) +- Exponential(\*\*) + +### Addition + +```py +# Mathematical Operation +# Addition +numpy_array_from_list = np.array([1, 2, 3, 4, 5]) +print('original array: ', numpy_array_from_list) +ten_plus_original = numpy_array_from_list + 10 +print(ten_plus_original) + +``` + +```sh + original array: [1 2 3 4 5] + [11 12 13 14 15] +``` + +### Subtraction + +```python +# Subtraction +numpy_array_from_list = np.array([1, 2, 3, 4, 5]) +print('original array: ', numpy_array_from_list) +ten_minus_original = numpy_array_from_list - 10 +print(ten_minus_original) +``` + +```sh + original array: [1 2 3 4 5] + [-9 -8 -7 -6 -5] +``` + +### Multiplication + +```python +# Multiplication +numpy_array_from_list = np.array([1, 2, 3, 4, 5]) +print('original array: ', numpy_array_from_list) +ten_times_original = numpy_array_from_list * 10 +print(ten_times_original) +``` + +```sh + original array: [1 2 3 4 5] + [10 20 30 40 50] +``` + +### Division + +```python +# Division +numpy_array_from_list = np.array([1, 2, 3, 4, 5]) +print('original array: ', numpy_array_from_list) +ten_times_original = numpy_array_from_list / 10 +print(ten_times_original) +``` + +```sh + original array: [1 2 3 4 5] + [0.1 0.2 0.3 0.4 0.5] +``` + +### Modulus + +```python +# Modulus; Finding the remainder +numpy_array_from_list = np.array([1, 2, 3, 4, 5]) +print('original array: ', numpy_array_from_list) +ten_times_original = numpy_array_from_list % 3 +print(ten_times_original) +``` + +```sh + original array: [1 2 3 4 5] + [1 2 0 1 2] +``` + +### Floor Division + +```py +# Floor division: the division result without the remainder +numpy_array_from_list = np.array([1, 2, 3, 4, 5]) +print('original array: ', numpy_array_from_list) +ten_times_original = numpy_array_from_list // 10 +print(ten_times_original) +``` + +### Exponential + +```py +# Exponential is finding some number the power of another: +numpy_array_from_list = np.array([1, 2, 3, 4, 5]) +print('original array: ', numpy_array_from_list) +ten_times_original = numpy_array_from_list ** 2 +print(ten_times_original) +``` + +```sh + original array: [1 2 3 4 5] + [ 1 4 9 16 25] +``` + +## Checking data types + +```py +#Int, Float numbers +numpy_int_arr = np.array([1,2,3,4]) +numpy_float_arr = np.array([1.1, 2.0,3.2]) +numpy_bool_arr = np.array([-3, -2, 0, 1,2,3], dtype='bool') + +print(numpy_int_arr.dtype) +print(numpy_float_arr.dtype) +print(numpy_bool_arr.dtype) +``` + +```sh + int64 + float64 + bool +``` + +### Converting types + +We can convert the data types of numpy array + +1. Int to Float + +```py +numpy_int_arr = np.array([1,2,3,4], dtype = 'float') +numpy_int_arr +``` + + array([1., 2., 3., 4.]) + +2. Float to Int + +```py +numpy_int_arr = np.array([1., 2., 3., 4.], dtype = 'int') +numpy_int_arr +``` + +```sh + array([1, 2, 3, 4]) +``` + +3. Int ot boolean + +```py +np.array([-3, -2, 0, 1,2,3], dtype='bool') + +``` + +```sh + array([ True, True, False, True, True, True]) +``` + +4. Int to str + +```py +numpy_float_list.astype('int').astype('str') +``` + +```sh + array(['1', '2', '3'], dtype=' + [[1 2 3] + [4 5 6] + [7 8 9]] + Shape: (3, 3) + Size: 9 + Data type: int64 +``` + +### Getting items from a numpy array + +```py +# 2 Dimension Array +two_dimension_array = np.array([[1,2,3],[4,5,6], [7,8,9]]) +first_row = two_dimension_array[0] +second_row = two_dimension_array[1] +third_row = two_dimension_array[2] +print('First row:', first_row) +print('Second row:', second_row) +print('Third row: ', third_row) +``` + +```sh + First row: [1 2 3] + Second row: [4 5 6] + Third row: [7 8 9] +``` + +```py +first_column= two_dimension_array[:,0] +second_column = two_dimension_array[:,1] +third_column = two_dimension_array[:,2] +print('First column:', first_column) +print('Second column:', second_column) +print('Third column: ', third_column) +print(two_dimension_array) + +``` + +```sh + First column: [1 4 7] + Second column: [2 5 8] + Third column: [3 6 9] + [[1 2 3] + [4 5 6] + [7 8 9]] +``` + +## Slicing Numpy array + +Slicing in numpy is similar to slicing in python list + +```py +two_dimension_array = np.array([[1,2,3],[4,5,6], [7,8,9]]) +first_two_rows_and_columns = two_dimension_array[0:2, 0:2] +print(first_two_rows_and_columns) +``` + +```sh + [[1 2] + [4 5]] +``` + +### How to reverse the rows and the whole array? + +```py +two_dimension_array[::] +``` + +```sh + array([[1, 2, 3], + [4, 5, 6], + [7, 8, 9]]) +``` + +### Reverse the row and column positions + +```py + two_dimension_array = np.array([[1,2,3],[4,5,6], [7,8,9]]) + two_dimension_array[::-1,::-1] +``` + +```sh + array([[9, 8, 7], + [6, 5, 4], + [3, 2, 1]]) +``` + +## How to represent missing values ? + +```python + print(two_dimension_array) + two_dimension_array[1,1] = 55 + two_dimension_array[1,2] =44 + print(two_dimension_array) +``` + +```sh + [[1 2 3] + [4 5 6] + [7 8 9]] + [[ 1 2 3] + [ 4 55 44] + [ 7 8 9]] +``` + +```py + # Numpy Zeroes + # numpy.zeros(shape, dtype=float, order='C') + numpy_zeroes = np.zeros((3,3),dtype=int,order='C') + numpy_zeroes +``` + +```sh + array([[0, 0, 0], + [0, 0, 0], + [0, 0, 0]]) +``` + +```py +# Numpy Zeroes +numpy_ones = np.ones((3,3),dtype=int,order='C') +print(numpy_ones) +``` + +```sh + [[1 1 1] + [1 1 1] + [1 1 1]] +``` + +```py +twoes = numpy_ones * 2 +``` + +```py +# Reshape +# numpy.reshape(), numpy.flatten() +first_shape = np.array([(1,2,3), (4,5,6)]) +print(first_shape) +reshaped = first_shape.reshape(3,2) +print(reshaped) + +``` + +```sh + [[1 2 3] + [4 5 6]] + [[1 2] + [3 4] + [5 6]] +``` + +```py +flattened = reshaped.flatten() +flattened +``` + +```sh + array([1, 2, 3, 4, 5, 6]) +``` + +```py + ## Horitzontal Stack + np_list_one = np.array([1,2,3]) + np_list_two = np.array([4,5,6]) + + print(np_list_one + np_list_two) + + print('Horizontal Append:', np.hstack((np_list_one, np_list_two))) +``` + +```sh + [5 7 9] + Horizontal Append: [1 2 3 4 5 6] +``` + +```py + ## Vertical Stack + print('Vertical Append:', np.vstack((np_list_one, np_list_two))) +``` + +```sh + Vertical Append: [[1 2 3] + [4 5 6]] +``` + +#### Generating Random Numbers + +```py + # Generate a random float number + random_float = np.random.random() + random_float +``` + +```sh + 0.018929887384753874 +``` + +```py + # Generate a random float number + random_floats = np.random.random(5) + random_floats +``` + +```sh + array([0.26392192, 0.35842215, 0.87908478, 0.41902195, 0.78926418]) +``` + +```py + # Generating a random integers between 0 and 10 + + random_int = np.random.randint(0, 11) + random_int +``` + +```sh + 4 +``` + +```py + # Generating a random integers between 2 and 11, and creating a one row array + random_int = np.random.randint(2,10, size=4) + random_int +``` + +```sh + array([8, 8, 8, 2]) +``` + +```py + # Generating a random integers between 0 and 10 + random_int = np.random.randint(2,10, size=(3,3)) + random_int +``` + +```sh + array([[3, 5, 3], + [7, 3, 6], + [2, 3, 3]]) +``` + +### Generationg random numbers + +```py + # np.random.normal(mu, sigma, size) + normal_array = np.random.normal(79, 15, 80) + normal_array + +``` + +```sh + array([ 89.49990595, 82.06056961, 107.21445842, 38.69307086, + 47.85259157, 93.07381061, 76.40724259, 78.55675184, + 72.17358173, 47.9888899 , 65.10370622, 76.29696568, + 95.58234254, 68.14897213, 38.75862686, 122.5587927 , + 67.0762565 , 95.73990864, 81.97454563, 92.54264805, + 59.37035153, 77.76828101, 52.30752166, 64.43109931, + 62.63695351, 90.04616138, 75.70009094, 49.87586877, + 80.22002414, 68.56708848, 76.27791052, 67.24343975, + 81.86363935, 78.22703433, 102.85737041, 65.15700341, + 84.87033426, 76.7569997 , 64.61321853, 67.37244562, + 74.4068773 , 58.65119655, 71.66488727, 53.42458179, + 70.26872028, 60.96588544, 83.56129414, 72.14255326, + 81.00787609, 71.81264853, 72.64168853, 86.56608717, + 94.94667321, 82.32676973, 70.5165446 , 85.43061003, + 72.45526212, 87.34681775, 87.69911217, 103.02831489, + 75.28598596, 67.17806893, 92.41274447, 101.06662611, + 87.70013935, 70.73980645, 46.40368207, 50.17947092, + 61.75618542, 90.26191397, 78.63968639, 70.84550744, + 88.91826581, 103.91474733, 66.3064638 , 79.49726264, + 70.81087439, 83.90130623, 87.58555972, 59.95462521]) +``` + +## Numpy and Statistics + +```py +import matplotlib.pyplot as plt +import seaborn as sns +sns.set() +plt.hist(normal_array, color="grey", bins=50) +``` + +```sh + (array([2., 0., 0., 0., 1., 2., 2., 0., 2., 0., 0., 1., 2., 2., 1., 4., 3., + 4., 2., 7., 2., 2., 5., 4., 2., 4., 3., 2., 1., 5., 3., 0., 3., 2., + 1., 0., 0., 1., 3., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 1.]), + array([ 38.69307086, 40.37038529, 42.04769973, 43.72501417, + 45.4023286 , 47.07964304, 48.75695748, 50.43427191, + 52.11158635, 53.78890079, 55.46621523, 57.14352966, + 58.8208441 , 60.49815854, 62.17547297, 63.85278741, + 65.53010185, 67.20741628, 68.88473072, 70.56204516, + 72.23935959, 73.91667403, 75.59398847, 77.27130291, + 78.94861734, 80.62593178, 82.30324622, 83.98056065, + 85.65787509, 87.33518953, 89.01250396, 90.6898184 , + 92.36713284, 94.04444727, 95.72176171, 97.39907615, + 99.07639058, 100.75370502, 102.43101946, 104.1083339 , + 105.78564833, 107.46296277, 109.14027721, 110.81759164, + 112.49490608, 114.17222052, 115.84953495, 117.52684939, + 119.20416383, 120.88147826, 122.5587927 ]), + ) +``` + +### Matrix in numpy + +```py + +four_by_four_matrix = np.matrix(np.ones((4,4), dtype=float)) +``` + +```py +four_by_four_matrix +``` + +```sh +matrix([[1., 1., 1., 1.], + [1., 1., 1., 1.], + [1., 1., 1., 1.], + [1., 1., 1., 1.]]) +``` + +```py +np.asarray(four_by_four_matrix)[2] = 2 +four_by_four_matrix +``` + +```sh + +matrix([[1., 1., 1., 1.], + [1., 1., 1., 1.], + [2., 2., 2., 2.], + [1., 1., 1., 1.]]) +``` + +### Numpy numpy.arange() + +#### What is Arrange? + +Sometimes, you want to create values that are evenly spaced within a defined interval. For instance, you want to create values from 1 to 10; you can use numpy.arange() function + +```py +# creating list using range(starting, stop, step) +lst = range(0, 11, 2) +lst +``` + +```python +range(0, 11, 2) +``` + +```python +for l in lst: + print(l) +``` + +```sh 0 + 2 + 4 + 6 + 8 + 10 +``` + +```py +# Similar to range arange numpy.arange(start, stop, step) +whole_numbers = np.arange(0, 20, 1) +whole_numbers +``` + +```sh +array([ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, + 17, 18, 19]) +``` + +```py +natural_numbers = np.arange(1, 20, 1) +natural_numbers +``` + +```py +odd_numbers = np.arange(1, 20, 2) +odd_numbers +``` + +```sh + array([ 1, 3, 5, 7, 9, 11, 13, 15, 17, 19]) +``` + +```py +even_numbers = np.arange(2, 20, 2) +even_numbers +``` + +```sh + array([ 2, 4, 6, 8, 10, 12, 14, 16, 18]) +``` + +### Creating sequence of numbers using linspace + +```py +# numpy.linspace() +# numpy.logspace() in Python with Example +# For instance, it can be used to create 10 values from 1 to 5 evenly spaced. +np.linspace(1.0, 5.0, num=10) +``` + +```sh + array([1. , 1.44444444, 1.88888889, 2.33333333, 2.77777778, + 3.22222222, 3.66666667, 4.11111111, 4.55555556, 5. ]) +``` + +```py +# not to include the last value in the interval +np.linspace(1.0, 5.0, num=5, endpoint=False) +``` + +``` +array([1. , 1.8, 2.6, 3.4, 4.2]) +``` + +```py +# LogSpace +# LogSpace returns even spaced numbers on a log scale. Logspace has the same parameters as np.linspace. + +# Syntax: + +# numpy.logspace(start, stop, num, endpoint) + +np.logspace(2, 4.0, num=4) +``` + +```sh + +array([ 100. , 464.15888336, 2154.43469003, 10000. ]) +``` + +```py +# to check the size of an array +x = np.array([1,2,3], dtype=np.complex128) +``` + +```py +x +``` + +```sh + array([1.+0.j, 2.+0.j, 3.+0.j]) +``` + +```py +x.itemsize +``` + +```sh +16 +``` + +```py +# indexing and Slicing NumPy Arrays in Python +np_list = np.array([(1,2,3), (4,5,6)]) +np_list + +``` + +```sh + array([[1, 2, 3], + [4, 5, 6]]) +``` + +```py +print('First row: ', np_list[0]) +print('Second row: ', np_list[1]) + +``` + +```sh + + First row: [1 2 3] + Second row: [4 5 6] +``` + +```p +print('First column: ', np_list[:,0]) +print('Second column: ', np_list[:,1]) +print('Third column: ', np_list[:,2]) + +``` + +```sh + First column: [1 4] + Second column: [2 5] + Third column: [3 6] +``` + +### NumPy Statistical Functions with Example + +NumPy has quite useful statistical functions for finding minimum, maximum, mean, median, percentile,standard deviation and variance, etc from the given elements in the array. +The functions are explained as follows − +Statistical function +Numpy is equipped with the robust statistical function as listed below + +- Numpy Functions + - Min np.min() + - Max np.max() + - Mean np.mean() + - Median np.median() + - Varience + - Percentile + - Standard deviation np.std() + +```python +np_normal_dis = np.random.normal(5, 0.5, 100) +np_normal_dis +## min, max, mean, median, sd +print('min: ', two_dimension_array.min()) +print('max: ', two_dimension_array.max()) +print('mean: ',two_dimension_array.mean()) +# print('median: ', two_dimension_array.median()) +print('sd: ', two_dimension_array.std()) +``` + + min: 1 + max: 55 + mean: 14.777777777777779 + sd: 18.913709183069525 + +```python +min: 1 +max: 55 +mean: 14.777777777777779 +sd: 18.913709183069525 +``` + +```python +print(two_dimension_array) +print('Column with minimum: ', np.amin(two_dimension_array,axis=0)) +print('Column with maximum: ', np.amax(two_dimension_array,axis=0)) +print('=== Row ==') +print('Row with minimum: ', np.amin(two_dimension_array,axis=1)) +print('Row with maximum: ', np.amax(two_dimension_array,axis=1)) +``` + + [[ 1 2 3] + [ 4 55 44] + [ 7 8 9]] + Column with minimum: [1 2 3] + Column with maximum: [ 7 55 44] + === Row == + Row with minimum: [1 4 7] + Row with maximum: [ 3 55 9] + +### How to create repeating sequences? + +```python +a = [1,2,3] + +# Repeat whole of 'a' two times +print('Tile: ', np.tile(a, 2)) + +# Repeat each element of 'a' two times +print('Repeat: ', np.repeat(a, 2)) + +``` + + Tile: [1 2 3 1 2 3] + Repeat: [1 1 2 2 3 3] + +### How to generate random numbers? + +```python +# One random number between [0,1) +one_random_num = np.random.random() +one_random_in = np.random +print(one_random_num) +``` + + 0.6149403282678213 + +```python +0.4763968133790438 +``` + + 0.4763968133790438 + +```python +# Random numbers between [0,1) of shape 2,3 +r = np.random.random(size=[2,3]) +print(r) +``` + + [[0.13031737 0.4429537 0.1129527 ] + [0.76811539 0.88256594 0.6754075 ]] + +```python +print(np.random.choice(['a', 'e', 'i', 'o', 'u'], size=10)) +``` + + ['u' 'o' 'o' 'i' 'e' 'e' 'u' 'o' 'u' 'a'] + +```python +['i' 'u' 'e' 'o' 'a' 'i' 'e' 'u' 'o' 'i'] +``` + + ['iueoaieuoi'] + +```python +## Random numbers between [0, 1] of shape 2, 2 +rand = np.random.rand(2,2) +rand +``` + + array([[0.97992598, 0.79642484], + [0.65263629, 0.55763145]]) + +```python +rand2 = np.random.randn(2,2) +rand2 + +``` + + array([[ 1.65593322, -0.52326621], + [ 0.39071179, -2.03649407]]) + +```python +# Random integers between [0, 10) of shape 2,5 +rand_int = np.random.randint(0, 10, size=[5,3]) +rand_int +``` + + array([[0, 7, 5], + [4, 1, 4], + [3, 5, 3], + [4, 3, 8], + [4, 6, 7]]) + +```py +from scipy import stats +np_normal_dis = np.random.normal(5, 0.5, 1000) # mean, standard deviation, number of samples +np_normal_dis +## min, max, mean, median, sd +print('min: ', np.min(np_normal_dis)) +print('max: ', np.max(np_normal_dis)) +print('mean: ', np.mean(np_normal_dis)) +print('median: ', np.median(np_normal_dis)) +print('mode: ', stats.mode(np_normal_dis)) +print('sd: ', np.std(np_normal_dis)) +``` + +```sh + + min: 3.557811005458804 + max: 6.876317743643499 + mean: 5.035832048106663 + median: 5.020161980441937 + mode: ModeResult(mode=array([3.55781101]), count=array([1])) + sd: 0.489682424165213 + +``` + +```python +plt.hist(np_normal_dis, color="grey", bins=21) +plt.show() +``` + +![png](../test_files/test_121_0.png) + +```python +# numpy.dot(): Dot Product in Python using Numpy +# Dot Product +# Numpy is powerful library for matrices computation. For instance, you can compute the dot product with np.dot + +# Syntax + +# numpy.dot(x, y, out=None) +``` + +### Linear Algebra + +1. Dot Product + +```python +## Linear algebra +### Dot product: product of two arrays +f = np.array([1,2,3]) +g = np.array([4,5,3]) +### 1*4+2*5 + 3*6 +np.dot(f, g) # 23 +``` + +### NumPy Matrix Multiplication with np.matmul() + +```python +### Matmul: matruc product of two arrays +h = [[1,2],[3,4]] +i = [[5,6],[7,8]] +### 1*5+2*7 = 19 +np.matmul(h, i) +``` + +```sh + array([[19, 22], + [43, 50]]) + +``` + +```py +## Determinant 2*2 matrix +### 5*8-7*6np.linalg.det(i) +``` + +```python +np.linalg.det(i) +``` + + -1.999999999999999 + +```python +Z = np.zeros((8,8)) +Z[1::2,::2] = 1 +Z[::2,1::2] = 1 +``` + +```python +Z +``` + + array([[0., 1., 0., 1., 0., 1., 0., 1.], + [1., 0., 1., 0., 1., 0., 1., 0.], + [0., 1., 0., 1., 0., 1., 0., 1.], + [1., 0., 1., 0., 1., 0., 1., 0.], + [0., 1., 0., 1., 0., 1., 0., 1.], + [1., 0., 1., 0., 1., 0., 1., 0.], + [0., 1., 0., 1., 0., 1., 0., 1.], + [1., 0., 1., 0., 1., 0., 1., 0.]]) + +```python +new_list = [ x + 2 for x in range(0, 11)] +``` + +```python +new_list +``` + + [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + +```python +[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] +``` + + [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12] + +```python +np_arr = np.array(range(0, 11)) +np_arr + 2 +``` + +array([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]) + +We use linear equation for quantities which have linear relationship. Let's see the example below: + +```python +temp = np.array([1,2,3,4,5]) +pressure = temp * 2 + 5 +pressure +``` + +array([ 7, 9, 11, 13, 15]) + +```python +plt.plot(temp,pressure) +plt.xlabel('Temperature in oC') +plt.ylabel('Pressure in atm') +plt.title('Temperature vs Pressure') +plt.xticks(np.arange(0, 6, step=0.5)) +plt.show() +``` + +![png](../test_files/test_141_0.png) + +To draw the Gaussian normal distribution using numpy. As you can see below, the numpy can generate random numbers. To create random sample, we need the mean(mu), sigma(standard deviation), mumber of data points. + +```python +mu = 28 +sigma = 15 +samples = 100000 + +x = np.random.normal(mu, sigma, samples) +ax = sns.distplot(x); +ax.set(xlabel="x", ylabel='y') +plt.show() +``` + +![png](../test_files/test_143_0.png) + +# Summery + +To summarize, the main differences with python lists are: + +1. Arrays support vectorized operations, while lists don’t. +1. Once an array is created, you cannot change its size. You will have to create a new array or overwrite the existing one. +1. Every array has one and only one dtype. All items in it should be of that dtype. +1. An equivalent numpy array occupies much less space than a python list of lists. +1. numpy arrays support boolean indexing. + +## 💻 Exercises: Day 24 + +1. Repeat all the examples + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 23](../23_Day_Virtual_environment/23_virtual_environment.md) | [Day 25 >>](../25_Day_Pandas/25_pandas.md) diff --git a/24_statistics/index.html b/24_statistics/index.html new file mode 100644 index 0000000..75e9c96 --- /dev/null +++ b/24_statistics/index.html @@ -0,0 +1,2075 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 24 statistics - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 24 - Statistics

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+
+ +

<< Day 23 | Day 25 >>

+

30DaysOfPython

+ +

📘 Day 24⚓︎

+

Python for Statistical Analysis⚓︎

+

Statistics⚓︎

+

Statistics is the discipline that studies the collection, organization, displaying, analysing, interpretation and presentation of data. +Statistics is a branch of Mathematics that is recommended to be a prerequisite for data science and machine learning. Statistics is a very broad field but we will focus in this section only on the most relevant part. +After completing this challenge, you may go onto the web development, data analysis, machine learning and data science path. Whatever path you may follow, at some point in your career you will get data which you may work on. Having some statistical knowledge will help you to make decisions based on data, data tells as they say.

+

Data⚓︎

+

What is data? Data is any set of characters that is gathered and translated for some purpose, usually analysis. It can be any character, including text and numbers, pictures, sound, or video. If data is not put in a context, it doesn't make any sense to a human or computer. To make sense from data we need to work on the data using different tools.

+

The work flow of data analysis, data science or machine learning starts from data. Data can be provided from some data source or it can be created. There are structured and unstructured data.

+

Data can be found in small or big format. Most of the data types we will get have been covered in the file handling section.

+

Statistics Module⚓︎

+

The Python statistics module provides functions for calculating mathematical statistics of numerical data. The module is not intended to be a competitor to third-party libraries such as NumPy, SciPy, or proprietary full-featured statistics packages aimed at professional statisticians such as Minitab, SAS and Matlab. It is aimed at the level of graphing and scientific calculators.

+

NumPy⚓︎

+

In the first section we defined Python as a great general-purpose programming language on its own, but with the help of other popular libraries as(numpy, scipy, matplotlib, pandas etc) it becomes a powerful environment for scientific computing.

+

NumPy is the core library for scientific computing in Python. It provides a high-performance multidimensional array object, and tools for working with arrays.

+

So far, we have been using vscode but from now on I would recommend using Jupyter Notebook. To access jupyter notebook let's install anaconda. If you are using anaconda most of the common packages are included and you don't have install packages if you installed anaconda.

+
asabeneh@Asabeneh:~/Desktop/30DaysOfPython$ pip install numpy
+
+

Importing NumPy⚓︎

+

Jupyter notebook is available if your are in favor of jupyter notebook

+
    # How to import numpy
+    import numpy as np
+    # How to check the version of the numpy package
+    print('numpy:', np.__version__)
+    # Checking the available methods
+    print(dir(np))
+
+

Creating numpy array using⚓︎

+

Creating int numpy arrays⚓︎

+
    # Creating python List
+    python_list = [1,2,3,4,5]
+
+    # Checking data types
+    print('Type:', type (python_list)) # <class 'list'>
+    #
+    print(python_list) # [1, 2, 3, 4, 5]
+
+    two_dimensional_list = [[0,1,2], [3,4,5], [6,7,8]]
+
+    print(two_dimensional_list)  # [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
+
+    # Creating Numpy(Numerical Python) array from python list
+
+    numpy_array_from_list = np.array(python_list)
+    print(type (numpy_array_from_list))   # <class 'numpy.ndarray'>
+    print(numpy_array_from_list) # array([1, 2, 3, 4, 5])
+
+

Creating float numpy arrays⚓︎

+

Creating a float numpy array from list with a float data type parameter

+
    # Python list
+    python_list = [1,2,3,4,5]
+
+    numy_array_from_list2 = np.array(python_list, dtype=float)
+    print(numy_array_from_list2) # array([1., 2., 3., 4., 5.])
+
+

Creating boolean numpy arrays⚓︎

+

Creating a boolean a numpy array from list

+
    numpy_bool_array = np.array([0, 1, -1, 0, 0], dtype=bool)
+    print(numpy_bool_array) # array([False,  True,  True, False, False])
+
+

Creating multidimensional array using numpy⚓︎

+

A numpy array may have one or multiple rows and columns

+
    two_dimensional_list = [[0,1,2], [3,4,5], [6,7,8]]
+    numpy_two_dimensional_list = np.array(two_dimensional_list)
+    print(type (numpy_two_dimensional_list))
+    print(numpy_two_dimensional_list)
+
+
    <class 'numpy.ndarray'>
+    [[0 1 2]
+     [3 4 5]
+     [6 7 8]]
+
+

Converting numpy array to list⚓︎

+
# We can always convert an array back to a python list using tolist().
+np_to_list = numpy_array_from_list.tolist()
+print(type (np_to_list))
+print('one dimensional array:', np_to_list)
+print('two dimensional array: ', numpy_two_dimensional_list.tolist())
+
+
    <class 'list'>
+    one dimensional array: [1, 2, 3, 4, 5]
+    two dimensional array:  [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
+
+

Creating numpy array from tuple⚓︎

+
# Numpy array from tuple
+# Creating tuple in Python
+python_tuple = (1,2,3,4,5)
+print(type (python_tuple)) # <class 'tuple'>
+print('python_tuple: ', python_tuple) # python_tuple:  (1, 2, 3, 4, 5)
+
+numpy_array_from_tuple = np.array(python_tuple)
+print(type (numpy_array_from_tuple)) # <class 'numpy.ndarray'>
+print('numpy_array_from_tuple: ', numpy_array_from_tuple) # numpy_array_from_tuple:  [1 2 3 4 5]
+
+

Shape of numpy array⚓︎

+

The shape method provide the shape of the array as a tuple. The first is the row and the second is the column. If the array is just one dimensional it returns the size of the array.

+
    nums = np.array([1, 2, 3, 4, 5])
+    print(nums)
+    print('shape of nums: ', nums.shape)
+    print(numpy_two_dimensional_list)
+    print('shape of numpy_two_dimensional_list: ', numpy_two_dimensional_list.shape)
+    three_by_four_array = np.array([[0, 1, 2, 3],
+        [4,5,6,7],
+        [8,9,10, 11]])
+    print(three_by_four_array.shape)
+
+
    [1 2 3 4 5]
+    shape of nums:  (5,)
+    [[0 1 2]
+     [3 4 5]
+     [6 7 8]]
+    shape of numpy_two_dimensional_list:  (3, 3)
+    (3, 4)
+
+

Data type of numpy array⚓︎

+

Type of data types: str, int, float, complex, bool, list, None

+
int_lists = [-3, -2, -1, 0, 1, 2,3]
+int_array = np.array(int_lists)
+float_array = np.array(int_lists, dtype=float)
+
+print(int_array)
+print(int_array.dtype)
+print(float_array)
+print(float_array.dtype)
+
+
    [-3 -2 -1  0  1  2  3]
+    int64
+    [-3. -2. -1.  0.  1.  2.  3.]
+    float64
+
+

Size of a numpy array⚓︎

+

In numpy to know the number of items in a numpy array list we use size

+
numpy_array_from_list = np.array([1, 2, 3, 4, 5])
+two_dimensional_list = np.array([[0, 1, 2],
+                              [3, 4, 5],
+                              [6, 7, 8]])
+
+print('The size:', numpy_array_from_list.size) # 5
+print('The size:', two_dimensional_list.size)  # 3
+
+
    The size: 5
+    The size: 9
+
+

Mathematical Operation using numpy⚓︎

+

NumPy array is not like exactly like python list. To do mathematical operation in Python list we have to loop through the items but numpy can allow to do any mathematical operation without looping. +Mathematical Operation:

+
    +
  • Addition (+)
  • +
  • Subtraction (-)
  • +
  • Multiplication (*)
  • +
  • Division (/)
  • +
  • Modules (%)
  • +
  • Floor Division(//)
  • +
  • Exponential(**)
  • +
+

Addition⚓︎

+
# Mathematical Operation
+# Addition
+numpy_array_from_list = np.array([1, 2, 3, 4, 5])
+print('original array: ', numpy_array_from_list)
+ten_plus_original = numpy_array_from_list  + 10
+print(ten_plus_original)
+
+
    original array:  [1 2 3 4 5]
+    [11 12 13 14 15]
+
+

Subtraction⚓︎

+
# Subtraction
+numpy_array_from_list = np.array([1, 2, 3, 4, 5])
+print('original array: ', numpy_array_from_list)
+ten_minus_original = numpy_array_from_list  - 10
+print(ten_minus_original)
+
+
    original array:  [1 2 3 4 5]
+    [-9 -8 -7 -6 -5]
+
+

Multiplication⚓︎

+
# Multiplication
+numpy_array_from_list = np.array([1, 2, 3, 4, 5])
+print('original array: ', numpy_array_from_list)
+ten_times_original = numpy_array_from_list * 10
+print(ten_times_original)
+
+
    original array:  [1 2 3 4 5]
+    [10 20 30 40 50]
+
+

Division⚓︎

+
# Division
+numpy_array_from_list = np.array([1, 2, 3, 4, 5])
+print('original array: ', numpy_array_from_list)
+ten_times_original = numpy_array_from_list / 10
+print(ten_times_original)
+
+
    original array:  [1 2 3 4 5]
+    [0.1 0.2 0.3 0.4 0.5]
+
+

Modulus⚓︎

+
# Modulus; Finding the remainder
+numpy_array_from_list = np.array([1, 2, 3, 4, 5])
+print('original array: ', numpy_array_from_list)
+ten_times_original = numpy_array_from_list % 3
+print(ten_times_original)
+
+
    original array:  [1 2 3 4 5]
+    [1 2 0 1 2]
+
+

Floor Division⚓︎

+
# Floor division: the division result without the remainder
+numpy_array_from_list = np.array([1, 2, 3, 4, 5])
+print('original array: ', numpy_array_from_list)
+ten_times_original = numpy_array_from_list // 10
+print(ten_times_original)
+
+

Exponential⚓︎

+
# Exponential is finding some number the power of another:
+numpy_array_from_list = np.array([1, 2, 3, 4, 5])
+print('original array: ', numpy_array_from_list)
+ten_times_original = numpy_array_from_list  ** 2
+print(ten_times_original)
+
+
    original array:  [1 2 3 4 5]
+    [ 1  4  9 16 25]
+
+

Checking data types⚓︎

+
#Int,  Float numbers
+numpy_int_arr = np.array([1,2,3,4])
+numpy_float_arr = np.array([1.1, 2.0,3.2])
+numpy_bool_arr = np.array([-3, -2, 0, 1,2,3], dtype='bool')
+
+print(numpy_int_arr.dtype)
+print(numpy_float_arr.dtype)
+print(numpy_bool_arr.dtype)
+
+
    int64
+    float64
+    bool
+
+

Converting types⚓︎

+

We can convert the data types of numpy array

+
    +
  1. Int to Float
  2. +
+
numpy_int_arr = np.array([1,2,3,4], dtype = 'float')
+numpy_int_arr
+
+
array([1., 2., 3., 4.])
+
+
    +
  1. Float to Int
  2. +
+
numpy_int_arr = np.array([1., 2., 3., 4.], dtype = 'int')
+numpy_int_arr
+
+
    array([1, 2, 3, 4])
+
+
    +
  1. Int ot boolean
  2. +
+
np.array([-3, -2, 0, 1,2,3], dtype='bool')
+
+
    array([ True,  True, False,  True,  True,  True])
+
+
    +
  1. Int to str
  2. +
+
numpy_float_list.astype('int').astype('str')
+
+
    array(['1', '2', '3'], dtype='<U21')
+
+

Multi-dimensional Arrays⚓︎

+
# 2 Dimension Array
+two_dimension_array = np.array([(1,2,3),(4,5,6), (7,8,9)])
+print(type (two_dimension_array))
+print(two_dimension_array)
+print('Shape: ', two_dimension_array.shape)
+print('Size:', two_dimension_array.size)
+print('Data type:', two_dimension_array.dtype)
+
+
    <class 'numpy.ndarray'>
+    [[1 2 3]
+     [4 5 6]
+     [7 8 9]]
+    Shape:  (3, 3)
+    Size: 9
+    Data type: int64
+
+

Getting items from a numpy array⚓︎

+
# 2 Dimension Array
+two_dimension_array = np.array([[1,2,3],[4,5,6], [7,8,9]])
+first_row = two_dimension_array[0]
+second_row = two_dimension_array[1]
+third_row = two_dimension_array[2]
+print('First row:', first_row)
+print('Second row:', second_row)
+print('Third row: ', third_row)
+
+
    First row: [1 2 3]
+    Second row: [4 5 6]
+    Third row:  [7 8 9]
+
+
first_column= two_dimension_array[:,0]
+second_column = two_dimension_array[:,1]
+third_column = two_dimension_array[:,2]
+print('First column:', first_column)
+print('Second column:', second_column)
+print('Third column: ', third_column)
+print(two_dimension_array)
+
+
    First column: [1 4 7]
+    Second column: [2 5 8]
+    Third column:  [3 6 9]
+    [[1 2 3]
+     [4 5 6]
+     [7 8 9]]
+
+

Slicing Numpy array⚓︎

+

Slicing in numpy is similar to slicing in python list

+
two_dimension_array = np.array([[1,2,3],[4,5,6], [7,8,9]])
+first_two_rows_and_columns = two_dimension_array[0:2, 0:2]
+print(first_two_rows_and_columns)
+
+
    [[1 2]
+     [4 5]]
+
+

How to reverse the rows and the whole array?⚓︎

+
two_dimension_array[::]
+
+
    array([[1, 2, 3],
+           [4, 5, 6],
+           [7, 8, 9]])
+
+

Reverse the row and column positions⚓︎

+
    two_dimension_array = np.array([[1,2,3],[4,5,6], [7,8,9]])
+    two_dimension_array[::-1,::-1]
+
+
    array([[9, 8, 7],
+           [6, 5, 4],
+           [3, 2, 1]])
+
+

How to represent missing values ?⚓︎

+
    print(two_dimension_array)
+    two_dimension_array[1,1] = 55
+    two_dimension_array[1,2] =44
+    print(two_dimension_array)
+
+
    [[1 2 3]
+     [4 5 6]
+     [7 8 9]]
+    [[ 1  2  3]
+     [ 4 55 44]
+     [ 7  8  9]]
+
+
    # Numpy Zeroes
+    # numpy.zeros(shape, dtype=float, order='C')
+    numpy_zeroes = np.zeros((3,3),dtype=int,order='C')
+    numpy_zeroes
+
+
    array([[0, 0, 0],
+           [0, 0, 0],
+           [0, 0, 0]])
+
+
# Numpy Zeroes
+numpy_ones = np.ones((3,3),dtype=int,order='C')
+print(numpy_ones)
+
+
    [[1 1 1]
+     [1 1 1]
+     [1 1 1]]
+
+
twoes = numpy_ones * 2
+
+
# Reshape
+# numpy.reshape(), numpy.flatten()
+first_shape  = np.array([(1,2,3), (4,5,6)])
+print(first_shape)
+reshaped = first_shape.reshape(3,2)
+print(reshaped)
+
+
    [[1 2 3]
+     [4 5 6]]
+    [[1 2]
+     [3 4]
+     [5 6]]
+
+
flattened = reshaped.flatten()
+flattened
+
+
    array([1, 2, 3, 4, 5, 6])
+
+
    ## Horitzontal Stack
+    np_list_one = np.array([1,2,3])
+    np_list_two = np.array([4,5,6])
+
+    print(np_list_one + np_list_two)
+
+    print('Horizontal Append:', np.hstack((np_list_one, np_list_two)))
+
+
    [5 7 9]
+    Horizontal Append: [1 2 3 4 5 6]
+
+
    ## Vertical Stack
+    print('Vertical Append:', np.vstack((np_list_one, np_list_two)))
+
+
    Vertical Append: [[1 2 3]
+     [4 5 6]]
+
+

Generating Random Numbers⚓︎

+
    # Generate a random float  number
+    random_float = np.random.random()
+    random_float
+
+
    0.018929887384753874
+
+
    # Generate a random float  number
+    random_floats = np.random.random(5)
+    random_floats
+
+
    array([0.26392192, 0.35842215, 0.87908478, 0.41902195, 0.78926418])
+
+
    # Generating a random integers between 0 and 10
+
+    random_int = np.random.randint(0, 11)
+    random_int
+
+
    4
+
+
    # Generating a random integers between 2 and 11, and creating a one row array
+    random_int = np.random.randint(2,10, size=4)
+    random_int
+
+
    array([8, 8, 8, 2])
+
+
    # Generating a random integers between 0 and 10
+    random_int = np.random.randint(2,10, size=(3,3))
+    random_int
+
+
    array([[3, 5, 3],
+           [7, 3, 6],
+           [2, 3, 3]])
+
+

Generationg random numbers⚓︎

+
    # np.random.normal(mu, sigma, size)
+    normal_array = np.random.normal(79, 15, 80)
+    normal_array
+
+
    array([ 89.49990595,  82.06056961, 107.21445842,  38.69307086,
+            47.85259157,  93.07381061,  76.40724259,  78.55675184,
+            72.17358173,  47.9888899 ,  65.10370622,  76.29696568,
+            95.58234254,  68.14897213,  38.75862686, 122.5587927 ,
+            67.0762565 ,  95.73990864,  81.97454563,  92.54264805,
+            59.37035153,  77.76828101,  52.30752166,  64.43109931,
+            62.63695351,  90.04616138,  75.70009094,  49.87586877,
+            80.22002414,  68.56708848,  76.27791052,  67.24343975,
+            81.86363935,  78.22703433, 102.85737041,  65.15700341,
+            84.87033426,  76.7569997 ,  64.61321853,  67.37244562,
+            74.4068773 ,  58.65119655,  71.66488727,  53.42458179,
+            70.26872028,  60.96588544,  83.56129414,  72.14255326,
+            81.00787609,  71.81264853,  72.64168853,  86.56608717,
+            94.94667321,  82.32676973,  70.5165446 ,  85.43061003,
+            72.45526212,  87.34681775,  87.69911217, 103.02831489,
+            75.28598596,  67.17806893,  92.41274447, 101.06662611,
+            87.70013935,  70.73980645,  46.40368207,  50.17947092,
+            61.75618542,  90.26191397,  78.63968639,  70.84550744,
+            88.91826581, 103.91474733,  66.3064638 ,  79.49726264,
+            70.81087439,  83.90130623,  87.58555972,  59.95462521])
+
+

Numpy and Statistics⚓︎

+
import matplotlib.pyplot as plt
+import seaborn as sns
+sns.set()
+plt.hist(normal_array, color="grey", bins=50)
+
+
    (array([2., 0., 0., 0., 1., 2., 2., 0., 2., 0., 0., 1., 2., 2., 1., 4., 3.,
+            4., 2., 7., 2., 2., 5., 4., 2., 4., 3., 2., 1., 5., 3., 0., 3., 2.,
+            1., 0., 0., 1., 3., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 1.]),
+     array([ 38.69307086,  40.37038529,  42.04769973,  43.72501417,
+             45.4023286 ,  47.07964304,  48.75695748,  50.43427191,
+             52.11158635,  53.78890079,  55.46621523,  57.14352966,
+             58.8208441 ,  60.49815854,  62.17547297,  63.85278741,
+             65.53010185,  67.20741628,  68.88473072,  70.56204516,
+             72.23935959,  73.91667403,  75.59398847,  77.27130291,
+             78.94861734,  80.62593178,  82.30324622,  83.98056065,
+             85.65787509,  87.33518953,  89.01250396,  90.6898184 ,
+             92.36713284,  94.04444727,  95.72176171,  97.39907615,
+             99.07639058, 100.75370502, 102.43101946, 104.1083339 ,
+            105.78564833, 107.46296277, 109.14027721, 110.81759164,
+            112.49490608, 114.17222052, 115.84953495, 117.52684939,
+            119.20416383, 120.88147826, 122.5587927 ]),
+     <a list of 50 Patch objects>)
+
+

Matrix in numpy⚓︎

+
four_by_four_matrix = np.matrix(np.ones((4,4), dtype=float))
+
+
four_by_four_matrix
+
+
matrix([[1., 1., 1., 1.],
+            [1., 1., 1., 1.],
+            [1., 1., 1., 1.],
+            [1., 1., 1., 1.]])
+
+
np.asarray(four_by_four_matrix)[2] = 2
+four_by_four_matrix
+
+
matrix([[1., 1., 1., 1.],
+            [1., 1., 1., 1.],
+            [2., 2., 2., 2.],
+            [1., 1., 1., 1.]])
+
+

Numpy numpy.arange()⚓︎

+

What is Arrange?⚓︎

+

Sometimes, you want to create values that are evenly spaced within a defined interval. For instance, you want to create values from 1 to 10; you can use numpy.arange() function

+
# creating list using range(starting, stop, step)
+lst = range(0, 11, 2)
+lst
+
+
range(0, 11, 2)
+
+
for l in lst:
+    print(l)
+
+

```sh 0 + 2 + 4 + 6 + 8 + 10 +

```py
+# Similar to range arange numpy.arange(start, stop, step)
+whole_numbers = np.arange(0, 20, 1)
+whole_numbers
+

+
array([ 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15, 16,
+           17, 18, 19])
+
+
natural_numbers = np.arange(1, 20, 1)
+natural_numbers
+
+
odd_numbers = np.arange(1, 20, 2)
+odd_numbers
+
+
    array([ 1,  3,  5,  7,  9, 11, 13, 15, 17, 19])
+
+
even_numbers = np.arange(2, 20, 2)
+even_numbers
+
+
    array([ 2,  4,  6,  8, 10, 12, 14, 16, 18])
+
+

Creating sequence of numbers using linspace⚓︎

+
# numpy.linspace()
+# numpy.logspace() in Python with Example
+# For instance, it can be used to create 10 values from 1 to 5 evenly spaced.
+np.linspace(1.0, 5.0, num=10)
+
+
    array([1.        , 1.44444444, 1.88888889, 2.33333333, 2.77777778,
+           3.22222222, 3.66666667, 4.11111111, 4.55555556, 5.        ])
+
+
# not to include the last value in the interval
+np.linspace(1.0, 5.0, num=5, endpoint=False)
+
+
array([1. , 1.8, 2.6, 3.4, 4.2])
+
+
# LogSpace
+# LogSpace returns even spaced numbers on a log scale. Logspace has the same parameters as np.linspace.
+
+# Syntax:
+
+# numpy.logspace(start, stop, num, endpoint)
+
+np.logspace(2, 4.0, num=4)
+
+
array([  100.        ,   464.15888336,  2154.43469003, 10000.        ])
+
+
# to check the size of an array
+x = np.array([1,2,3], dtype=np.complex128)
+
+
x
+
+
    array([1.+0.j, 2.+0.j, 3.+0.j])
+
+
x.itemsize
+
+
16
+
+
# indexing and Slicing NumPy Arrays in Python
+np_list = np.array([(1,2,3), (4,5,6)])
+np_list
+
+
    array([[1, 2, 3],
+           [4, 5, 6]])
+
+
print('First row: ', np_list[0])
+print('Second row: ', np_list[1])
+
+
    First row:  [1 2 3]
+    Second row:  [4 5 6]
+
+
print('First column: ', np_list[:,0])
+print('Second column: ', np_list[:,1])
+print('Third column: ', np_list[:,2])
+
+
    First column:  [1 4]
+    Second column:  [2 5]
+    Third column:  [3 6]
+
+

NumPy Statistical Functions with Example⚓︎

+

NumPy has quite useful statistical functions for finding minimum, maximum, mean, median, percentile,standard deviation and variance, etc from the given elements in the array. +The functions are explained as follows − +Statistical function +Numpy is equipped with the robust statistical function as listed below

+
    +
  • Numpy Functions
  • +
  • Min np.min()
  • +
  • Max np.max()
  • +
  • Mean np.mean()
  • +
  • Median np.median()
  • +
  • Varience
  • +
  • Percentile
  • +
  • Standard deviation np.std()
  • +
+
np_normal_dis = np.random.normal(5, 0.5, 100)
+np_normal_dis
+## min, max, mean, median, sd
+print('min: ', two_dimension_array.min())
+print('max: ', two_dimension_array.max())
+print('mean: ',two_dimension_array.mean())
+# print('median: ', two_dimension_array.median())
+print('sd: ', two_dimension_array.std())
+
+
min:  1
+max:  55
+mean:  14.777777777777779
+sd:  18.913709183069525
+
+
min:  1
+max:  55
+mean:  14.777777777777779
+sd:  18.913709183069525
+
+
print(two_dimension_array)
+print('Column with minimum: ', np.amin(two_dimension_array,axis=0))
+print('Column with maximum: ', np.amax(two_dimension_array,axis=0))
+print('=== Row ==')
+print('Row with minimum: ', np.amin(two_dimension_array,axis=1))
+print('Row with maximum: ', np.amax(two_dimension_array,axis=1))
+
+
[[ 1  2  3]
+ [ 4 55 44]
+ [ 7  8  9]]
+Column with minimum:  [1 2 3]
+Column with maximum:  [ 7 55 44]
+=== Row ==
+Row with minimum:  [1 4 7]
+Row with maximum:  [ 3 55  9]
+
+

How to create repeating sequences?⚓︎

+
a = [1,2,3]
+
+# Repeat whole of 'a' two times
+print('Tile:   ', np.tile(a, 2))
+
+# Repeat each element of 'a' two times
+print('Repeat: ', np.repeat(a, 2))
+
+
Tile:    [1 2 3 1 2 3]
+Repeat:  [1 1 2 2 3 3]
+
+

How to generate random numbers?⚓︎

+
# One random number between [0,1)
+one_random_num = np.random.random()
+one_random_in = np.random
+print(one_random_num)
+
+
0.6149403282678213
+
+
0.4763968133790438
+
+
0.4763968133790438
+
+
# Random numbers between [0,1) of shape 2,3
+r = np.random.random(size=[2,3])
+print(r)
+
+
[[0.13031737 0.4429537  0.1129527 ]
+ [0.76811539 0.88256594 0.6754075 ]]
+
+
print(np.random.choice(['a', 'e', 'i', 'o', 'u'], size=10))
+
+
['u' 'o' 'o' 'i' 'e' 'e' 'u' 'o' 'u' 'a']
+
+
['i' 'u' 'e' 'o' 'a' 'i' 'e' 'u' 'o' 'i']
+
+
['iueoaieuoi']
+
+
## Random numbers between [0, 1] of shape 2, 2
+rand = np.random.rand(2,2)
+rand
+
+
array([[0.97992598, 0.79642484],
+       [0.65263629, 0.55763145]])
+
+
rand2 = np.random.randn(2,2)
+rand2
+
+
array([[ 1.65593322, -0.52326621],
+       [ 0.39071179, -2.03649407]])
+
+
# Random integers between [0, 10) of shape 2,5
+rand_int = np.random.randint(0, 10, size=[5,3])
+rand_int
+
+
array([[0, 7, 5],
+       [4, 1, 4],
+       [3, 5, 3],
+       [4, 3, 8],
+       [4, 6, 7]])
+
+
from scipy import stats
+np_normal_dis = np.random.normal(5, 0.5, 1000) # mean, standard deviation, number of samples
+np_normal_dis
+## min, max, mean, median, sd
+print('min: ', np.min(np_normal_dis))
+print('max: ', np.max(np_normal_dis))
+print('mean: ', np.mean(np_normal_dis))
+print('median: ', np.median(np_normal_dis))
+print('mode: ', stats.mode(np_normal_dis))
+print('sd: ', np.std(np_normal_dis))
+
+
    min:  3.557811005458804
+    max:  6.876317743643499
+    mean:  5.035832048106663
+    median:  5.020161980441937
+    mode:  ModeResult(mode=array([3.55781101]), count=array([1]))
+    sd:  0.489682424165213
+
+
plt.hist(np_normal_dis, color="grey", bins=21)
+plt.show()
+
+

png

+
# numpy.dot(): Dot Product in Python using Numpy
+# Dot Product
+# Numpy is powerful library for matrices computation. For instance, you can compute the dot product with np.dot
+
+# Syntax
+
+# numpy.dot(x, y, out=None)
+
+

Linear Algebra⚓︎

+
    +
  1. Dot Product
  2. +
+
## Linear algebra
+### Dot product: product of two arrays
+f = np.array([1,2,3])
+g = np.array([4,5,3])
+### 1*4+2*5 + 3*6
+np.dot(f, g)  # 23
+
+

NumPy Matrix Multiplication with np.matmul()⚓︎

+
### Matmul: matruc product of two arrays
+h = [[1,2],[3,4]]
+i = [[5,6],[7,8]]
+### 1*5+2*7 = 19
+np.matmul(h, i)
+
+
    array([[19, 22],
+           [43, 50]])
+
+
## Determinant 2*2 matrix
+### 5*8-7*6np.linalg.det(i)
+
+
np.linalg.det(i)
+
+
-1.999999999999999
+
+
Z = np.zeros((8,8))
+Z[1::2,::2] = 1
+Z[::2,1::2] = 1
+
+
Z
+
+
array([[0., 1., 0., 1., 0., 1., 0., 1.],
+       [1., 0., 1., 0., 1., 0., 1., 0.],
+       [0., 1., 0., 1., 0., 1., 0., 1.],
+       [1., 0., 1., 0., 1., 0., 1., 0.],
+       [0., 1., 0., 1., 0., 1., 0., 1.],
+       [1., 0., 1., 0., 1., 0., 1., 0.],
+       [0., 1., 0., 1., 0., 1., 0., 1.],
+       [1., 0., 1., 0., 1., 0., 1., 0.]])
+
+
new_list = [ x + 2 for x in range(0, 11)]
+
+
new_list
+
+
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+
+
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+
+
[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]
+
+
np_arr = np.array(range(0, 11))
+np_arr + 2
+
+

array([ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])

+

We use linear equation for quantities which have linear relationship. Let's see the example below:

+
temp = np.array([1,2,3,4,5])
+pressure = temp * 2 + 5
+pressure
+
+

array([ 7, 9, 11, 13, 15])

+
plt.plot(temp,pressure)
+plt.xlabel('Temperature in oC')
+plt.ylabel('Pressure in atm')
+plt.title('Temperature vs Pressure')
+plt.xticks(np.arange(0, 6, step=0.5))
+plt.show()
+
+

png

+

To draw the Gaussian normal distribution using numpy. As you can see below, the numpy can generate random numbers. To create random sample, we need the mean(mu), sigma(standard deviation), mumber of data points.

+
mu = 28
+sigma = 15
+samples = 100000
+
+x = np.random.normal(mu, sigma, samples)
+ax = sns.distplot(x);
+ax.set(xlabel="x", ylabel='y')
+plt.show()
+
+

png

+

Summery⚓︎

+

To summarize, the main differences with python lists are:

+
    +
  1. Arrays support vectorized operations, while lists don’t.
  2. +
  3. Once an array is created, you cannot change its size. You will have to create a new array or overwrite the existing one.
  4. +
  5. Every array has one and only one dtype. All items in it should be of that dtype.
  6. +
  7. An equivalent numpy array occupies much less space than a python list of lists.
  8. +
  9. numpy arrays support boolean indexing.
  10. +
+

💻 Exercises: Day 24⚓︎

+
    +
  1. Repeat all the examples
  2. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 23 | Day 25 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/25_pandas/25_pandas.md b/25_pandas/25_pandas.md new file mode 100644 index 0000000..4f1c821 --- /dev/null +++ b/25_pandas/25_pandas.md @@ -0,0 +1,1216 @@ +
+

30 Days Of Python: Day 25 - Pandas

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+ +
+ +[<< Day 24](../24_Day_Statistics/24_statistics.md) | [Day 26 >>](../26_Day_Python_web/26_python_web.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 25](#-day-25) + - [Pandas](#pandas) + - [Installing Pandas](#installing-pandas) + - [Importing Pandas](#importing-pandas) + - [Creating Pandas Series with Default Index](#creating-pandas-series-with-default-index) + - [Creating Pandas Series with custom index](#creating--pandas-series-with-custom-index) + - [Creating Pandas Series from a Dictionary](#creating-pandas-series-from-a-dictionary) + - [Creating a Constant Pandas Series](#creating-a-constant-pandas-series) + - [Creating a Pandas Series Using Linspace](#creating-a--pandas-series-using-linspace) + - [DataFrames](#dataframes) + - [Creating DataFrames from List of Lists](#creating-dataframes-from-list-of-lists) + - [Creating DataFrame Using Dictionary](#creating-dataframe-using-dictionary) + - [Creating DataFrames from a List of Dictionaries](#creating-dataframes-from-a-list-of-dictionaries) + - [Reading CSV File Using Pandas](#reading-csv-file-using-pandas) + - [Data Exploration](#data-exploration) + - [Modifying a DataFrame](#modifying-a-dataframe) + - [Creating a DataFrame](#creating-a-dataframe) + - [Adding a New Column](#adding-a-new-column) + - [Modifying column values](#modifying-column-values) + - [Formating DataFrame columns](#formating-dataframe-columns) + - [Checking data types of Column values](#checking-data-types-of-column-values) + - [Boolean Indexing](#boolean-indexing) + - [Exercises: Day 25](#exercises-day-25) + +# 📘 Day 25 + +## Pandas + +Pandas is an open source, high-performance, easy-to-use data structures and data analysis tools for the Python programming language. +Pandas adds data structures and tools designed to work with table-like data which is *Series* and *Data Frames*. +Pandas provides tools for data manipulation: + +- reshaping +- merging +- sorting +- slicing +- aggregation +- imputation. +If you are using anaconda, you do not have install pandas. + +### Installing Pandas + +For Mac: +```py +pip install conda +conda install pandas +``` + +For Windows: +```py +pip install conda +pip install pandas +``` + +Pandas data structure is based on *Series* and *DataFrames*. + +A *series* is a *column* and a DataFrame is a *multidimensional table* made up of collection of *series*. In order to create a pandas series we should use numpy to create a one dimensional arrays or a python list. +Let us see an example of a series: + +Names Pandas Series + +![pandas series](../images/pandas-series-1.png) + +Countries Series + +![pandas series](../images/pandas-series-2.png) + +Cities Series + +![pandas series](../images/pandas-series-3.png) + +As you can see, pandas series is just one column of data. If we want to have multiple columns we use data frames. The example below shows pandas DataFrames. + +Let us see, an example of a pandas data frame: + +![Pandas data frame](../images/pandas-dataframe-1.png) + +Data frame is a collection of rows and columns. Look at the table below; it has many more columns than the example above: + +![Pandas data frame](../images/pandas-dataframe-2.png) + +Next, we will see how to import pandas and how to create Series and DataFrames using pandas + +### Importing Pandas + +```python +import pandas as pd # importing pandas as pd +import numpy as np # importing numpy as np +``` + +### Creating Pandas Series with Default Index + +```python +nums = [1, 2, 3, 4,5] +s = pd.Series(nums) +print(s) +``` + +```sh + 0 1 + 1 2 + 2 3 + 3 4 + 4 5 + dtype: int64 +``` + +### Creating Pandas Series with custom index + +```python +nums = [1, 2, 3, 4, 5] +s = pd.Series(nums, index=[1, 2, 3, 4, 5]) +print(s) +``` + +```sh + 1 1 + 2 2 + 3 3 + 4 4 + 5 5 + dtype: int64 +``` + +```python +fruits = ['Orange','Banana','Mango'] +fruits = pd.Series(fruits, index=[1, 2, 3]) +print(fruits) +``` + +```sh + 1 Orange + 2 Banana + 3 Mango + dtype: object +``` + +### Creating Pandas Series from a Dictionary + +```python +dct = {'name':'Asabeneh','country':'Finland','city':'Helsinki'} +``` + +```python +s = pd.Series(dct) +print(s) +``` + +```sh + name Asabeneh + country Finland + city Helsinki + dtype: object +``` + +### Creating a Constant Pandas Series + +```python +s = pd.Series(10, index = [1, 2, 3]) +print(s) +``` + +```sh + 1 10 + 2 10 + 3 10 + dtype: int64 +``` + +### Creating a Pandas Series Using Linspace + +```python +s = pd.Series(np.linspace(5, 20, 10)) # linspace(starting, end, items) +print(s) +``` + +```sh + 0 5.000000 + 1 6.666667 + 2 8.333333 + 3 10.000000 + 4 11.666667 + 5 13.333333 + 6 15.000000 + 7 16.666667 + 8 18.333333 + 9 20.000000 + dtype: float64 +``` + +## DataFrames + +Pandas data frames can be created in different ways. + +### Creating DataFrames from List of Lists + +```python +data = [ + ['Asabeneh', 'Finland', 'Helsink'], + ['David', 'UK', 'London'], + ['John', 'Sweden', 'Stockholm'] +] +df = pd.DataFrame(data, columns=['Names','Country','City']) +print(df) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NamesCountryCity
0AsabenehFinlandHelsink
1DavidUKLondon
2JohnSwedenStockholm
+ +### Creating DataFrame Using Dictionary + +```python +data = {'Name': ['Asabeneh', 'David', 'John'], 'Country':[ + 'Finland', 'UK', 'Sweden'], 'City': ['Helsiki', 'London', 'Stockholm']} +df = pd.DataFrame(data) +print(df) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCity
0AsabenehFinlandHelsiki
1DavidUKLondon
2JohnSwedenStockholm
+ +### Creating DataFrames from a List of Dictionaries + +```python +data = [ + {'Name': 'Asabeneh', 'Country': 'Finland', 'City': 'Helsinki'}, + {'Name': 'David', 'Country': 'UK', 'City': 'London'}, + {'Name': 'John', 'Country': 'Sweden', 'City': 'Stockholm'}] +df = pd.DataFrame(data) +print(df) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCity
0AsabenehFinlandHelsinki
1DavidUKLondon
2JohnSwedenStockholm
+ +## Reading CSV File Using Pandas + +To download the CSV file, what is needed in this example, console/command line is enough: + +```sh +curl -O https://raw.githubusercontent.com/Asabeneh/30-Days-Of-Python/master/data/weight-height.csv +``` + +Put the downloaded file in your working directory. + +```python +import pandas as pd + +df = pd.read_csv('weight-height.csv') +print(df) +``` + +### Data Exploration + +Let us read only the first 5 rows using head() + +```python +print(df.head()) # give five rows we can increase the number of rows by passing argument to the head() method +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GenderHeightWeight
0Male73.847017241.893563
1Male68.781904162.310473
2Male74.110105212.740856
3Male71.730978220.042470
4Male69.881796206.349801
+ +Let us also explore the last recordings of the dataframe using the tail() methods. + +```python +print(df.tail()) # tails give the last five rows, we can increase the rows by passing argument to tail method +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GenderHeightWeight
9995Female66.172652136.777454
9996Female67.067155170.867906
9997Female63.867992128.475319
9998Female69.034243163.852461
9999Female61.944246113.649103
+ +As you can see the csv file has three rows: Gender, Height and Weight. If the DataFrame would have a long rows, it would be hard to know all the columns. Therefore, we should use a method to know the colums. we do not know the number of rows. Let's use shape meathod. + +```python +print(df.shape) # as you can see 10000 rows and three columns +``` + + (10000, 3) + +Let us get all the columns using columns. + +```python +print(df.columns) +``` + + Index(['Gender', 'Height', 'Weight'], dtype='object') + +Now, let us get a specific column using the column key + +```python +heights = df['Height'] # this is now a series +``` + +```python +print(heights) +``` + +```sh + 0 73.847017 + 1 68.781904 + 2 74.110105 + 3 71.730978 + 4 69.881796 + ... + 9995 66.172652 + 9996 67.067155 + 9997 63.867992 + 9998 69.034243 + 9999 61.944246 + Name: Height, Length: 10000, dtype: float64 +``` + +```python +weights = df['Weight'] # this is now a series +``` + +```python +print(weights) +``` + +```sh + 0 241.893563 + 1 162.310473 + 2 212.740856 + 3 220.042470 + 4 206.349801 + ... + 9995 136.777454 + 9996 170.867906 + 9997 128.475319 + 9998 163.852461 + 9999 113.649103 + Name: Weight, Length: 10000, dtype: float64 +``` + +```python +print(len(heights) == len(weights)) +``` + + True + +The describe() method provides a descriptive statistical values of a dataset. + +```python +print(heights.describe()) # give statisical information about height data +``` + +```sh + count 10000.000000 + mean 66.367560 + std 3.847528 + min 54.263133 + 25% 63.505620 + 50% 66.318070 + 75% 69.174262 + max 78.998742 + Name: Height, dtype: float64 +``` + +```python +print(weights.describe()) +``` + +```sh + count 10000.000000 + mean 161.440357 + std 32.108439 + min 64.700127 + 25% 135.818051 + 50% 161.212928 + 75% 187.169525 + max 269.989699 + Name: Weight, dtype: float64 +``` + +```python +print(df.describe()) # describe can also give statistical information from a dataFrame +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HeightWeight
count10000.00000010000.000000
mean66.367560161.440357
std3.84752832.108439
min54.26313364.700127
25%63.505620135.818051
50%66.318070161.212928
75%69.174262187.169525
max78.998742269.989699
+ +Similar to describe(), the info() method also give information about the dataset. + +## Modifying a DataFrame + +Modifying a DataFrame: + * We can create a new DataFrame + * We can create a new column and add it to the DataFrame, + * we can remove an existing column from a DataFrame, + * we can modify an existing column in a DataFrame, + * we can change the data type of column values in the DataFrame + +### Creating a DataFrame + +As always, first we import the necessary packages. Now, lets import pandas and numpy, two best friends ever. + +```python +import pandas as pd +import numpy as np +data = [ + {"Name": "Asabeneh", "Country":"Finland","City":"Helsinki"}, + {"Name": "David", "Country":"UK","City":"London"}, + {"Name": "John", "Country":"Sweden","City":"Stockholm"}] +df = pd.DataFrame(data) +print(df) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCity
0AsabenehFinlandHelsinki
1DavidUKLondon
2JohnSwedenStockholm
+ +Adding a column to a DataFrame is like adding a key to a dictionary. + +First let's use the previous example to create a DataFrame. After we create the DataFrame, we will start modifying the columns and column values. + +### Adding a New Column + +Let's add a weight column in the DataFrame + +```python +weights = [74, 78, 69] +df['Weight'] = weights +df +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeight
0AsabenehFinlandHelsinki74
1DavidUKLondon78
2JohnSwedenStockholm69
+ +Let's add a height column into the DataFrame aswell + +```python +heights = [173, 175, 169] +df['Height'] = heights +print(df) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeight
0AsabenehFinlandHelsinki74173
1DavidUKLondon78175
2JohnSwedenStockholm69169
+ +As you can see in the DataFrame above, we did add new columns, Weight and Height. Let's add one additional column called BMI(Body Mass Index) by calculating their BMI using thier mass and height. BMI is mass divided by height squared (in meters) - Weight/Height * Height. + +As you can see, the height is in centimeters, so we shoud change it to meters. Let's modify the height row. + +### Modifying column values + +```python +df['Height'] = df['Height'] * 0.01 +df +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeight
0AsabenehFinlandHelsinki741.73
1DavidUKLondon781.75
2JohnSwedenStockholm691.69
+ +```python +# Using functions makes our code clean, but you can calculate the bmi without one +def calculate_bmi (): + weights = df['Weight'] + heights = df['Height'] + bmi = [] + for w,h in zip(weights, heights): + b = w/(h*h) + bmi.append(b) + return bmi + +bmi = calculate_bmi() + +``` + + +```python +df['BMI'] = bmi +df +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMI
0AsabenehFinlandHelsinki741.7324.725183
1DavidUKLondon781.7525.469388
2JohnSwedenStockholm691.6924.158818
+ +### Formating DataFrame columns + +The BMI column values of the DataFrame are float with many significant digits after decimal. Let's change it to one significant digit after point. + +```python +df['BMI'] = round(df['BMI'], 1) +print(df) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMI
0AsabenehFinlandHelsinki741.7324.7
1DavidUKLondon781.7525.5
2JohnSwedenStockholm691.6924.2
+ +The information in the DataFrame seems not yet complete, let's add birth year and current year columns. + +```python +birth_year = ['1769', '1985', '1990'] +current_year = pd.Series(2020, index=[0, 1,2]) +df['Birth Year'] = birth_year +df['Current Year'] = current_year +df +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMIBirth YearCurrent Year
0AsabenehFinlandHelsinki741.7324.717692020
1DavidUKLondon781.7525.519852020
2JohnSwedenStockholm691.6924.219902020
+ +## Checking data types of Column values + +```python +print(df.Weight.dtype) +``` + +```sh + dtype('int64') +``` + +```python +df['Birth Year'].dtype # it gives string object , we should change this to number + +``` + +```python +df['Birth Year'] = df['Birth Year'].astype('int') +print(df['Birth Year'].dtype) # let's check the data type now +``` + +```sh + dtype('int32') +``` + +Now same for the current year: + +```python +df['Current Year'] = df['Current Year'].astype('int') +df['Current Year'].dtype +``` + +```sh + dtype('int32') +``` + +Now, the column values of birth year and current year are integers. We can calculate the age. + +```python +ages = df['Current Year'] - df['Birth Year'] +ages +``` + + 0 251 + 1 35 + 2 30 + dtype: int32 + +```python +df['Ages'] = ages +print(df) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMIBirth YearCurrent YearAges
0AsabenehFinlandHelsinki741.7324.717692019250
1DavidUKLondon781.7525.51985201934
2JohnSwedenStockholm691.6924.21990201929
+ +The person in the first row lived so far for 251 years. It is unlikely for someone to live so long. Either it is a typo or the data is cooked. So lets fill that data with average of the columns without including outlier. + +mean = (35 + 30)/ 2 + +```python +mean = (35 + 30)/ 2 +print('Mean: ',mean) #it is good to add some description to the output, so we know what is what +``` + +```sh + Mean: 32.5 +``` + +### Boolean Indexing + +```python +print(df[df['Ages'] > 120]) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMIBirth YearCurrent YearAges
0AsabenehFinlandHelsinki741.7324.717692020251
+ + +```python +print(df[df['Ages'] < 120]) +``` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMIBirth YearCurrent YearAges
1DavidUKLondon781.7525.51985202035
2JohnSwedenStockholm691.6924.21990202030
+ +## Exercises: Day 25 + +1. Read the hacker_news.csv file from data directory +1. Get the first five rows +1. Get the last five rows +1. Get the title column as pandas series +1. Count the number of rows and columns + - Filter the titles which contain python + - Filter the titles which contain JavaScript + - Explore the data and make sense of it + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 24](../24_Day_Statistics/24_statistics.md) | [Day 26 >>](../26_Day_Python_web/26_python_web.md) diff --git a/25_pandas/index.html b/25_pandas/index.html new file mode 100644 index 0000000..1311d35 --- /dev/null +++ b/25_pandas/index.html @@ -0,0 +1,2636 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 25 pandas - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 25 - Pandas

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+ +
+ +

<< Day 24 | Day 26 >>

+

30DaysOfPython

+ +

📘 Day 25⚓︎

+

Pandas⚓︎

+

Pandas is an open source, high-performance, easy-to-use data structures and data analysis tools for the Python programming language. +Pandas adds data structures and tools designed to work with table-like data which is Series and Data Frames. +Pandas provides tools for data manipulation:

+
    +
  • reshaping
  • +
  • merging
  • +
  • sorting
  • +
  • slicing
  • +
  • aggregation
  • +
  • imputation. +If you are using anaconda, you do not have install pandas.
  • +
+

Installing Pandas⚓︎

+

For Mac: +

pip install conda
+conda install pandas
+

+

For Windows: +

pip install conda
+pip install pandas
+

+

Pandas data structure is based on Series and DataFrames.

+

A series is a column and a DataFrame is a multidimensional table made up of collection of series. In order to create a pandas series we should use numpy to create a one dimensional arrays or a python list. +Let us see an example of a series:

+

Names Pandas Series

+

pandas series

+

Countries Series

+

pandas series

+

Cities Series

+

pandas series

+

As you can see, pandas series is just one column of data. If we want to have multiple columns we use data frames. The example below shows pandas DataFrames.

+

Let us see, an example of a pandas data frame:

+

Pandas data frame

+

Data frame is a collection of rows and columns. Look at the table below; it has many more columns than the example above:

+

Pandas data frame

+

Next, we will see how to import pandas and how to create Series and DataFrames using pandas

+

Importing Pandas⚓︎

+
import pandas as pd # importing pandas as pd
+import numpy  as np # importing numpy as np
+
+

Creating Pandas Series with Default Index⚓︎

+
nums = [1, 2, 3, 4,5]
+s = pd.Series(nums)
+print(s)
+
+
    0    1
+    1    2
+    2    3
+    3    4
+    4    5
+    dtype: int64
+
+

Creating Pandas Series with custom index⚓︎

+
nums = [1, 2, 3, 4, 5]
+s = pd.Series(nums, index=[1, 2, 3, 4, 5])
+print(s)
+
+
    1    1
+    2    2
+    3    3
+    4    4
+    5    5
+    dtype: int64
+
+
fruits = ['Orange','Banana','Mango']
+fruits = pd.Series(fruits, index=[1, 2, 3])
+print(fruits)
+
+
    1    Orange
+    2    Banana
+    3    Mango
+    dtype: object
+
+

Creating Pandas Series from a Dictionary⚓︎

+
dct = {'name':'Asabeneh','country':'Finland','city':'Helsinki'}
+
+
s = pd.Series(dct)
+print(s)
+
+
    name       Asabeneh
+    country     Finland
+    city       Helsinki
+    dtype: object
+
+

Creating a Constant Pandas Series⚓︎

+
s = pd.Series(10, index = [1, 2, 3])
+print(s)
+
+
    1    10
+    2    10
+    3    10
+    dtype: int64
+
+

Creating a Pandas Series Using Linspace⚓︎

+
s = pd.Series(np.linspace(5, 20, 10)) # linspace(starting, end, items)
+print(s)
+
+
    0     5.000000
+    1     6.666667
+    2     8.333333
+    3    10.000000
+    4    11.666667
+    5    13.333333
+    6    15.000000
+    7    16.666667
+    8    18.333333
+    9    20.000000
+    dtype: float64
+
+

DataFrames⚓︎

+

Pandas data frames can be created in different ways.

+

Creating DataFrames from List of Lists⚓︎

+
data = [
+    ['Asabeneh', 'Finland', 'Helsink'], 
+    ['David', 'UK', 'London'],
+    ['John', 'Sweden', 'Stockholm']
+]
+df = pd.DataFrame(data, columns=['Names','Country','City'])
+print(df)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NamesCountryCity
0AsabenehFinlandHelsink
1DavidUKLondon
2JohnSwedenStockholm
+ +

Creating DataFrame Using Dictionary⚓︎

+
data = {'Name': ['Asabeneh', 'David', 'John'], 'Country':[
+    'Finland', 'UK', 'Sweden'], 'City': ['Helsiki', 'London', 'Stockholm']}
+df = pd.DataFrame(data)
+print(df)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCity
0AsabenehFinlandHelsiki
1DavidUKLondon
2JohnSwedenStockholm
+ +

Creating DataFrames from a List of Dictionaries⚓︎

+
data = [
+    {'Name': 'Asabeneh', 'Country': 'Finland', 'City': 'Helsinki'},
+    {'Name': 'David', 'Country': 'UK', 'City': 'London'},
+    {'Name': 'John', 'Country': 'Sweden', 'City': 'Stockholm'}]
+df = pd.DataFrame(data)
+print(df)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCity
0AsabenehFinlandHelsinki
1DavidUKLondon
2JohnSwedenStockholm
+ +

Reading CSV File Using Pandas⚓︎

+

To download the CSV file, what is needed in this example, console/command line is enough:

+
curl -O https://raw.githubusercontent.com/Asabeneh/30-Days-Of-Python/master/data/weight-height.csv
+
+

Put the downloaded file in your working directory.

+
import pandas as pd
+
+df = pd.read_csv('weight-height.csv')
+print(df)
+
+

Data Exploration⚓︎

+

Let us read only the first 5 rows using head()

+
print(df.head()) # give five rows we can increase the number of rows by passing argument to the head() method
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GenderHeightWeight
0Male73.847017241.893563
1Male68.781904162.310473
2Male74.110105212.740856
3Male71.730978220.042470
4Male69.881796206.349801
+ +

Let us also explore the last recordings of the dataframe using the tail() methods.

+
print(df.tail()) # tails give the last five rows, we can increase the rows by passing argument to tail method
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
GenderHeightWeight
9995Female66.172652136.777454
9996Female67.067155170.867906
9997Female63.867992128.475319
9998Female69.034243163.852461
9999Female61.944246113.649103
+ +

As you can see the csv file has three rows: Gender, Height and Weight. If the DataFrame would have a long rows, it would be hard to know all the columns. Therefore, we should use a method to know the colums. we do not know the number of rows. Let's use shape meathod.

+
print(df.shape) # as you can see 10000 rows and three columns
+
+
(10000, 3)
+
+

Let us get all the columns using columns.

+
print(df.columns)
+
+
Index(['Gender', 'Height', 'Weight'], dtype='object')
+
+

Now, let us get a specific column using the column key

+
heights = df['Height'] # this is now a series
+
+
print(heights)
+
+
    0       73.847017
+    1       68.781904
+    2       74.110105
+    3       71.730978
+    4       69.881796
+              ...    
+    9995    66.172652
+    9996    67.067155
+    9997    63.867992
+    9998    69.034243
+    9999    61.944246
+    Name: Height, Length: 10000, dtype: float64
+
+
weights = df['Weight'] # this is now a series
+
+
print(weights)
+
+
    0       241.893563
+    1       162.310473
+    2       212.740856
+    3       220.042470
+    4       206.349801
+               ...    
+    9995    136.777454
+    9996    170.867906
+    9997    128.475319
+    9998    163.852461
+    9999    113.649103
+    Name: Weight, Length: 10000, dtype: float64
+
+
print(len(heights) == len(weights))
+
+
True
+
+

The describe() method provides a descriptive statistical values of a dataset.

+
print(heights.describe()) # give statisical information about height data
+
+
    count    10000.000000
+    mean        66.367560
+    std          3.847528
+    min         54.263133
+    25%         63.505620
+    50%         66.318070
+    75%         69.174262
+    max         78.998742
+    Name: Height, dtype: float64
+
+
print(weights.describe())
+
+
    count    10000.000000
+    mean       161.440357
+    std         32.108439
+    min         64.700127
+    25%        135.818051
+    50%        161.212928
+    75%        187.169525
+    max        269.989699
+    Name: Weight, dtype: float64
+
+
print(df.describe())  # describe can also give statistical information from a dataFrame
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HeightWeight
count10000.00000010000.000000
mean66.367560161.440357
std3.84752832.108439
min54.26313364.700127
25%63.505620135.818051
50%66.318070161.212928
75%69.174262187.169525
max78.998742269.989699
+ +

Similar to describe(), the info() method also give information about the dataset.

+

Modifying a DataFrame⚓︎

+

Modifying a DataFrame: + * We can create a new DataFrame + * We can create a new column and add it to the DataFrame, + * we can remove an existing column from a DataFrame, + * we can modify an existing column in a DataFrame, + * we can change the data type of column values in the DataFrame

+

Creating a DataFrame⚓︎

+

As always, first we import the necessary packages. Now, lets import pandas and numpy, two best friends ever.

+
import pandas as pd
+import numpy as np
+data = [
+    {"Name": "Asabeneh", "Country":"Finland","City":"Helsinki"},
+    {"Name": "David", "Country":"UK","City":"London"},
+    {"Name": "John", "Country":"Sweden","City":"Stockholm"}]
+df = pd.DataFrame(data)
+print(df)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCity
0AsabenehFinlandHelsinki
1DavidUKLondon
2JohnSwedenStockholm
+ +

Adding a column to a DataFrame is like adding a key to a dictionary.

+

First let's use the previous example to create a DataFrame. After we create the DataFrame, we will start modifying the columns and column values.

+

Adding a New Column⚓︎

+

Let's add a weight column in the DataFrame

+
weights = [74, 78, 69]
+df['Weight'] = weights
+df
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeight
0AsabenehFinlandHelsinki74
1DavidUKLondon78
2JohnSwedenStockholm69
+ +

Let's add a height column into the DataFrame aswell

+
heights = [173, 175, 169]
+df['Height'] = heights
+print(df)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeight
0AsabenehFinlandHelsinki74173
1DavidUKLondon78175
2JohnSwedenStockholm69169
+ +

As you can see in the DataFrame above, we did add new columns, Weight and Height. Let's add one additional column called BMI(Body Mass Index) by calculating their BMI using thier mass and height. BMI is mass divided by height squared (in meters) - Weight/Height * Height.

+

As you can see, the height is in centimeters, so we shoud change it to meters. Let's modify the height row.

+

Modifying column values⚓︎

+
df['Height'] = df['Height'] * 0.01
+df
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeight
0AsabenehFinlandHelsinki741.73
1DavidUKLondon781.75
2JohnSwedenStockholm691.69
+ +
# Using functions makes our code clean, but you can calculate the bmi without one
+def calculate_bmi ():
+    weights = df['Weight']
+    heights = df['Height']
+    bmi = []
+    for w,h in zip(weights, heights):
+        b = w/(h*h)
+        bmi.append(b)
+    return bmi
+
+bmi = calculate_bmi()
+
+
df['BMI'] = bmi
+df
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMI
0AsabenehFinlandHelsinki741.7324.725183
1DavidUKLondon781.7525.469388
2JohnSwedenStockholm691.6924.158818
+ +

Formating DataFrame columns⚓︎

+

The BMI column values of the DataFrame are float with many significant digits after decimal. Let's change it to one significant digit after point.

+
df['BMI'] = round(df['BMI'], 1)
+print(df)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMI
0AsabenehFinlandHelsinki741.7324.7
1DavidUKLondon781.7525.5
2JohnSwedenStockholm691.6924.2
+ +

The information in the DataFrame seems not yet complete, let's add birth year and current year columns.

+
birth_year = ['1769', '1985', '1990']
+current_year = pd.Series(2020, index=[0, 1,2])
+df['Birth Year'] = birth_year
+df['Current Year'] = current_year
+df
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMIBirth YearCurrent Year
0AsabenehFinlandHelsinki741.7324.717692020
1DavidUKLondon781.7525.519852020
2JohnSwedenStockholm691.6924.219902020
+ +

Checking data types of Column values⚓︎

+
print(df.Weight.dtype)
+
+
    dtype('int64')
+
+
df['Birth Year'].dtype # it gives string object , we should change this to number
+
+
df['Birth Year'] = df['Birth Year'].astype('int')
+print(df['Birth Year'].dtype) # let's check the data type now
+
+
    dtype('int32')
+
+

Now same for the current year:

+
df['Current Year'] = df['Current Year'].astype('int')
+df['Current Year'].dtype
+
+
    dtype('int32')
+
+

Now, the column values of birth year and current year are integers. We can calculate the age.

+
ages = df['Current Year'] - df['Birth Year']
+ages
+
+
0    251
+1     35
+2     30
+dtype: int32
+
+
df['Ages'] = ages
+print(df)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMIBirth YearCurrent YearAges
0AsabenehFinlandHelsinki741.7324.717692019250
1DavidUKLondon781.7525.51985201934
2JohnSwedenStockholm691.6924.21990201929
+ +

The person in the first row lived so far for 251 years. It is unlikely for someone to live so long. Either it is a typo or the data is cooked. So lets fill that data with average of the columns without including outlier.

+

mean = (35 + 30)/ 2

+
mean = (35 + 30)/ 2
+print('Mean: ',mean)    #it is good to add some description to the output, so we know what is what
+
+
   Mean:  32.5
+
+

Boolean Indexing⚓︎

+
print(df[df['Ages'] > 120])
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMIBirth YearCurrent YearAges
0AsabenehFinlandHelsinki741.7324.717692020251
+ +
print(df[df['Ages'] < 120])
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameCountryCityWeightHeightBMIBirth YearCurrent YearAges
1DavidUKLondon781.7525.51985202035
2JohnSwedenStockholm691.6924.21990202030
+ +

Exercises: Day 25⚓︎

+
    +
  1. Read the hacker_news.csv file from data directory
  2. +
  3. Get the first five rows
  4. +
  5. Get the last five rows
  6. +
  7. Get the title column as pandas series
  8. +
  9. Count the number of rows and columns
      +
    • Filter the titles which contain python
    • +
    • Filter the titles which contain JavaScript
    • +
    • Explore the data and make sense of it
    • +
    +
  10. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 24 | Day 26 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/26_python_web/26_python_web.md b/26_python_web/26_python_web.md new file mode 100644 index 0000000..a04cee9 --- /dev/null +++ b/26_python_web/26_python_web.md @@ -0,0 +1,576 @@ +
+

30 Days Of Python: Day 26 - Python for web

+ + + + + Twitter Follow + + + Author: + Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+
+ + +[<< Day 25 ](../25_Day_Pandas/25_pandas.md) | [Day 27 >>](../27_Day_Python_with_mongodb/27_python_with_mongodb.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 26](#-day-26) + - [Python for Web](#python-for-web) + - [Flask](#flask) + - [Folder structure](#folder-structure) + - [Setting up your project directory](#setting-up-your-project-directory) + - [Creating routes](#creating-routes) + - [Creating templates](#creating-templates) + - [Python Script](#python-script) + - [Navigation](#navigation) + - [Creating a layout](#creating-a-layout) + - [Serving Static File](#serving-static-file) + - [Deployment](#deployment) + - [Creating Heroku account](#creating-heroku-account) + - [Login to Heroku](#login-to-heroku) + - [Create requirements and Procfile](#create-requirements-and-procfile) + - [Pushing project to heroku](#pushing-project-to-heroku) + - [Exercises: Day 26](#exercises-day-26) + +# 📘 Day 26 + +## Python for Web + +Python is a general purpose programming language and it can be used for many places. In this section, we will see how we use Python for the web. There are many Python web frame works. Django and Flask are the most popular ones. Today, we will see how to use Flask for web development. + +### Flask + +Flask is a web development framework written in Python. Flask uses Jinja2 template engine. Flask can be also used with other modern front libraries such as React. + +If you did not install the virtualenv package yet install it first. Virtual environment will allows to isolate project dependencies from the local machine dependencies. + +#### Folder structure + +After completing all the step, your project file structure should look like this: + +```sh + +├── Procfile +├── app.py +├── env +│   ├── bin +├── requirements.txt +├── static +│   └── css +│   └── main.css +└── templates + ├── about.html + ├── home.html + ├── layout.html + ├── post.html + └── result.html +``` + +### Setting up your project directory + +Follow the following steps to get started with Flask. + +Step 1: install virtualenv using the following command. + +```sh +pip install virtualenv +``` + +Step 2: + +```sh +asabeneh@Asabeneh:~/Desktop$ mkdir python_for_web +asabeneh@Asabeneh:~/Desktop$ cd python_for_web/ +asabeneh@Asabeneh:~/Desktop/python_for_web$ virtualenv venv +asabeneh@Asabeneh:~/Desktop/python_for_web$ source venv/bin/activate +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip install Flask +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze +Click==7.0 +Flask==1.1.1 +itsdangerous==1.1.0 +Jinja2==2.10.3 +MarkupSafe==1.1.1 +Werkzeug==0.16.0 +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ +``` + +We created a project director named python_for_web. Inside the project we created a virtual environment *venv* which could be any name but I prefer to call it _venv_. Then we activated the virtual environment. We used pip freeze to check the installed packages in the project directory. The result of pip freeze was empty because a package was not installed yet. + +Now, let's create app.py file in the project directory and write the following code. The app.py file will be the main file in the project. The following code has flask module, os module. + +### Creating routes + +The home route. + +```py +# let's import the flask +from flask import Flask +import os # importing operating system module + +app = Flask(__name__) + +@app.route('/') # this decorator create the home route +def home (): + return '

Welcome

' + +@app.route('/about') +def about(): + return '

About us

' + + +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +To run the flask application, write python app.py in the main flask application directory. + +After you run _python app.py_ check local host 5000. + +Let us add additional route. +Creating about route + +```py +# let's import the flask +from flask import Flask +import os # importing operating system module + +app = Flask(__name__) + +@app.route('/') # this decorator create the home route +def home (): + return '

Welcome

' + +@app.route('/about') +def about(): + return '

About us

' + +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +Now, we added the about route in the above code. How about if we want to render an HTML file instead of string? It is possible to render HTML file using the function *render_templae*. Let us create a folder called templates and create home.html and about.html in the project directory. Let us also import the *render_template* function from flask. + +### Creating templates + +Create the HTML files inside templates folder. + +home.html + +```html + + + + + + Home + + + +

Welcome Home

+ + +``` + +about.html + +```html + + + + + + About + + + +

About Us

+ + +``` + +### Python Script + +app.py + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module + +app = Flask(__name__) + +@app.route('/') # this decorator create the home route +def home (): + return render_template('home.html') + +@app.route('/about') +def about(): + return render_template('about.html') + +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +As you can see to go to different pages or to navigate we need a navigation. Let's add a link to each page or let's create a layout which we use to every page. + +### Navigation + +```html + +``` + +Now, we can navigate between the pages using the above link. Let us create additional page which handle form data. You can call it any name, I like to call it post.html. + +We can inject data to the HTML files using Jinja2 template engine. + +```py +# let's import the flask +from flask import Flask, render_template, request, redirect, url_for +import os # importing operating system module + +app = Flask(__name__) + +@app.route('/') # this decorator create the home route +def home (): + techs = ['HTML', 'CSS', 'Flask', 'Python'] + name = '30 Days Of Python Programming' + return render_template('home.html', techs=techs, name = name, title = 'Home') + +@app.route('/about') +def about(): + name = '30 Days Of Python Programming' + return render_template('about.html', name = name, title = 'About Us') + +@app.route('/post') +def post(): + name = 'Text Analyzer' + return render_template('post.html', name = name, title = name) + + +if __name__ == '__main__': + # for deployment + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +Let's see the templates too: + +home.html + +```html + + + + + + Home + + + + +

Welcome to {{name}}

+
    + {% for tech in techs %} +
  • {{tech}}
  • + {% endfor %} +
+ + +``` + +about.html + +```html + + + + + + About Us + + + + +

About Us

+

{{name}}

+ + +``` + +### Creating a layout + +In the template files, there are lots of repeated codes, we can write a layout and we can remove the repetition. Let's create layout.html inside the templates folder. +After we create the layout we will import to every file. + +#### Serving Static File + +Create a static folder in your project directory. Inside the static folder create CSS or styles folder and create a CSS stylesheet. We use the *url_for* module to serve the static file. + +layout.html + +```html + + + + + + + + {% if title %} + 30 Days of Python - {{ title}} + {% else %} + 30 Days of Python + {% endif %} + + + +
+ +
+
+ {% block content %} {% endblock %} +
+ + +``` + +Now, lets remove all the repeated code in the other template files and import the layout.html. The href is using _url_for_ function with the name of the route function to connect each navigation route. + +home.html + +```html +{% extends 'layout.html' %} {% block content %} +
+

Welcome to {{name}}

+

+ This application clean texts and analyse the number of word, characters and + most frequent words in the text. Check it out by click text analyzer at the + menu. You need the following technologies to build this web application: +

+
    + {% for tech in techs %} +
  • {{tech}}
  • + + {% endfor %} +
+
+ +{% endblock %} +``` + +about.html + +```html +{% extends 'layout.html' %} {% block content %} +
+

About {{name}}

+

+ This is a 30 days of python programming challenge. If you have been coding + this far, you are awesome. Congratulations for the job well done! +

+
+{% endblock %} +``` + +post.html + +```html +{% extends 'layout.html' %} {% block content %} +
+

Text Analyzer

+
+
+ +
+
+ +
+
+
+ +{% endblock %} +``` + +Request methods, there are different request methods(GET, POST, PUT, DELETE) are the common request methods which allow us to do CRUD(Create, Read, Update, Delete) operation. + +In the post, route we will use GET and POST method alternative depending on the type of request, check how it looks in the code below. The request method is a function to handle request methods and also to access form data. +app.py + +```py +# let's import the flask +from flask import Flask, render_template, request, redirect, url_for +import os # importing operating system module + +app = Flask(__name__) +# to stop caching static file +app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0 + + + +@app.route('/') # this decorator create the home route +def home (): + techs = ['HTML', 'CSS', 'Flask', 'Python'] + name = '30 Days Of Python Programming' + return render_template('home.html', techs=techs, name = name, title = 'Home') + +@app.route('/about') +def about(): + name = '30 Days Of Python Programming' + return render_template('about.html', name = name, title = 'About Us') + +@app.route('/result') +def result(): + return render_template('result.html') + +@app.route('/post', methods= ['GET','POST']) +def post(): + name = 'Text Analyzer' + if request.method == 'GET': + return render_template('post.html', name = name, title = name) + if request.method =='POST': + content = request.form['content'] + print(content) + return redirect(url_for('result')) + +if __name__ == '__main__': + # for deployment + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +So far, we have seen how to use template and how to inject data to template, how to a common layout. +Now, lets handle static file. Create a folder called static in the project director and create a folder called css. Inside css folder create main.css. Your main. css file will be linked to the layout.html. + +You don't have to write the css file, copy and use it. Let's move on to deployment. + +### Deployment + +#### Creating Heroku account + +Heroku provides a free deployment service for both front end and fullstack applications. Create an account on [heroku](https://www.heroku.com/) and install the heroku [CLI](https://devcenter.heroku.com/articles/heroku-cli) for you machine. +After installing heroku write the following command + +#### Login to Heroku + +```sh +asabeneh@Asabeneh:~$ heroku login +heroku: Press any key to open up the browser to login or q to exit: +``` + +Let's see the result by clicking any key from the keyboard. When you press any key from you keyboard it will open the heroku login page and click the login page. Then you will local machine will be connected to the remote heroku server. If you are connected to remote server, you will see this. + +```sh +asabeneh@Asabeneh:~$ heroku login +heroku: Press any key to open up the browser to login or q to exit: +Opening browser to https://cli-auth.heroku.com/auth/browser/be12987c-583a-4458-a2c2-ba2ce7f41610 +Logging in... done +Logged in as asabeneh@gmail.com +asabeneh@Asabeneh:~$ +``` + +#### Create requirements and Procfile + +Before we push our code to remote server, we need requirements + +- requirements.txt +- Procfile + +```sh +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze +Click==7.0 +Flask==1.1.1 +itsdangerous==1.1.0 +Jinja2==2.10.3 +MarkupSafe==1.1.1 +Werkzeug==0.16.0 +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ touch requirements.txt +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze > requirements.txt +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ cat requirements.txt +Click==7.0 +Flask==1.1.1 +itsdangerous==1.1.0 +Jinja2==2.10.3 +MarkupSafe==1.1.1 +Werkzeug==0.16.0 +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ touch Procfile +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ ls +Procfile env/ static/ +app.py requirements.txt templates/ +(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ +``` + +The Procfile will have the command which run the application in the web server in our case on Heroku. + +```sh +web: python app.py +``` + +#### Pushing project to heroku + +Now, it is ready to be deployed. Steps to deploy the application on heroku + +1. git init +2. git add . +3. git commit -m "commit message" +4. heroku create 'name of the app as one word' +5. git push heroku master +6. heroku open(to launch the deployed application) + +After this step you will get an application like [this](http://thirdaysofpython-practice.herokuapp.com/) + +## Exercises: Day 26 + +1. You will build [this application](https://thirtydaysofpython-v1-final.herokuapp.com/). Only the text analyser part is left + + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 25 ](../25_Day_Pandas/25_pandas.md) | [Day 27 >>](../27_Day_Python_with_mongodb/27_python_with_mongodb.md) \ No newline at end of file diff --git a/26_python_web/index.html b/26_python_web/index.html new file mode 100644 index 0000000..e113900 --- /dev/null +++ b/26_python_web/index.html @@ -0,0 +1,1947 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 26 python web - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+

<< Day 25 | Day 27 >>

+

30DaysOfPython

+ +

📘 Day 26⚓︎

+

Python for Web⚓︎

+

Python is a general purpose programming language and it can be used for many places. In this section, we will see how we use Python for the web. There are many Python web frame works. Django and Flask are the most popular ones. Today, we will see how to use Flask for web development.

+

Flask⚓︎

+

Flask is a web development framework written in Python. Flask uses Jinja2 template engine. Flask can be also used with other modern front libraries such as React.

+

If you did not install the virtualenv package yet install it first. Virtual environment will allows to isolate project dependencies from the local machine dependencies.

+

Folder structure⚓︎

+

After completing all the step, your project file structure should look like this:

+
├── Procfile
+├── app.py
+├── env
+│   ├── bin
+├── requirements.txt
+├── static
+│   └── css
+│       └── main.css
+└── templates
+    ├── about.html
+    ├── home.html
+    ├── layout.html
+    ├── post.html
+    └── result.html
+
+

Setting up your project directory⚓︎

+

Follow the following steps to get started with Flask.

+

Step 1: install virtualenv using the following command.

+
pip install virtualenv
+
+

Step 2:

+
asabeneh@Asabeneh:~/Desktop$ mkdir python_for_web
+asabeneh@Asabeneh:~/Desktop$ cd python_for_web/
+asabeneh@Asabeneh:~/Desktop/python_for_web$ virtualenv venv
+asabeneh@Asabeneh:~/Desktop/python_for_web$ source venv/bin/activate
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip install Flask
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
+Click==7.0
+Flask==1.1.1
+itsdangerous==1.1.0
+Jinja2==2.10.3
+MarkupSafe==1.1.1
+Werkzeug==0.16.0
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$
+
+

We created a project director named python_for_web. Inside the project we created a virtual environment venv which could be any name but I prefer to call it venv. Then we activated the virtual environment. We used pip freeze to check the installed packages in the project directory. The result of pip freeze was empty because a package was not installed yet.

+

Now, let's create app.py file in the project directory and write the following code. The app.py file will be the main file in the project. The following code has flask module, os module.

+

Creating routes⚓︎

+

The home route.

+
# let's import the flask
+from flask import Flask
+import os # importing operating system module
+
+app = Flask(__name__)
+
+@app.route('/') # this decorator create the home route
+def home ():
+    return '<h1>Welcome</h1>'
+
+@app.route('/about')
+def about():
+    return '<h1>About us</h1>'
+
+
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

To run the flask application, write python app.py in the main flask application directory.

+

After you run python app.py check local host 5000.

+

Let us add additional route. +Creating about route

+
# let's import the flask
+from flask import Flask
+import os # importing operating system module
+
+app = Flask(__name__)
+
+@app.route('/') # this decorator create the home route
+def home ():
+    return '<h1>Welcome</h1>'
+
+@app.route('/about')
+def about():
+    return '<h1>About us</h1>'
+
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

Now, we added the about route in the above code. How about if we want to render an HTML file instead of string? It is possible to render HTML file using the function render_templae. Let us create a folder called templates and create home.html and about.html in the project directory. Let us also import the render_template function from flask.

+

Creating templates⚓︎

+

Create the HTML files inside templates folder.

+

home.html

+
<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Home</title>
+  </head>
+
+  <body>
+    <h1>Welcome Home</h1>
+  </body>
+</html>
+
+

about.html

+
<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>About</title>
+  </head>
+
+  <body>
+    <h1>About Us</h1>
+  </body>
+</html>
+
+

Python Script⚓︎

+

app.py

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+
+app = Flask(__name__)
+
+@app.route('/') # this decorator create the home route
+def home ():
+    return render_template('home.html')
+
+@app.route('/about')
+def about():
+    return render_template('about.html')
+
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

As you can see to go to different pages or to navigate we need a navigation. Let's add a link to each page or let's create a layout which we use to every page.

+ +
<ul>
+  <li><a href="/">Home</a></li>
+  <li><a href="/about">About</a></li>
+</ul>
+
+

Now, we can navigate between the pages using the above link. Let us create additional page which handle form data. You can call it any name, I like to call it post.html.

+

We can inject data to the HTML files using Jinja2 template engine.

+
# let's import the flask
+from flask import Flask, render_template, request, redirect, url_for
+import os # importing operating system module
+
+app = Flask(__name__)
+
+@app.route('/') # this decorator create the home route
+def home ():
+    techs = ['HTML', 'CSS', 'Flask', 'Python']
+    name = '30 Days Of Python Programming'
+    return render_template('home.html', techs=techs, name = name, title = 'Home')
+
+@app.route('/about')
+def about():
+    name = '30 Days Of Python Programming'
+    return render_template('about.html', name = name, title = 'About Us')
+
+@app.route('/post')
+def post():
+    name = 'Text Analyzer'
+    return render_template('post.html', name = name, title = name)
+
+
+if __name__ == '__main__':
+    # for deployment
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

Let's see the templates too:

+

home.html

+
<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>Home</title>
+  </head>
+
+  <body>
+    <ul>
+      <li><a href="/">Home</a></li>
+      <li><a href="/about">About</a></li>
+    </ul>
+    <h1>Welcome to {{name}}</h1>
+     <ul>
+    {% for tech in techs %}
+      <li>{{tech}}</li>
+    {% endfor %}
+    </ul>
+  </body>
+</html>
+
+

about.html

+
<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <title>About Us</title>
+  </head>
+
+  <body>
+    <ul>
+      <li><a href="/">Home</a></li>
+      <li><a href="/about">About</a></li>
+    </ul>
+    <h1>About Us</h1>
+    <h2>{{name}}</h2>
+  </body>
+</html>
+
+

Creating a layout⚓︎

+

In the template files, there are lots of repeated codes, we can write a layout and we can remove the repetition. Let's create layout.html inside the templates folder. +After we create the layout we will import to every file.

+

Serving Static File⚓︎

+

Create a static folder in your project directory. Inside the static folder create CSS or styles folder and create a CSS stylesheet. We use the url_for module to serve the static file.

+

layout.html

+
<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="UTF-8" />
+    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+    <link
+      href="https://fonts.googleapis.com/css?family=Lato:300,400|Nunito:300,400|Raleway:300,400,500&display=swap"
+      rel="stylesheet"
+    />
+    <link
+      rel="stylesheet"
+      href="{{ url_for('static', filename='css/main.css') }}"
+    />
+    {% if title %}
+    <title>30 Days of Python - {{ title}}</title>
+    {% else %}
+    <title>30 Days of Python</title>
+    {% endif %}
+  </head>
+
+  <body>
+    <header>
+      <div class="menu-container">
+        <div>
+          <a class="brand-name nav-link" href="/">30DaysOfPython</a>
+        </div>
+        <ul class="nav-lists">
+          <li class="nav-list">
+            <a class="nav-link active" href="{{ url_for('home') }}">Home</a>
+          </li>
+          <li class="nav-list">
+            <a class="nav-link active" href="{{ url_for('about') }}">About</a>
+          </li>
+          <li class="nav-list">
+            <a class="nav-link active" href="{{ url_for('post') }}"
+              >Text Analyzer</a
+            >
+          </li>
+        </ul>
+      </div>
+    </header>
+    <main>
+      {% block content %} {% endblock %}
+    </main>
+  </body>
+</html>
+
+

Now, lets remove all the repeated code in the other template files and import the layout.html. The href is using url_for function with the name of the route function to connect each navigation route.

+

home.html

+
{% extends 'layout.html' %} {% block content %}
+<div class="container">
+  <h1>Welcome to {{name}}</h1>
+  <p>
+    This application clean texts and analyse the number of word, characters and
+    most frequent words in the text. Check it out by click text analyzer at the
+    menu. You need the following technologies to build this web application:
+  </p>
+  <ul class="tech-lists">
+    {% for tech in techs %}
+    <li class="tech">{{tech}}</li>
+
+    {% endfor %}
+  </ul>
+</div>
+
+{% endblock %}
+
+

about.html

+
{% extends 'layout.html' %} {% block content %}
+<div class="container">
+  <h1>About {{name}}</h1>
+  <p>
+    This is a 30 days of python programming challenge. If you have been coding
+    this far, you are awesome. Congratulations for the job well done!
+  </p>
+</div>
+{% endblock %}
+
+

post.html

+
{% extends 'layout.html' %} {% block content %}
+<div class="container">
+  <h1>Text Analyzer</h1>
+  <form action="https://thirtydaysofpython-v1.herokuapp.com/post" method="POST">
+    <div>
+      <textarea rows="25" name="content" autofocus></textarea>
+    </div>
+    <div>
+      <input type="submit" class="btn" value="Process Text" />
+    </div>
+  </form>
+</div>
+
+{% endblock %}
+
+

Request methods, there are different request methods(GET, POST, PUT, DELETE) are the common request methods which allow us to do CRUD(Create, Read, Update, Delete) operation.

+

In the post, route we will use GET and POST method alternative depending on the type of request, check how it looks in the code below. The request method is a function to handle request methods and also to access form data. +app.py

+
# let's import the flask
+from flask import Flask, render_template, request, redirect, url_for
+import os # importing operating system module
+
+app = Flask(__name__)
+# to stop caching static file
+app.config['SEND_FILE_MAX_AGE_DEFAULT'] = 0
+
+
+
+@app.route('/') # this decorator create the home route
+def home ():
+    techs = ['HTML', 'CSS', 'Flask', 'Python']
+    name = '30 Days Of Python Programming'
+    return render_template('home.html', techs=techs, name = name, title = 'Home')
+
+@app.route('/about')
+def about():
+    name = '30 Days Of Python Programming'
+    return render_template('about.html', name = name, title = 'About Us')
+
+@app.route('/result')
+def result():
+    return render_template('result.html')
+
+@app.route('/post', methods= ['GET','POST'])
+def post():
+    name = 'Text Analyzer'
+    if request.method == 'GET':
+         return render_template('post.html', name = name, title = name)
+    if request.method =='POST':
+        content = request.form['content']
+        print(content)
+        return redirect(url_for('result'))
+
+if __name__ == '__main__':
+    # for deployment
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

So far, we have seen how to use template and how to inject data to template, how to a common layout. +Now, lets handle static file. Create a folder called static in the project director and create a folder called css. Inside css folder create main.css. Your main. css file will be linked to the layout.html.

+

You don't have to write the css file, copy and use it. Let's move on to deployment.

+

Deployment⚓︎

+

Creating Heroku account⚓︎

+

Heroku provides a free deployment service for both front end and fullstack applications. Create an account on heroku and install the heroku CLI for you machine. +After installing heroku write the following command

+

Login to Heroku⚓︎

+
asabeneh@Asabeneh:~$ heroku login
+heroku: Press any key to open up the browser to login or q to exit:
+
+

Let's see the result by clicking any key from the keyboard. When you press any key from you keyboard it will open the heroku login page and click the login page. Then you will local machine will be connected to the remote heroku server. If you are connected to remote server, you will see this.

+
asabeneh@Asabeneh:~$ heroku login
+heroku: Press any key to open up the browser to login or q to exit:
+Opening browser to https://cli-auth.heroku.com/auth/browser/be12987c-583a-4458-a2c2-ba2ce7f41610
+Logging in... done
+Logged in as asabeneh@gmail.com
+asabeneh@Asabeneh:~$
+
+

Create requirements and Procfile⚓︎

+

Before we push our code to remote server, we need requirements

+
    +
  • requirements.txt
  • +
  • Procfile
  • +
+
(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze
+Click==7.0
+Flask==1.1.1
+itsdangerous==1.1.0
+Jinja2==2.10.3
+MarkupSafe==1.1.1
+Werkzeug==0.16.0
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ touch requirements.txt
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ pip freeze > requirements.txt
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ cat requirements.txt
+Click==7.0
+Flask==1.1.1
+itsdangerous==1.1.0
+Jinja2==2.10.3
+MarkupSafe==1.1.1
+Werkzeug==0.16.0
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ touch Procfile
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$ ls
+Procfile          env/              static/
+app.py            requirements.txt  templates/
+(env) asabeneh@Asabeneh:~/Desktop/python_for_web$
+
+

The Procfile will have the command which run the application in the web server in our case on Heroku.

+
web: python app.py
+
+

Pushing project to heroku⚓︎

+

Now, it is ready to be deployed. Steps to deploy the application on heroku

+
    +
  1. git init
  2. +
  3. git add .
  4. +
  5. git commit -m "commit message"
  6. +
  7. heroku create 'name of the app as one word'
  8. +
  9. git push heroku master
  10. +
  11. heroku open(to launch the deployed application)
  12. +
+

After this step you will get an application like this

+

Exercises: Day 26⚓︎

+
    +
  1. You will build this application. Only the text analyser part is left
  2. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 25 | Day 27 >>

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/27_python_with_mongodb/27_python_with_mongodb.md b/27_python_with_mongodb/27_python_with_mongodb.md new file mode 100644 index 0000000..b708ed9 --- /dev/null +++ b/27_python_with_mongodb/27_python_with_mongodb.md @@ -0,0 +1,659 @@ +
+

30 Days Of Python: Day 27 - Python with MongoDB

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+ +
+ +[<< Day 26](../26_Day_Python_web/26_python_web.md) | [Day 28 >>](../28_Day_API/28_API.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 27](#-day-27) +- [Python with MongoDB](#python-with-mongodb) + - [MongoDB](#mongodb) + - [SQL versus NoSQL](#sql-versus-nosql) + - [Getting Connection String(MongoDB URI)](#getting-connection-stringmongodb-uri) + - [Connecting Flask application to MongoDB Cluster](#connecting-flask-application-to-mongodb-cluster) + - [Creating a database and collection](#creating-a-database-and-collection) + - [Inserting many documents to collection](#inserting-many-documents-to-collection) + - [MongoDB Find](#mongodb-find) + - [Find with Query](#find-with-query) + - [Find query with modifier](#find-query-with-modifier) + - [Limiting documents](#limiting-documents) + - [Find with sort](#find-with-sort) + - [Update with query](#update-with-query) + - [Delete Document](#delete-document) + - [Drop a collection](#drop-a-collection) + - [💻 Exercises: Day 27](#-exercises-day-27) + +# 📘 Day 27 + +# Python with MongoDB + +Python is a backend technology and it can be connected with different data base applications. It can be connected to both SQL and noSQL databases. In this section, we connect Python with MongoDB database which is noSQL database. + +## MongoDB + +MongoDB is a NoSQL database. MongoDB stores data in a JSON like document which make MongoDB very flexible and scalable. Let us see the different terminologies of SQL and NoSQL databases. The following table will make the difference between SQL versus NoSQL databases. + +### SQL versus NoSQL + +![SQL versus NoSQL](../images/mongoDB/sql-vs-nosql.png) + +In this section, we will focus on a NoSQL database MongoDB. Lets sign up on [mongoDB](https://www.mongodb.com/) by click on the sign in button then click register on the next page. + +![MongoDB Sign up pages](../images/mongoDB/mongodb-signup-page.png) + +Complete the fields and click continue + +![Mongodb register](../images/mongoDB/mongodb-register.png) + +Select the free plan + +![Mongodb free plan](../images/mongoDB/mongodb-free.png) + +Choose the proximate free region and give any name for you cluster. + +![Mongodb cluster name](../images/mongoDB/mongodb-cluster-name.png) + +Now, a free sandbox is created + +![Mongodb sandbox](../images/mongoDB/mongodb-sandbox.png) + +All local host access + +![Mongodb allow ip access](../images/mongoDB/mongodb-allow-ip-access.png) + +Add user and password + +![Mongodb add user](../images/mongoDB/mongodb-add-user.png) + +Create a mongoDB uri link + +![Mongodb create uri](../images/mongoDB/mongodb-create-uri.png) + +Select Python 3.6 or above driver + +![Mongodb python driver](../images/mongoDB/mongodb-python-driver.png) + +### Getting Connection String(MongoDB URI) + +Copy the connection string link and you will get something like this + +```sh +mongodb+srv://asabeneh:@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority +``` + +Do not worry about the url, it is a means to connect your application with mongoDB. +Let us replace the password placeholder with the password you used to add a user. + +**Example:** + +```sh +mongodb+srv://asabeneh:123123123@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority +``` + +Now, I replaced everything and the password is 123123 and the name of the database is thirty_days_python. This is just an example, your password must be a bit stronger than this. + +Python needs a mongoDB driver to access mongoDB database. We will use _pymongo_ with _dnspython_ to connect our application with mongoDB base . Inside your project directory install pymongo and dnspython. + +```sh +pip install pymongo dnspython +``` + +The "dnspython" module must be installed to use mongodb+srv:// URIs. The dnspython is a DNS toolkit for Python. It supports almost all record types. + +### Connecting Flask application to MongoDB Cluster + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +print(client.list_database_names()) + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) + +``` + +When we run the above code we get the default mongoDB databases. + +```sh +['admin', 'local'] +``` + +### Creating a database and collection + +Let us create a database, database and collection in mongoDB will be created if it doesn't exist. Let's create a data base name _thirty_days_of_python_ and _students_ collection. +To create a database + +```sh +db = client.name_of_databse # we can create a database like this or the second way +db = client['name_of_database'] +``` + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +# Creating database +db = client.thirty_days_of_python +# Creating students collection and inserting a document +db.students.insert_one({'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}) +print(client.list_database_names()) + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +After we create a database, we also created a students collection and we used *insert_one()* method to insert a document. +Now, the database *thirty_days_of_python* and *students* collection have been created and the document has been inserted. +Check your mongoDB cluster and you will see both the database and the collection. Inside the collection, there will be a document. + +```sh +['thirty_days_of_python', 'admin', 'local'] +``` + +If you see this on the mongoDB cluster, it means you have successfully created a database and a collection. + +![Creating database and collection](../images/mongoDB/mongodb-creating_database.png) + +If you have seen on the figure, the document has been created with a long id which acts as a primary key. Every time we create a document mongoDB create and unique id for it. + +### Inserting many documents to collection + +The *insert_one()* method inserts one item at a time if we want to insert many documents at once either we use *insert_many()* method or for loop. +We can use for loop to inset many documents at once. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) + +students = [ + {'name':'David','country':'UK','city':'London','age':34}, + {'name':'John','country':'Sweden','city':'Stockholm','age':28}, + {'name':'Sami','country':'Finland','city':'Helsinki','age':25}, + ] +for student in students: + db.students.insert_one(student) + + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +### MongoDB Find + +The *find()* and *findOne()* methods are common method to find data in a collection in mongoDB database. It is similar to the SELECT statement in a MySQL database. +Let us use the _find_one()_ method to get a document in a database collection. + +- \*find_one({"\_id": ObjectId("id"}): Gets the first occurrence if an id is not provided + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +student = db.students.find_one() +print(student) + + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) + +``` + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Helsinki', 'city': 'Helsinki', 'age': 250} +``` + +The above query returns the first entry but we can target specific document using specific \_id. Let us do one example, use David's id to get David object. +'\_id':ObjectId('5df68a23f106fe2d315bbc8c') + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +from bson.objectid import ObjectId # id object +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +student = db.students.find_one({'_id':ObjectId('5df68a23f106fe2d315bbc8c')}) +print(student) + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34} +``` + +We have seen, how to use _find_one()_ using the above examples. Let's move one to _find()_ + +- _find()_: returns all the occurrence from a collection if we don't pass a query object. The object is pymongo.cursor object. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +students = db.students.find() +for student in students: + print(student) + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250} +{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34} +{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28} +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +``` + +We can specify which fields to return by passing second object in the _find({}, {})_. 0 means not include and 1 means include but we can not mix 0 and 1, except for \_id. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +students = db.students.find({}, {"_id":0, "name": 1, "country":1}) # 0 means not include and 1 means include +for student in students: + print(student) + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'name': 'Asabeneh', 'country': 'Finland'} +{'name': 'David', 'country': 'UK'} +{'name': 'John', 'country': 'Sweden'} +{'name': 'Sami', 'country': 'Finland'} +``` + +### Find with Query + +In mongoDB find take a query object. We can pass a query object and we can filter the documents we like to filter out. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +query = { + "country":"Finland" +} +students = db.students.find(query) + +for student in students: + print(student) + + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250} +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +``` + +Query with modifiers + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +query = { + "city":"Helsinki" +} +students = db.students.find(query) +for student in students: + print(student) + + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250} +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +``` + +### Find query with modifier + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +query = { + "country":"Finland", + "city":"Helsinki" +} +students = db.students.find(query) +for student in students: + print(student) + + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250} +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +``` + +Query with modifiers + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +query = {"age":{"$gt":30}} +students = db.students.find(query) +for student in students: + print(student) + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250} +{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34} +``` + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +query = {"age":{"$gt":30}} +students = db.students.find(query) +for student in students: + print(student) +``` + +```sh +{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28} +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +``` + +### Limiting documents + +We can limit the number of documents we return using the _limit()_ method. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +db.students.find().limit(3) +``` + +### Find with sort + +By default, sort is in ascending order. We can change the sorting to descending order by adding -1 parameter. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +students = db.students.find().sort('name') +for student in students: + print(student) + + +students = db.students.find().sort('name',-1) +for student in students: + print(student) + +students = db.students.find().sort('age') +for student in students: + print(student) + +students = db.students.find().sort('age',-1) +for student in students: + print(student) + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +Ascending order + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250} +{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34} +{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28} +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +``` + +Descending order + +```sh +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28} +{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34} +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250} +``` + +### Update with query + +We will use *update_one()* method to update one item. It takes two object one is a query and the second is the new object. +The first person, Asabeneh got a very implausible age. Let us update Asabeneh's age. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +query = {'age':250} +new_value = {'$set':{'age':38}} + +db.students.update_one(query, new_value) +# lets check the result if the age is modified +for student in db.students.find(): + print(student) + + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 38} +{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34} +{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28} +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +``` + +When we want to update many documents at once we use *upate_many()* method. + +### Delete Document + +The method *delete_one()* deletes one document. The *delete_one()* takes a query object parameter. It only removes the first occurrence. +Let us remove one John from the collection. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +query = {'name':'John'} +db.students.delete_one(query) + +for student in db.students.find(): + print(student) +# lets check the result if the age is modified +for student in db.students.find(): + print(student) + + +app = Flask(__name__) +if __name__ == '__main__': + # for deployment we use the environ + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 38} +{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34} +{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25} +``` + +As you can see John has been removed from the collection. + +When we want to delete many documents we use *delete_many()* method, it takes a query object. If we pass an empty query object to *delete_many({})* it will delete all the documents in the collection. + +### Drop a collection + +Using the _drop()_ method we can delete a collection from a database. + +```py +# let's import the flask +from flask import Flask, render_template +import os # importing operating system module +import pymongo + +MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database +db.students.drop() +``` + +Now, we have deleted the students collection from the database. + +## 💻 Exercises: Day 27 + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 26](../26_Day_Python_web/26_python_web.md) | [Day 28 >>](../28_Day_API/28_API.md) diff --git a/27_python_with_mongodb/index.html b/27_python_with_mongodb/index.html new file mode 100644 index 0000000..5b02659 --- /dev/null +++ b/27_python_with_mongodb/index.html @@ -0,0 +1,1615 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 27 python with mongodb - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 27 - Python with MongoDB

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+ Second Edition: July, 2021 +
+ +
+ +

<< Day 26 | Day 28 >>

+

30DaysOfPython

+ +

📘 Day 27⚓︎

+

Python with MongoDB⚓︎

+

Python is a backend technology and it can be connected with different data base applications. It can be connected to both SQL and noSQL databases. In this section, we connect Python with MongoDB database which is noSQL database.

+

MongoDB⚓︎

+

MongoDB is a NoSQL database. MongoDB stores data in a JSON like document which make MongoDB very flexible and scalable. Let us see the different terminologies of SQL and NoSQL databases. The following table will make the difference between SQL versus NoSQL databases.

+

SQL versus NoSQL⚓︎

+

SQL versus NoSQL

+

In this section, we will focus on a NoSQL database MongoDB. Lets sign up on mongoDB by click on the sign in button then click register on the next page.

+

MongoDB Sign up pages

+

Complete the fields and click continue

+

Mongodb register

+

Select the free plan

+

Mongodb free plan

+

Choose the proximate free region and give any name for you cluster.

+

Mongodb cluster name

+

Now, a free sandbox is created

+

Mongodb sandbox

+

All local host access

+

Mongodb allow ip access

+

Add user and password

+

Mongodb add user

+

Create a mongoDB uri link

+

Mongodb create uri

+

Select Python 3.6 or above driver

+

Mongodb python driver

+

Getting Connection String(MongoDB URI)⚓︎

+

Copy the connection string link and you will get something like this

+
mongodb+srv://asabeneh:<password>@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority
+
+

Do not worry about the url, it is a means to connect your application with mongoDB. +Let us replace the password placeholder with the password you used to add a user.

+

Example:

+
mongodb+srv://asabeneh:123123123@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority
+
+

Now, I replaced everything and the password is 123123 and the name of the database is thirty_days_python. This is just an example, your password must be a bit stronger than this.

+

Python needs a mongoDB driver to access mongoDB database. We will use pymongo with dnspython to connect our application with mongoDB base . Inside your project directory install pymongo and dnspython.

+
pip install pymongo dnspython
+
+

The "dnspython" module must be installed to use mongodb+srv:// URIs. The dnspython is a DNS toolkit for Python. It supports almost all record types.

+

Connecting Flask application to MongoDB Cluster⚓︎

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+print(client.list_database_names())
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

When we run the above code we get the default mongoDB databases.

+
['admin', 'local']
+
+

Creating a database and collection⚓︎

+

Let us create a database, database and collection in mongoDB will be created if it doesn't exist. Let's create a data base name thirty_days_of_python and students collection. +To create a database

+
db = client.name_of_databse # we can create a database like this or the second way
+db = client['name_of_database']
+
+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+# Creating database
+db = client.thirty_days_of_python
+# Creating students collection and inserting a document
+db.students.insert_one({'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250})
+print(client.list_database_names())
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

After we create a database, we also created a students collection and we used insert_one() method to insert a document. +Now, the database thirty_days_of_python and students collection have been created and the document has been inserted. +Check your mongoDB cluster and you will see both the database and the collection. Inside the collection, there will be a document.

+
['thirty_days_of_python', 'admin', 'local']
+
+

If you see this on the mongoDB cluster, it means you have successfully created a database and a collection.

+

Creating database and collection

+

If you have seen on the figure, the document has been created with a long id which acts as a primary key. Every time we create a document mongoDB create and unique id for it.

+

Inserting many documents to collection⚓︎

+

The insert_one() method inserts one item at a time if we want to insert many documents at once either we use insert_many() method or for loop. +We can use for loop to inset many documents at once.

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+
+students = [
+        {'name':'David','country':'UK','city':'London','age':34},
+        {'name':'John','country':'Sweden','city':'Stockholm','age':28},
+        {'name':'Sami','country':'Finland','city':'Helsinki','age':25},
+    ]
+for student in students:
+    db.students.insert_one(student)
+
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

MongoDB Find⚓︎

+

The find() and findOne() methods are common method to find data in a collection in mongoDB database. It is similar to the SELECT statement in a MySQL database. +Let us use the find_one() method to get a document in a database collection.

+
    +
  • *find_one({"_id": ObjectId("id"}): Gets the first occurrence if an id is not provided
  • +
+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+student = db.students.find_one()
+print(student)
+
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Helsinki', 'city': 'Helsinki', 'age': 250}
+
+

The above query returns the first entry but we can target specific document using specific _id. Let us do one example, use David's id to get David object. +'_id':ObjectId('5df68a23f106fe2d315bbc8c')

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+from bson.objectid import ObjectId # id object
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+student = db.students.find_one({'_id':ObjectId('5df68a23f106fe2d315bbc8c')})
+print(student)
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34}
+
+

We have seen, how to use find_one() using the above examples. Let's move one to find()

+
    +
  • find(): returns all the occurrence from a collection if we don't pass a query object. The object is pymongo.cursor object.
  • +
+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+students = db.students.find()
+for student in students:
+    print(student)
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+
+

We can specify which fields to return by passing second object in the find({}, {}). 0 means not include and 1 means include but we can not mix 0 and 1, except for _id.

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+students = db.students.find({}, {"_id":0,  "name": 1, "country":1}) # 0 means not include and 1 means include
+for student in students:
+    print(student)
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'name': 'Asabeneh', 'country': 'Finland'}
+{'name': 'David', 'country': 'UK'}
+{'name': 'John', 'country': 'Sweden'}
+{'name': 'Sami', 'country': 'Finland'}
+
+

Find with Query⚓︎

+

In mongoDB find take a query object. We can pass a query object and we can filter the documents we like to filter out.

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+query = {
+    "country":"Finland"
+}
+students = db.students.find(query)
+
+for student in students:
+    print(student)
+
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+
+

Query with modifiers

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+query = {
+    "city":"Helsinki"
+}
+students = db.students.find(query)
+for student in students:
+    print(student)
+
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+
+

Find query with modifier⚓︎

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+query = {
+    "country":"Finland",
+    "city":"Helsinki"
+}
+students = db.students.find(query)
+for student in students:
+    print(student)
+
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+
+

Query with modifiers

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+query = {"age":{"$gt":30}}
+students = db.students.find(query)
+for student in students:
+    print(student)
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34}
+
+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+query = {"age":{"$gt":30}}
+students = db.students.find(query)
+for student in students:
+    print(student)
+
+
{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+
+

Limiting documents⚓︎

+

We can limit the number of documents we return using the limit() method.

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+db.students.find().limit(3)
+
+

Find with sort⚓︎

+

By default, sort is in ascending order. We can change the sorting to descending order by adding -1 parameter.

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+students = db.students.find().sort('name')
+for student in students:
+    print(student)
+
+
+students = db.students.find().sort('name',-1)
+for student in students:
+    print(student)
+
+students = db.students.find().sort('age')
+for student in students:
+    print(student)
+
+students = db.students.find().sort('age',-1)
+for student in students:
+    print(student)
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

Ascending order

+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+
+

Descending order

+
{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34}
+{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 250}
+
+

Update with query⚓︎

+

We will use update_one() method to update one item. It takes two object one is a query and the second is the new object. +The first person, Asabeneh got a very implausible age. Let us update Asabeneh's age.

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+query = {'age':250}
+new_value = {'$set':{'age':38}}
+
+db.students.update_one(query, new_value)
+# lets check the result if the age is modified
+for student in db.students.find():
+    print(student)
+
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 38}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8d'), 'name': 'John', 'country': 'Sweden', 'city': 'Stockholm', 'age': 28}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+
+

When we want to update many documents at once we use upate_many() method.

+

Delete Document⚓︎

+

The method delete_one() deletes one document. The delete_one() takes a query object parameter. It only removes the first occurrence. +Let us remove one John from the collection.

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+query = {'name':'John'}
+db.students.delete_one(query)
+
+for student in db.students.find():
+    print(student)
+# lets check the result if the age is modified
+for student in db.students.find():
+    print(student)
+
+
+app = Flask(__name__)
+if __name__ == '__main__':
+    # for deployment we use the environ
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
{'_id': ObjectId('5df68a21f106fe2d315bbc8b'), 'name': 'Asabeneh', 'country': 'Finland', 'city': 'Helsinki', 'age': 38}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8c'), 'name': 'David', 'country': 'UK', 'city': 'London', 'age': 34}
+{'_id': ObjectId('5df68a23f106fe2d315bbc8e'), 'name': 'Sami', 'country': 'Finland', 'city': 'Helsinki', 'age': 25}
+
+

As you can see John has been removed from the collection.

+

When we want to delete many documents we use delete_many() method, it takes a query object. If we pass an empty query object to delete_many({}) it will delete all the documents in the collection.

+

Drop a collection⚓︎

+

Using the drop() method we can delete a collection from a database.

+
# let's import the flask
+from flask import Flask, render_template
+import os # importing operating system module
+import pymongo
+
+MONGODB_URI = 'mongodb+srv://asabeneh:your_password_goes_here@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+db.students.drop()
+
+

Now, we have deleted the students collection from the database.

+

💻 Exercises: Day 27⚓︎

+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 26 | Day 28 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/28_API/28_API.md b/28_API/28_API.md new file mode 100644 index 0000000..18532bc --- /dev/null +++ b/28_API/28_API.md @@ -0,0 +1,162 @@ +
+

30 Days Of Python: Day 28 - API

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+ +
+ + +[<< Day 27](../27_Day_Python_with_mongodb/27_python_with_mongodb.md) | [Day 29 >>](../29_Day_Building_API/29_building_API.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [📘 Day 28](#-day-28) +- [Application Programming Interface(API)](#application-programming-interfaceapi) + - [API](#api) + - [Building API](#building-api) + - [HTTP(Hypertext Transfer Protocol)](#httphypertext-transfer-protocol) + - [Structure of HTTP](#structure-of-http) + - [Initial Request Line(Status Line)](#initial-request-linestatus-line) + - [Initial Response Line(Status Line)](#initial-response-linestatus-line) + - [Header Fields](#header-fields) + - [The message body](#the-message-body) + - [Request Methods](#request-methods) + - [💻 Exercises: Day 28](#-exercises-day-28) + +# 📘 Day 28 + +# Application Programming Interface(API) + +## API + +API stands for Application Programming Interface. The kind of API we will cover in this section is going to be Web APIs. +Web APIs are the defined interfaces through which interactions happen between an enterprise and applications that use its assets, which also is a Service Level Agreement (SLA) to specify the functional provider and expose the service path or URL for its API users. + +In the context of web development, an API is defined as a set of specifications, such as Hypertext Transfer Protocol (HTTP) request messages, along with a definition of the structure of response messages, usually in an XML or a JavaScript Object Notation (JSON) format. + +Web API has been moving away from Simple Object Access Protocol (SOAP) based web services and service-oriented architecture (SOA) towards more direct representational state transfer (REST) style web resources. + +Social media services, web APIs have allowed web communities to share content and data between communities and different platforms. + +Using API, content that is created in one place dynamically can be posted and updated to multiple locations on the web. + +For example, Twitter's REST API allows developers to access core Twitter data and the Search API provides methods for developers to interact with Twitter Search and trends data. + +Many applications provide API end points. Some examples of API such as the countries [API](https://restcountries.eu/rest/v2/all), [cat's breed API](https://api.thecatapi.com/v1/breeds). + +In this section, we will cover a RESTful API that uses HTTP request methods to GET, PUT, POST and DELETE data. + +## Building API + +RESTful API is an application program interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. In the previous sections, we have learned about python, flask and mongoDB. We will use the knowledge we acquire to develop a RESTful API using Python flask and mongoDB database. Every application which has CRUD(Create, Read, Update, Delete) operation has an API to create data, to get data, to update data or to delete data from a database. + +To build an API, it is good to understand HTTP protocol and HTTP request and response cycle. + +## HTTP(Hypertext Transfer Protocol) + +HTTP is an established communication protocol between a client and a server. A client in this case is a browser and server is the place where you access data. HTTP is a network protocol used to deliver resources which could be files on the World Wide Web, whether they are HTML files, image files, query results, scripts, or other file types. + +A browser is an HTTP client because it sends requests to an HTTP server (Web server), which then sends responses back to the client. + +## Structure of HTTP + +HTTP uses client-server model. An HTTP client opens a connection and sends a request message to an HTTP server and the HTTP server returns response message which is the requested resources. When the request response cycle completes the server closes the connection. + +![HTTP request response cycle](../images/http_request_response_cycle.png) + +The format of the request and response messages are similar. Both kinds of messages have + +- an initial line, +- zero or more header lines, +- a blank line (i.e. a CRLF by itself), and +- an optional message body (e.g. a file, or query data, or query output). + +Let us an example of request and response messages by navigating this site:https://thirtydaysofpython-v1-final.herokuapp.com/. This site has been deployed on Heroku free dyno and in some months may not work because of high request. Support this work to make the server run all the time. + +![Request and Response header](../images/request_response_header.png) + +## Initial Request Line(Status Line) + +The initial request line is different from the response. +A request line has three parts, separated by spaces: + +- method name(GET, POST, HEAD) +- path of the requested resource, +- the version of HTTP being used. eg GET / HTTP/1.1 + +GET is the most common HTTP that helps to get or read resource and POST is a common request method to create resource. + +### Initial Response Line(Status Line) + +The initial response line, called the status line, also has three parts separated by spaces: + +- HTTP version +- Response status code that gives the result of the request, and a reason which describes the status code. Example of status lines are: + HTTP/1.0 200 OK + or + HTTP/1.0 404 Not Found + Notes: + +The most common status codes are: +200 OK: The request succeeded, and the resulting resource (e.g. file or script output) is returned in the message body. +500 Server Error +A complete list of HTTP status code can be found [here](https://httpstatuses.com/). It can be also found [here](https://httpstatusdogs.com/). + +### Header Fields + +As you have seen in the above screenshot, header lines provide information about the request or response, or about the object sent in the message body. + +```sh +GET / HTTP/1.1 +Host: thirtydaysofpython-v1-final.herokuapp.com +Connection: keep-alive +Pragma: no-cache +Cache-Control: no-cache +Upgrade-Insecure-Requests: 1 +User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36 +Sec-Fetch-User: ?1 +Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9 +Sec-Fetch-Site: same-origin +Sec-Fetch-Mode: navigate +Referer: https://thirtydaysofpython-v1-final.herokuapp.com/post +Accept-Encoding: gzip, deflate, br +Accept-Language: en-GB,en;q=0.9,fi-FI;q=0.8,fi;q=0.7,en-CA;q=0.6,en-US;q=0.5,fr;q=0.4 +``` + +### The message body + +An HTTP message may have a body of data sent after the header lines. In a response, this is where the requested resource is returned to the client (the most common use of the message body), or perhaps explanatory text if there's an error. In a request, this is where user-entered data or uploaded files are sent to the server. + +If an HTTP message includes a body, there are usually header lines in the message that describe the body. In particular, + +The Content-Type: header gives the MIME-type of the data in the body(text/html, application/json, text/plain, text/css, image/gif). +The Content-Length: header gives the number of bytes in the body. + +### Request Methods + +The GET, POST, PUT and DELETE are the HTTP request methods which we are going to implement an API or a CRUD operation application. + +1. GET: GET method is used to retrieve and get information from the given server using a given URI. Requests using GET should only retrieve data and should have no other effect on the data. + +2. POST: POST request is used to create data and send data to the server, for example, creating a new post, file upload, etc. using HTML forms. + +3. PUT: Replaces all current representations of the target resource with the uploaded content and we use it modify or update data. + +4. DELETE: Removes data + +## 💻 Exercises: Day 28 + +1. Read about API and HTTP + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 27](../27_Day_Python_with_mongodb/27_python_with_mongodb.md) | [Day 29 >>](../29_Day_Building_API/29_building_API.md) diff --git a/28_API/index.html b/28_API/index.html new file mode 100644 index 0000000..bc713f3 --- /dev/null +++ b/28_API/index.html @@ -0,0 +1,1228 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 28 API - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+

<< Day 27 | Day 29 >>

+

30DaysOfPython

+ +

📘 Day 28⚓︎

+

Application Programming Interface(API)⚓︎

+

API⚓︎

+

API stands for Application Programming Interface. The kind of API we will cover in this section is going to be Web APIs. +Web APIs are the defined interfaces through which interactions happen between an enterprise and applications that use its assets, which also is a Service Level Agreement (SLA) to specify the functional provider and expose the service path or URL for its API users.

+

In the context of web development, an API is defined as a set of specifications, such as Hypertext Transfer Protocol (HTTP) request messages, along with a definition of the structure of response messages, usually in an XML or a JavaScript Object Notation (JSON) format.

+

Web API has been moving away from Simple Object Access Protocol (SOAP) based web services and service-oriented architecture (SOA) towards more direct representational state transfer (REST) style web resources.

+

Social media services, web APIs have allowed web communities to share content and data between communities and different platforms.

+

Using API, content that is created in one place dynamically can be posted and updated to multiple locations on the web.

+

For example, Twitter's REST API allows developers to access core Twitter data and the Search API provides methods for developers to interact with Twitter Search and trends data.

+

Many applications provide API end points. Some examples of API such as the countries API, cat's breed API.

+

In this section, we will cover a RESTful API that uses HTTP request methods to GET, PUT, POST and DELETE data.

+

Building API⚓︎

+

RESTful API is an application program interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. In the previous sections, we have learned about python, flask and mongoDB. We will use the knowledge we acquire to develop a RESTful API using Python flask and mongoDB database. Every application which has CRUD(Create, Read, Update, Delete) operation has an API to create data, to get data, to update data or to delete data from a database.

+

To build an API, it is good to understand HTTP protocol and HTTP request and response cycle.

+

HTTP(Hypertext Transfer Protocol)⚓︎

+

HTTP is an established communication protocol between a client and a server. A client in this case is a browser and server is the place where you access data. HTTP is a network protocol used to deliver resources which could be files on the World Wide Web, whether they are HTML files, image files, query results, scripts, or other file types.

+

A browser is an HTTP client because it sends requests to an HTTP server (Web server), which then sends responses back to the client.

+

Structure of HTTP⚓︎

+

HTTP uses client-server model. An HTTP client opens a connection and sends a request message to an HTTP server and the HTTP server returns response message which is the requested resources. When the request response cycle completes the server closes the connection.

+

HTTP request response cycle

+

The format of the request and response messages are similar. Both kinds of messages have

+
    +
  • an initial line,
  • +
  • zero or more header lines,
  • +
  • a blank line (i.e. a CRLF by itself), and
  • +
  • an optional message body (e.g. a file, or query data, or query output).
  • +
+

Let us an example of request and response messages by navigating this site:https://thirtydaysofpython-v1-final.herokuapp.com/. This site has been deployed on Heroku free dyno and in some months may not work because of high request. Support this work to make the server run all the time.

+

Request and Response header

+

Initial Request Line(Status Line)⚓︎

+

The initial request line is different from the response. +A request line has three parts, separated by spaces:

+
    +
  • method name(GET, POST, HEAD)
  • +
  • path of the requested resource,
  • +
  • the version of HTTP being used. eg GET / HTTP/1.1
  • +
+

GET is the most common HTTP that helps to get or read resource and POST is a common request method to create resource.

+

Initial Response Line(Status Line)⚓︎

+

The initial response line, called the status line, also has three parts separated by spaces:

+
    +
  • HTTP version
  • +
  • Response status code that gives the result of the request, and a reason which describes the status code. Example of status lines are: + HTTP/1.0 200 OK + or + HTTP/1.0 404 Not Found + Notes:
  • +
+

The most common status codes are: +200 OK: The request succeeded, and the resulting resource (e.g. file or script output) is returned in the message body. +500 Server Error +A complete list of HTTP status code can be found here. It can be also found here.

+

Header Fields⚓︎

+

As you have seen in the above screenshot, header lines provide information about the request or response, or about the object sent in the message body.

+
GET / HTTP/1.1
+Host: thirtydaysofpython-v1-final.herokuapp.com
+Connection: keep-alive
+Pragma: no-cache
+Cache-Control: no-cache
+Upgrade-Insecure-Requests: 1
+User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.79 Safari/537.36
+Sec-Fetch-User: ?1
+Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
+Sec-Fetch-Site: same-origin
+Sec-Fetch-Mode: navigate
+Referer: https://thirtydaysofpython-v1-final.herokuapp.com/post
+Accept-Encoding: gzip, deflate, br
+Accept-Language: en-GB,en;q=0.9,fi-FI;q=0.8,fi;q=0.7,en-CA;q=0.6,en-US;q=0.5,fr;q=0.4
+
+

The message body⚓︎

+

An HTTP message may have a body of data sent after the header lines. In a response, this is where the requested resource is returned to the client (the most common use of the message body), or perhaps explanatory text if there's an error. In a request, this is where user-entered data or uploaded files are sent to the server.

+

If an HTTP message includes a body, there are usually header lines in the message that describe the body. In particular,

+

The Content-Type: header gives the MIME-type of the data in the body(text/html, application/json, text/plain, text/css, image/gif). +The Content-Length: header gives the number of bytes in the body.

+

Request Methods⚓︎

+

The GET, POST, PUT and DELETE are the HTTP request methods which we are going to implement an API or a CRUD operation application.

+
    +
  1. +

    GET: GET method is used to retrieve and get information from the given server using a given URI. Requests using GET should only retrieve data and should have no other effect on the data.

    +
  2. +
  3. +

    POST: POST request is used to create data and send data to the server, for example, creating a new post, file upload, etc. using HTML forms.

    +
  4. +
  5. +

    PUT: Replaces all current representations of the target resource with the uploaded content and we use it modify or update data.

    +
  6. +
  7. +

    DELETE: Removes data

    +
  8. +
+

💻 Exercises: Day 28⚓︎

+
    +
  1. Read about API and HTTP
  2. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 27 | Day 29 >>

+ + + + + + + + + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + + + +
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/29_building_API/29_building_API.md b/29_building_API/29_building_API.md new file mode 100644 index 0000000..472b2c4 --- /dev/null +++ b/29_building_API/29_building_API.md @@ -0,0 +1,502 @@ +
+

30 Days Of Python: Day 29 - Building an API

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+ +
+ +[<< Day 28](../28_Day_API/28_API.md) | [Day 29 >>](../30_Day_Conclusions/30_conclusions.md) + +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [Day 29](#day-29) +- [Building API](#building-api) + - [Structure of an API](#structure-of-an-api) + - [Retrieving data using get](#retrieving-data-using-get) + - [Getting a document by id](#getting-a-document-by-id) + - [Creating data using POST](#creating-data-using-post) + - [Updating using PUT](#updating-using-put) + - [Deleting a document using Delete](#deleting-a-document-using-delete) +- [💻 Exercises: Day 29](#-exercises-day-29) + +## Day 29 + +## Building API + + +In this section, we will cove a RESTful API that uses HTTP request methods to GET, PUT, POST and DELETE data. + +RESTful API is an application program interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. In the previous sections, we have learned about python, flask and mongoDB. We will use the knowledge we acquire to develop a RESTful API using python flask and mongoDB. Every application which has CRUD(Create, Read, Update, Delete) operation has an API to create data, to get data, to update data or to delete data from database. + +The browser can handle only get request. Therefore, we have to have a tool which can help us to handle all request methods(GET, POST, PUT, DELETE). + +Examples of API + +- Countries API: https://restcountries.eu/rest/v2/all +- Cats breed API: https://api.thecatapi.com/v1/breeds + +[Postman](https://www.getpostman.com/) is a very popular tool when it comes to API development. So, if you like to do this section you need to [download postman](https://www.getpostman.com/). An alternative of Postman is [Insomnia](https://insomnia.rest/download). + +![Postman](../images/postman.png) + +### Structure of an API + +An API end point is a URL which can help to retrieve, create, update or delete a resource. The structure looks like this: +Example: +https://api.twitter.com/1.1/lists/members.json +Returns the members of the specified list. Private list members will only be shown if the authenticated user owns the specified list. +The name of the company name followed by version followed by the purpose of the API. +The methods: +HTTP methods & URLs + +The API uses the following HTTP methods for object manipulation: + +```sh +GET Used for object retrieval +POST Used for object creation and object actions +PUT Used for object update +DELETE Used for object deletion +``` + +Let us build an API which collects information about 30DaysOfPython students. We will collect the name, country, city, date of birth, skills and bio. + +To implement this API, we will use: + +- Postman +- Python +- Flask +- MongoDB + +### Retrieving data using get + +In this step, let us use dummy data and return it as a json. To return it as json, will use json module and Response module. + +```py +# let's import the flask + +from flask import Flask, Response +import json + +app = Flask(__name__) + +@app.route('/api/v1.0/students', methods = ['GET']) +def students (): + student_list = [ + { + 'name':'Asabeneh', + 'country':'Finland', + 'city':'Helsinki', + 'skills':['HTML', 'CSS','JavaScript','Python'] + }, + { + 'name':'David', + 'country':'UK', + 'city':'London', + 'skills':['Python','MongoDB'] + }, + { + 'name':'John', + 'country':'Sweden', + 'city':'Stockholm', + 'skills':['Java','C#'] + } + ] + return Response(json.dumps(student_list), mimetype='application/json') + + +if __name__ == '__main__': + # for deployment + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +When you request the http://localhost:5000/api/v1.0/students url on the browser you will get this: + +![Get on browser](../images/get_on_browser.png) + +When you request the http://localhost:5000/api/v1.0/students url on the browser you will get this: + +![Get on postman](../images/get_on_postman.png) + +In stead of displaying dummy data let us connect the flask application with MongoDB and get data from mongoDB database. + +```py +# let's import the flask + +from flask import Flask, Response +import json +import pymongo + + +app = Flask(__name__) + +# +MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +@app.route('/api/v1.0/students', methods = ['GET']) +def students (): + + return Response(json.dumps(student), mimetype='application/json') + + +if __name__ == '__main__': + # for deployment + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +By connecting the flask, we can fetch students collection data from the thirty_days_of_python database. + +```sh +[ + { + "_id": { + "$oid": "5df68a21f106fe2d315bbc8b" + }, + "name": "Asabeneh", + "country": "Finland", + "city": "Helsinki", + "age": 38 + }, + { + "_id": { + "$oid": "5df68a23f106fe2d315bbc8c" + }, + "name": "David", + "country": "UK", + "city": "London", + "age": 34 + }, + { + "_id": { + "$oid": "5df68a23f106fe2d315bbc8e" + }, + "name": "Sami", + "country": "Finland", + "city": "Helsinki", + "age": 25 + } +] +``` + +### Getting a document by id + +We can access signle document using an id, let's access Asabeneh using his id. +http://localhost:5000/api/v1.0/students/5df68a21f106fe2d315bbc8b + +```py +# let's import the flask + +from flask import Flask, Response +import json +from bson.objectid import ObjectId +import json +from bson.json_util import dumps +import pymongo + + +app = Flask(__name__) + +# +MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +@app.route('/api/v1.0/students', methods = ['GET']) +def students (): + + return Response(json.dumps(student), mimetype='application/json') +@app.route('/api/v1.0/students/', methods = ['GET']) +def single_student (id): + student = db.students.find({'_id':ObjectId(id)}) + return Response(dumps(student), mimetype='application/json') + +if __name__ == '__main__': + # for deployment + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +```sh +[ + { + "_id": { + "$oid": "5df68a21f106fe2d315bbc8b" + }, + "name": "Asabeneh", + "country": "Finland", + "city": "Helsinki", + "age": 38 + } +] +``` + +### Creating data using POST + +We use the POST request method to create data + +```py +# let's import the flask + +from flask import Flask, Response +import json +from bson.objectid import ObjectId +import json +from bson.json_util import dumps +import pymongo +from datetime import datetime + + +app = Flask(__name__) + +# +MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +@app.route('/api/v1.0/students', methods = ['GET']) +def students (): + + return Response(json.dumps(student), mimetype='application/json') +@app.route('/api/v1.0/students/', methods = ['GET']) +def single_student (id): + student = db.students.find({'_id':ObjectId(id)}) + return Response(dumps(student), mimetype='application/json') +@app.route('/api/v1.0/students', methods = ['POST']) +def create_student (): + name = request.form['name'] + country = request.form['country'] + city = request.form['city'] + skills = request.form['skills'].split(', ') + bio = request.form['bio'] + birthyear = request.form['birthyear'] + created_at = datetime.now() + student = { + 'name': name, + 'country': country, + 'city': city, + 'birthyear': birthyear, + 'skills': skills, + 'bio': bio, + 'created_at': created_at + + } + db.students.insert_one(student) + return ; +def update_student (id): +if __name__ == '__main__': + # for deployment + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +### Updating using PUT + +```py +# let's import the flask + +from flask import Flask, Response +import json +from bson.objectid import ObjectId +import json +from bson.json_util import dumps +import pymongo +from datetime import datetime + + +app = Flask(__name__) + +# +MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +@app.route('/api/v1.0/students', methods = ['GET']) +def students (): + + return Response(json.dumps(student), mimetype='application/json') +@app.route('/api/v1.0/students/', methods = ['GET']) +def single_student (id): + student = db.students.find({'_id':ObjectId(id)}) + return Response(dumps(student), mimetype='application/json') +@app.route('/api/v1.0/students', methods = ['POST']) +def create_student (): + name = request.form['name'] + country = request.form['country'] + city = request.form['city'] + skills = request.form['skills'].split(', ') + bio = request.form['bio'] + birthyear = request.form['birthyear'] + created_at = datetime.now() + student = { + 'name': name, + 'country': country, + 'city': city, + 'birthyear': birthyear, + 'skills': skills, + 'bio': bio, + 'created_at': created_at + + } + db.students.insert_one(student) + return +@app.route('/api/v1.0/students/', methods = ['PUT']) # this decorator create the home route +def update_student (id): + query = {"_id":ObjectId(id)} + name = request.form['name'] + country = request.form['country'] + city = request.form['city'] + skills = request.form['skills'].split(', ') + bio = request.form['bio'] + birthyear = request.form['birthyear'] + created_at = datetime.now() + student = { + 'name': name, + 'country': country, + 'city': city, + 'birthyear': birthyear, + 'skills': skills, + 'bio': bio, + 'created_at': created_at + + } + db.students.update_one(query, student) + # return Response(dumps({"result":"a new student has been created"}), mimetype='application/json') + return +def update_student (id): +if __name__ == '__main__': + # for deployment + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +### Deleting a document using Delete + +```py +# let's import the flask + +from flask import Flask, Response +import json +from bson.objectid import ObjectId +import json +from bson.json_util import dumps +import pymongo +from datetime import datetime + + +app = Flask(__name__) + +# +MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority' +client = pymongo.MongoClient(MONGODB_URI) +db = client['thirty_days_of_python'] # accessing the database + +@app.route('/api/v1.0/students', methods = ['GET']) +def students (): + + return Response(json.dumps(student), mimetype='application/json') +@app.route('/api/v1.0/students/', methods = ['GET']) +def single_student (id): + student = db.students.find({'_id':ObjectId(id)}) + return Response(dumps(student), mimetype='application/json') +@app.route('/api/v1.0/students', methods = ['POST']) +def create_student (): + name = request.form['name'] + country = request.form['country'] + city = request.form['city'] + skills = request.form['skills'].split(', ') + bio = request.form['bio'] + birthyear = request.form['birthyear'] + created_at = datetime.now() + student = { + 'name': name, + 'country': country, + 'city': city, + 'birthyear': birthyear, + 'skills': skills, + 'bio': bio, + 'created_at': created_at + + } + db.students.insert_one(student) + return +@app.route('/api/v1.0/students/', methods = ['PUT']) # this decorator create the home route +def update_student (id): + query = {"_id":ObjectId(id)} + name = request.form['name'] + country = request.form['country'] + city = request.form['city'] + skills = request.form['skills'].split(', ') + bio = request.form['bio'] + birthyear = request.form['birthyear'] + created_at = datetime.now() + student = { + 'name': name, + 'country': country, + 'city': city, + 'birthyear': birthyear, + 'skills': skills, + 'bio': bio, + 'created_at': created_at + + } + db.students.update_one(query, student) + # return Response(dumps({"result":"a new student has been created"}), mimetype='application/json') + return +@app.route('/api/v1.0/students/', methods = ['PUT']) # this decorator create the home route +def update_student (id): + query = {"_id":ObjectId(id)} + name = request.form['name'] + country = request.form['country'] + city = request.form['city'] + skills = request.form['skills'].split(', ') + bio = request.form['bio'] + birthyear = request.form['birthyear'] + created_at = datetime.now() + student = { + 'name': name, + 'country': country, + 'city': city, + 'birthyear': birthyear, + 'skills': skills, + 'bio': bio, + 'created_at': created_at + + } + db.students.update_one(query, student) + # return Response(dumps({"result":"a new student has been created"}), mimetype='application/json') + return ; +@app.route('/api/v1.0/students/', methods = ['DELETE']) +def delete_student (id): + db.students.delete_one({"_id":ObjectId(id)}) + return +if __name__ == '__main__': + # for deployment + # to make it work for both production and development + port = int(os.environ.get("PORT", 5000)) + app.run(debug=True, host='0.0.0.0', port=port) +``` + +## 💻 Exercises: Day 29 + +1. Implement the above example and develop [this](https://thirtydayofpython-api.herokuapp.com/) + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 28](../28_Day_API/28_API.md) | [Day 30 >>](../30_Day_Conclusions/30_conclusions.md) diff --git a/29_building_API/index.html b/29_building_API/index.html new file mode 100644 index 0000000..8a728d1 --- /dev/null +++ b/29_building_API/index.html @@ -0,0 +1,1759 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 29 building API - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+

30 Days Of Python: Day 29 - Building an API

+ + + + + Twitter Follow + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+ +
+ +

<< Day 28 | Day 29 >>

+

30DaysOfPython

+ +

Day 29⚓︎

+

Building API⚓︎

+

In this section, we will cove a RESTful API that uses HTTP request methods to GET, PUT, POST and DELETE data.

+

RESTful API is an application program interface (API) that uses HTTP requests to GET, PUT, POST and DELETE data. In the previous sections, we have learned about python, flask and mongoDB. We will use the knowledge we acquire to develop a RESTful API using python flask and mongoDB. Every application which has CRUD(Create, Read, Update, Delete) operation has an API to create data, to get data, to update data or to delete data from database.

+

The browser can handle only get request. Therefore, we have to have a tool which can help us to handle all request methods(GET, POST, PUT, DELETE).

+

Examples of API

+
    +
  • Countries API: https://restcountries.eu/rest/v2/all
  • +
  • Cats breed API: https://api.thecatapi.com/v1/breeds
  • +
+

Postman is a very popular tool when it comes to API development. So, if you like to do this section you need to download postman. An alternative of Postman is Insomnia.

+

Postman

+

Structure of an API⚓︎

+

An API end point is a URL which can help to retrieve, create, update or delete a resource. The structure looks like this: +Example: +https://api.twitter.com/1.1/lists/members.json +Returns the members of the specified list. Private list members will only be shown if the authenticated user owns the specified list. +The name of the company name followed by version followed by the purpose of the API. +The methods: +HTTP methods & URLs

+

The API uses the following HTTP methods for object manipulation:

+
GET        Used for object retrieval
+POST       Used for object creation and object actions
+PUT        Used for object update
+DELETE     Used for object deletion
+
+

Let us build an API which collects information about 30DaysOfPython students. We will collect the name, country, city, date of birth, skills and bio.

+

To implement this API, we will use:

+
    +
  • Postman
  • +
  • Python
  • +
  • Flask
  • +
  • MongoDB
  • +
+

Retrieving data using get⚓︎

+

In this step, let us use dummy data and return it as a json. To return it as json, will use json module and Response module.

+
# let's import the flask
+
+from flask import Flask,  Response
+import json
+
+app = Flask(__name__)
+
+@app.route('/api/v1.0/students', methods = ['GET'])
+def students ():
+    student_list = [
+        {
+            'name':'Asabeneh',
+            'country':'Finland',
+            'city':'Helsinki',
+            'skills':['HTML', 'CSS','JavaScript','Python']
+        },
+        {
+            'name':'David',
+            'country':'UK',
+            'city':'London',
+            'skills':['Python','MongoDB']
+        },
+        {
+            'name':'John',
+            'country':'Sweden',
+            'city':'Stockholm',
+            'skills':['Java','C#']
+        }
+    ]
+    return Response(json.dumps(student_list), mimetype='application/json')
+
+
+if __name__ == '__main__':
+    # for deployment
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

When you request the http://localhost:5000/api/v1.0/students url on the browser you will get this:

+

Get on browser

+

When you request the http://localhost:5000/api/v1.0/students url on the browser you will get this:

+

Get on postman

+

In stead of displaying dummy data let us connect the flask application with MongoDB and get data from mongoDB database.

+
# let's import the flask
+
+from flask import Flask,  Response
+import json
+import pymongo
+
+
+app = Flask(__name__)
+
+#
+MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+@app.route('/api/v1.0/students', methods = ['GET'])
+def students ():
+
+    return Response(json.dumps(student), mimetype='application/json')
+
+
+if __name__ == '__main__':
+    # for deployment
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

By connecting the flask, we can fetch students collection data from the thirty_days_of_python database.

+
[
+    {
+        "_id": {
+            "$oid": "5df68a21f106fe2d315bbc8b"
+        },
+        "name": "Asabeneh",
+        "country": "Finland",
+        "city": "Helsinki",
+        "age": 38
+    },
+    {
+        "_id": {
+            "$oid": "5df68a23f106fe2d315bbc8c"
+        },
+        "name": "David",
+        "country": "UK",
+        "city": "London",
+        "age": 34
+    },
+    {
+        "_id": {
+            "$oid": "5df68a23f106fe2d315bbc8e"
+        },
+        "name": "Sami",
+        "country": "Finland",
+        "city": "Helsinki",
+        "age": 25
+    }
+]
+
+

Getting a document by id⚓︎

+

We can access signle document using an id, let's access Asabeneh using his id. +http://localhost:5000/api/v1.0/students/5df68a21f106fe2d315bbc8b

+
# let's import the flask
+
+from flask import Flask,  Response
+import json
+from bson.objectid import ObjectId
+import json
+from bson.json_util import dumps
+import pymongo
+
+
+app = Flask(__name__)
+
+#
+MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+@app.route('/api/v1.0/students', methods = ['GET'])
+def students ():
+
+    return Response(json.dumps(student), mimetype='application/json')
+@app.route('/api/v1.0/students/<id>', methods = ['GET'])
+def single_student (id):
+    student = db.students.find({'_id':ObjectId(id)})
+    return Response(dumps(student), mimetype='application/json')
+
+if __name__ == '__main__':
+    # for deployment
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+
[
+    {
+        "_id": {
+            "$oid": "5df68a21f106fe2d315bbc8b"
+        },
+        "name": "Asabeneh",
+        "country": "Finland",
+        "city": "Helsinki",
+        "age": 38
+    }
+]
+
+

Creating data using POST⚓︎

+

We use the POST request method to create data

+
# let's import the flask
+
+from flask import Flask,  Response
+import json
+from bson.objectid import ObjectId
+import json
+from bson.json_util import dumps
+import pymongo
+from datetime import datetime
+
+
+app = Flask(__name__)
+
+#
+MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+@app.route('/api/v1.0/students', methods = ['GET'])
+def students ():
+
+    return Response(json.dumps(student), mimetype='application/json')
+@app.route('/api/v1.0/students/<id>', methods = ['GET'])
+def single_student (id):
+    student = db.students.find({'_id':ObjectId(id)})
+    return Response(dumps(student), mimetype='application/json')
+@app.route('/api/v1.0/students', methods = ['POST'])
+def create_student ():
+    name = request.form['name']
+    country = request.form['country']
+    city = request.form['city']
+    skills = request.form['skills'].split(', ')
+    bio = request.form['bio']
+    birthyear = request.form['birthyear']
+    created_at = datetime.now()
+    student = {
+        'name': name,
+        'country': country,
+        'city': city,
+        'birthyear': birthyear,
+        'skills': skills,
+        'bio': bio,
+        'created_at': created_at
+
+    }
+    db.students.insert_one(student)
+    return ;
+def update_student (id):
+if __name__ == '__main__':
+    # for deployment
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

Updating using PUT⚓︎

+
# let's import the flask
+
+from flask import Flask,  Response
+import json
+from bson.objectid import ObjectId
+import json
+from bson.json_util import dumps
+import pymongo
+from datetime import datetime
+
+
+app = Flask(__name__)
+
+#
+MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+@app.route('/api/v1.0/students', methods = ['GET'])
+def students ():
+
+    return Response(json.dumps(student), mimetype='application/json')
+@app.route('/api/v1.0/students/<id>', methods = ['GET'])
+def single_student (id):
+    student = db.students.find({'_id':ObjectId(id)})
+    return Response(dumps(student), mimetype='application/json')
+@app.route('/api/v1.0/students', methods = ['POST'])
+def create_student ():
+    name = request.form['name']
+    country = request.form['country']
+    city = request.form['city']
+    skills = request.form['skills'].split(', ')
+    bio = request.form['bio']
+    birthyear = request.form['birthyear']
+    created_at = datetime.now()
+    student = {
+        'name': name,
+        'country': country,
+        'city': city,
+        'birthyear': birthyear,
+        'skills': skills,
+        'bio': bio,
+        'created_at': created_at
+
+    }
+    db.students.insert_one(student)
+    return
+@app.route('/api/v1.0/students/<id>', methods = ['PUT']) # this decorator create the home route
+def update_student (id):
+    query = {"_id":ObjectId(id)}
+    name = request.form['name']
+    country = request.form['country']
+    city = request.form['city']
+    skills = request.form['skills'].split(', ')
+    bio = request.form['bio']
+    birthyear = request.form['birthyear']
+    created_at = datetime.now()
+    student = {
+        'name': name,
+        'country': country,
+        'city': city,
+        'birthyear': birthyear,
+        'skills': skills,
+        'bio': bio,
+        'created_at': created_at
+
+    }
+    db.students.update_one(query, student)
+    # return Response(dumps({"result":"a new student has been created"}), mimetype='application/json')
+    return
+def update_student (id):
+if __name__ == '__main__':
+    # for deployment
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

Deleting a document using Delete⚓︎

+
# let's import the flask
+
+from flask import Flask,  Response
+import json
+from bson.objectid import ObjectId
+import json
+from bson.json_util import dumps
+import pymongo
+from datetime import datetime
+
+
+app = Flask(__name__)
+
+#
+MONGODB_URI='mongodb+srv://asabeneh:your_password@30daysofpython-twxkr.mongodb.net/test?retryWrites=true&w=majority'
+client = pymongo.MongoClient(MONGODB_URI)
+db = client['thirty_days_of_python'] # accessing the database
+
+@app.route('/api/v1.0/students', methods = ['GET'])
+def students ():
+
+    return Response(json.dumps(student), mimetype='application/json')
+@app.route('/api/v1.0/students/<id>', methods = ['GET'])
+def single_student (id):
+    student = db.students.find({'_id':ObjectId(id)})
+    return Response(dumps(student), mimetype='application/json')
+@app.route('/api/v1.0/students', methods = ['POST'])
+def create_student ():
+    name = request.form['name']
+    country = request.form['country']
+    city = request.form['city']
+    skills = request.form['skills'].split(', ')
+    bio = request.form['bio']
+    birthyear = request.form['birthyear']
+    created_at = datetime.now()
+    student = {
+        'name': name,
+        'country': country,
+        'city': city,
+        'birthyear': birthyear,
+        'skills': skills,
+        'bio': bio,
+        'created_at': created_at
+
+    }
+    db.students.insert_one(student)
+    return
+@app.route('/api/v1.0/students/<id>', methods = ['PUT']) # this decorator create the home route
+def update_student (id):
+    query = {"_id":ObjectId(id)}
+    name = request.form['name']
+    country = request.form['country']
+    city = request.form['city']
+    skills = request.form['skills'].split(', ')
+    bio = request.form['bio']
+    birthyear = request.form['birthyear']
+    created_at = datetime.now()
+    student = {
+        'name': name,
+        'country': country,
+        'city': city,
+        'birthyear': birthyear,
+        'skills': skills,
+        'bio': bio,
+        'created_at': created_at
+
+    }
+    db.students.update_one(query, student)
+    # return Response(dumps({"result":"a new student has been created"}), mimetype='application/json')
+    return
+@app.route('/api/v1.0/students/<id>', methods = ['PUT']) # this decorator create the home route
+def update_student (id):
+    query = {"_id":ObjectId(id)}
+    name = request.form['name']
+    country = request.form['country']
+    city = request.form['city']
+    skills = request.form['skills'].split(', ')
+    bio = request.form['bio']
+    birthyear = request.form['birthyear']
+    created_at = datetime.now()
+    student = {
+        'name': name,
+        'country': country,
+        'city': city,
+        'birthyear': birthyear,
+        'skills': skills,
+        'bio': bio,
+        'created_at': created_at
+
+    }
+    db.students.update_one(query, student)
+    # return Response(dumps({"result":"a new student has been created"}), mimetype='application/json')
+    return ;
+@app.route('/api/v1.0/students/<id>', methods = ['DELETE'])
+def delete_student (id):
+    db.students.delete_one({"_id":ObjectId(id)})
+    return
+if __name__ == '__main__':
+    # for deployment
+    # to make it work for both production and development
+    port = int(os.environ.get("PORT", 5000))
+    app.run(debug=True, host='0.0.0.0', port=port)
+
+

💻 Exercises: Day 29⚓︎

+
    +
  1. Implement the above example and develop this
  2. +
+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 28 | Day 30 >>

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/30_conclusions/30_conclusions.md b/30_conclusions/30_conclusions.md new file mode 100644 index 0000000..e8865fc --- /dev/null +++ b/30_conclusions/30_conclusions.md @@ -0,0 +1,40 @@ +
+ +

30 Days Of Python: Day 30- Conclusions

+ + + + + Twitter Follow + + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+ +
+ +[<< Day 29](../29_Day_Building_API/29_building_API.md) +![30DaysOfPython](../images/30DaysOfPython_banner3@2x.png) + +- [Day 30](#day-30) + - [Conclusions](#conclusions) + +# Day 30 + + +## Conclusions + +In the process of preparing this material I have learned quite a lot and you have inspired me to do more. Congratulations for making it to this level. If you have done all the exercise and the projects, now you are capable to go to a data analysis, data science, machine learning or web development paths. [Support the author for more educational materials](https://www.paypal.com/paypalme/asabeneh). + +## Testimony +Now it is time to express your thoughts about the Author and 30DaysOfPyhton. You can leave your testimonial on this [link](https://testimonial-vdzd.onrender.com/) + +GIVE FEEDBACK: +http://thirtydayofpython-api.herokuapp.com/feedback + +🎉 CONGRATULATIONS ! 🎉 + +[<< Day 29](../29_Day_Building_API/29_building_API.md) diff --git a/30_conclusions/index.html b/30_conclusions/index.html new file mode 100644 index 0000000..e74b8a0 --- /dev/null +++ b/30_conclusions/index.html @@ -0,0 +1,1186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + 30 conclusions - 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + 跳转至 + + +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+ +

30 Days Of Python: Day 30- Conclusions

+ + + + + Twitter Follow + + + +Author: +Asabeneh Yetayeh
+Second Edition: July, 2021 +
+ +
+ +

<< Day 29 +30DaysOfPython

+ +

Day 30⚓︎

+

Conclusions⚓︎

+

In the process of preparing this material I have learned quite a lot and you have inspired me to do more. Congratulations for making it to this level. If you have done all the exercise and the projects, now you are capable to go to a data analysis, data science, machine learning or web development paths. Support the author for more educational materials.

+

Testimony⚓︎

+

Now it is time to express your thoughts about the Author and 30DaysOfPyhton. You can leave your testimonial on this link

+

GIVE FEEDBACK: +http://thirtydayofpython-api.herokuapp.com/feedback

+

🎉 CONGRATULATIONS ! 🎉

+

<< Day 29

+ + + + + + + + + + + + + + + + + + + + + + +
+
+ + + +
+ + + +
+ + + +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/404.html b/404.html new file mode 100644 index 0000000..22df04d --- /dev/null +++ b/404.html @@ -0,0 +1,974 @@ + + + + + + + + + + + + + + + + + + + + + + + 30天入门Python全栈开发 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + + +
+ + + +
+ +
+ + + + +
+ +
+
+
+
+ +
+ + + + + + + + + + \ No newline at end of file diff --git a/assets/favicon.jpg b/assets/favicon.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0131458924a60213933b63aaaffbfe3c1fe5a1d8 GIT binary patch literal 715300 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

  • 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
  • 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 IM6N<$f(jP3KmY&$ literal 0 HcmV?d00001 diff --git a/assets/javascripts/bundle.d7c377c4.min.js b/assets/javascripts/bundle.d7c377c4.min.js new file mode 100644 index 0000000..6a0bcf8 --- /dev/null +++ b/assets/javascripts/bundle.d7c377c4.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Mi=Object.create;var gr=Object.defineProperty;var Li=Object.getOwnPropertyDescriptor;var _i=Object.getOwnPropertyNames,Ft=Object.getOwnPropertySymbols,Ai=Object.getPrototypeOf,xr=Object.prototype.hasOwnProperty,ro=Object.prototype.propertyIsEnumerable;var to=(e,t,r)=>t in e?gr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))xr.call(t,r)&&to(e,r,t[r]);if(Ft)for(var r of Ft(t))ro.call(t,r)&&to(e,r,t[r]);return e};var oo=(e,t)=>{var r={};for(var o in e)xr.call(e,o)&&t.indexOf(o)<0&&(r[o]=e[o]);if(e!=null&&Ft)for(var o of Ft(e))t.indexOf(o)<0&&ro.call(e,o)&&(r[o]=e[o]);return r};var yr=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Ci=(e,t,r,o)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of _i(t))!xr.call(e,n)&&n!==r&&gr(e,n,{get:()=>t[n],enumerable:!(o=Li(t,n))||o.enumerable});return e};var jt=(e,t,r)=>(r=e!=null?Mi(Ai(e)):{},Ci(t||!e||!e.__esModule?gr(r,"default",{value:e,enumerable:!0}):r,e));var no=(e,t,r)=>new Promise((o,n)=>{var i=c=>{try{a(r.next(c))}catch(p){n(p)}},s=c=>{try{a(r.throw(c))}catch(p){n(p)}},a=c=>c.done?o(c.value):Promise.resolve(c.value).then(i,s);a((r=r.apply(e,t)).next())});var ao=yr((Er,io)=>{(function(e,t){typeof Er=="object"&&typeof io!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(Er,function(){"use strict";function e(r){var o=!0,n=!1,i=null,s={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function a(C){return!!(C&&C!==document&&C.nodeName!=="HTML"&&C.nodeName!=="BODY"&&"classList"in C&&"contains"in C.classList)}function c(C){var ct=C.type,Ve=C.tagName;return!!(Ve==="INPUT"&&s[ct]&&!C.readOnly||Ve==="TEXTAREA"&&!C.readOnly||C.isContentEditable)}function p(C){C.classList.contains("focus-visible")||(C.classList.add("focus-visible"),C.setAttribute("data-focus-visible-added",""))}function l(C){C.hasAttribute("data-focus-visible-added")&&(C.classList.remove("focus-visible"),C.removeAttribute("data-focus-visible-added"))}function f(C){C.metaKey||C.altKey||C.ctrlKey||(a(r.activeElement)&&p(r.activeElement),o=!0)}function u(C){o=!1}function d(C){a(C.target)&&(o||c(C.target))&&p(C.target)}function y(C){a(C.target)&&(C.target.classList.contains("focus-visible")||C.target.hasAttribute("data-focus-visible-added"))&&(n=!0,window.clearTimeout(i),i=window.setTimeout(function(){n=!1},100),l(C.target))}function b(C){document.visibilityState==="hidden"&&(n&&(o=!0),D())}function D(){document.addEventListener("mousemove",J),document.addEventListener("mousedown",J),document.addEventListener("mouseup",J),document.addEventListener("pointermove",J),document.addEventListener("pointerdown",J),document.addEventListener("pointerup",J),document.addEventListener("touchmove",J),document.addEventListener("touchstart",J),document.addEventListener("touchend",J)}function Q(){document.removeEventListener("mousemove",J),document.removeEventListener("mousedown",J),document.removeEventListener("mouseup",J),document.removeEventListener("pointermove",J),document.removeEventListener("pointerdown",J),document.removeEventListener("pointerup",J),document.removeEventListener("touchmove",J),document.removeEventListener("touchstart",J),document.removeEventListener("touchend",J)}function J(C){C.target.nodeName&&C.target.nodeName.toLowerCase()==="html"||(o=!1,Q())}document.addEventListener("keydown",f,!0),document.addEventListener("mousedown",u,!0),document.addEventListener("pointerdown",u,!0),document.addEventListener("touchstart",u,!0),document.addEventListener("visibilitychange",b,!0),D(),r.addEventListener("focus",d,!0),r.addEventListener("blur",y,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var Kr=yr((kt,qr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof kt=="object"&&typeof qr=="object"?qr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof kt=="object"?kt.ClipboardJS=r():t.ClipboardJS=r()})(kt,function(){return function(){var e={686:function(o,n,i){"use strict";i.d(n,{default:function(){return Oi}});var s=i(279),a=i.n(s),c=i(370),p=i.n(c),l=i(817),f=i.n(l);function u(V){try{return document.execCommand(V)}catch(_){return!1}}var d=function(_){var O=f()(_);return u("cut"),O},y=d;function b(V){var _=document.documentElement.getAttribute("dir")==="rtl",O=document.createElement("textarea");O.style.fontSize="12pt",O.style.border="0",O.style.padding="0",O.style.margin="0",O.style.position="absolute",O.style[_?"right":"left"]="-9999px";var $=window.pageYOffset||document.documentElement.scrollTop;return O.style.top="".concat($,"px"),O.setAttribute("readonly",""),O.value=V,O}var D=function(_,O){var $=b(_);O.container.appendChild($);var N=f()($);return u("copy"),$.remove(),N},Q=function(_){var O=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},$="";return typeof _=="string"?$=D(_,O):_ instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(_==null?void 0:_.type)?$=D(_.value,O):($=f()(_),u("copy")),$},J=Q;function C(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?C=function(O){return typeof O}:C=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},C(V)}var ct=function(){var _=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},O=_.action,$=O===void 0?"copy":O,N=_.container,Y=_.target,ke=_.text;if($!=="copy"&&$!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(Y!==void 0)if(Y&&C(Y)==="object"&&Y.nodeType===1){if($==="copy"&&Y.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if($==="cut"&&(Y.hasAttribute("readonly")||Y.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(ke)return J(ke,{container:N});if(Y)return $==="cut"?y(Y):J(Y,{container:N})},Ve=ct;function Fe(V){"@babel/helpers - typeof";return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Fe=function(O){return typeof O}:Fe=function(O){return O&&typeof Symbol=="function"&&O.constructor===Symbol&&O!==Symbol.prototype?"symbol":typeof O},Fe(V)}function vi(V,_){if(!(V instanceof _))throw new TypeError("Cannot call a class as a function")}function eo(V,_){for(var O=0;O<_.length;O++){var $=_[O];$.enumerable=$.enumerable||!1,$.configurable=!0,"value"in $&&($.writable=!0),Object.defineProperty(V,$.key,$)}}function gi(V,_,O){return _&&eo(V.prototype,_),O&&eo(V,O),V}function xi(V,_){if(typeof _!="function"&&_!==null)throw new TypeError("Super expression must either be null or a function");V.prototype=Object.create(_&&_.prototype,{constructor:{value:V,writable:!0,configurable:!0}}),_&&br(V,_)}function br(V,_){return br=Object.setPrototypeOf||function($,N){return $.__proto__=N,$},br(V,_)}function yi(V){var _=Ti();return function(){var $=Rt(V),N;if(_){var Y=Rt(this).constructor;N=Reflect.construct($,arguments,Y)}else N=$.apply(this,arguments);return Ei(this,N)}}function Ei(V,_){return _&&(Fe(_)==="object"||typeof _=="function")?_:wi(V)}function wi(V){if(V===void 0)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return V}function Ti(){if(typeof Reflect=="undefined"||!Reflect.construct||Reflect.construct.sham)return!1;if(typeof Proxy=="function")return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(V){return!1}}function Rt(V){return Rt=Object.setPrototypeOf?Object.getPrototypeOf:function(O){return O.__proto__||Object.getPrototypeOf(O)},Rt(V)}function vr(V,_){var O="data-clipboard-".concat(V);if(_.hasAttribute(O))return _.getAttribute(O)}var Si=function(V){xi(O,V);var _=yi(O);function O($,N){var Y;return vi(this,O),Y=_.call(this),Y.resolveOptions(N),Y.listenClick($),Y}return gi(O,[{key:"resolveOptions",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof N.action=="function"?N.action:this.defaultAction,this.target=typeof N.target=="function"?N.target:this.defaultTarget,this.text=typeof N.text=="function"?N.text:this.defaultText,this.container=Fe(N.container)==="object"?N.container:document.body}},{key:"listenClick",value:function(N){var Y=this;this.listener=p()(N,"click",function(ke){return Y.onClick(ke)})}},{key:"onClick",value:function(N){var Y=N.delegateTarget||N.currentTarget,ke=this.action(Y)||"copy",It=Ve({action:ke,container:this.container,target:this.target(Y),text:this.text(Y)});this.emit(It?"success":"error",{action:ke,text:It,trigger:Y,clearSelection:function(){Y&&Y.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(N){return vr("action",N)}},{key:"defaultTarget",value:function(N){var Y=vr("target",N);if(Y)return document.querySelector(Y)}},{key:"defaultText",value:function(N){return vr("text",N)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(N){var Y=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return J(N,Y)}},{key:"cut",value:function(N){return y(N)}},{key:"isSupported",value:function(){var N=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],Y=typeof N=="string"?[N]:N,ke=!!document.queryCommandSupported;return Y.forEach(function(It){ke=ke&&!!document.queryCommandSupported(It)}),ke}}]),O}(a()),Oi=Si},828:function(o){var n=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function s(a,c){for(;a&&a.nodeType!==n;){if(typeof a.matches=="function"&&a.matches(c))return a;a=a.parentNode}}o.exports=s},438:function(o,n,i){var s=i(828);function a(l,f,u,d,y){var b=p.apply(this,arguments);return l.addEventListener(u,b,y),{destroy:function(){l.removeEventListener(u,b,y)}}}function c(l,f,u,d,y){return typeof l.addEventListener=="function"?a.apply(null,arguments):typeof u=="function"?a.bind(null,document).apply(null,arguments):(typeof l=="string"&&(l=document.querySelectorAll(l)),Array.prototype.map.call(l,function(b){return a(b,f,u,d,y)}))}function p(l,f,u,d){return function(y){y.delegateTarget=s(y.target,f),y.delegateTarget&&d.call(l,y)}}o.exports=c},879:function(o,n){n.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},n.nodeList=function(i){var s=Object.prototype.toString.call(i);return i!==void 0&&(s==="[object NodeList]"||s==="[object HTMLCollection]")&&"length"in i&&(i.length===0||n.node(i[0]))},n.string=function(i){return typeof i=="string"||i instanceof String},n.fn=function(i){var s=Object.prototype.toString.call(i);return s==="[object Function]"}},370:function(o,n,i){var s=i(879),a=i(438);function c(u,d,y){if(!u&&!d&&!y)throw new Error("Missing required arguments");if(!s.string(d))throw new TypeError("Second argument must be a String");if(!s.fn(y))throw new TypeError("Third argument must be a Function");if(s.node(u))return p(u,d,y);if(s.nodeList(u))return l(u,d,y);if(s.string(u))return f(u,d,y);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function p(u,d,y){return u.addEventListener(d,y),{destroy:function(){u.removeEventListener(d,y)}}}function l(u,d,y){return Array.prototype.forEach.call(u,function(b){b.addEventListener(d,y)}),{destroy:function(){Array.prototype.forEach.call(u,function(b){b.removeEventListener(d,y)})}}}function f(u,d,y){return a(document.body,u,d,y)}o.exports=c},817:function(o){function n(i){var s;if(i.nodeName==="SELECT")i.focus(),s=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var a=i.hasAttribute("readonly");a||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),a||i.removeAttribute("readonly"),s=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var c=window.getSelection(),p=document.createRange();p.selectNodeContents(i),c.removeAllRanges(),c.addRange(p),s=c.toString()}return s}o.exports=n},279:function(o){function n(){}n.prototype={on:function(i,s,a){var c=this.e||(this.e={});return(c[i]||(c[i]=[])).push({fn:s,ctx:a}),this},once:function(i,s,a){var c=this;function p(){c.off(i,p),s.apply(a,arguments)}return p._=s,this.on(i,p,a)},emit:function(i){var s=[].slice.call(arguments,1),a=((this.e||(this.e={}))[i]||[]).slice(),c=0,p=a.length;for(c;c{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var Wa=/["'&<>]/;Vn.exports=Ua;function Ua(e){var t=""+e,r=Wa.exec(t);if(!r)return t;var o,n="",i=0,s=0;for(i=r.index;i0&&i[i.length-1])&&(p[0]===6||p[0]===2)){r=0;continue}if(p[0]===3&&(!i||p[1]>i[0]&&p[1]=e.length&&(e=void 0),{value:e&&e[o++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function z(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var o=r.call(e),n,i=[],s;try{for(;(t===void 0||t-- >0)&&!(n=o.next()).done;)i.push(n.value)}catch(a){s={error:a}}finally{try{n&&!n.done&&(r=o.return)&&r.call(o)}finally{if(s)throw s.error}}return i}function K(e,t,r){if(r||arguments.length===2)for(var o=0,n=t.length,i;o1||a(u,d)})})}function a(u,d){try{c(o[u](d))}catch(y){f(i[0][3],y)}}function c(u){u.value instanceof ot?Promise.resolve(u.value.v).then(p,l):f(i[0][2],u)}function p(u){a("next",u)}function l(u){a("throw",u)}function f(u,d){u(d),i.shift(),i.length&&a(i[0][0],i[0][1])}}function po(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof be=="function"?be(e):e[Symbol.iterator](),r={},o("next"),o("throw"),o("return"),r[Symbol.asyncIterator]=function(){return this},r);function o(i){r[i]=e[i]&&function(s){return new Promise(function(a,c){s=e[i](s),n(a,c,s.done,s.value)})}}function n(i,s,a,c){Promise.resolve(c).then(function(p){i({value:p,done:a})},s)}}function k(e){return typeof e=="function"}function pt(e){var t=function(o){Error.call(o),o.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var Ut=pt(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(o,n){return n+1+") "+o.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function ze(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var je=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,o,n,i;if(!this.closed){this.closed=!0;var s=this._parentage;if(s)if(this._parentage=null,Array.isArray(s))try{for(var a=be(s),c=a.next();!c.done;c=a.next()){var p=c.value;p.remove(this)}}catch(b){t={error:b}}finally{try{c&&!c.done&&(r=a.return)&&r.call(a)}finally{if(t)throw t.error}}else s.remove(this);var l=this.initialTeardown;if(k(l))try{l()}catch(b){i=b instanceof Ut?b.errors:[b]}var f=this._finalizers;if(f){this._finalizers=null;try{for(var u=be(f),d=u.next();!d.done;d=u.next()){var y=d.value;try{lo(y)}catch(b){i=i!=null?i:[],b instanceof Ut?i=K(K([],z(i)),z(b.errors)):i.push(b)}}}catch(b){o={error:b}}finally{try{d&&!d.done&&(n=u.return)&&n.call(u)}finally{if(o)throw o.error}}}if(i)throw new Ut(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)lo(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&ze(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&ze(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Tr=je.EMPTY;function Nt(e){return e instanceof je||e&&"closed"in e&&k(e.remove)&&k(e.add)&&k(e.unsubscribe)}function lo(e){k(e)?e():e.unsubscribe()}var He={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var lt={setTimeout:function(e,t){for(var r=[],o=2;o0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var o=this,n=this,i=n.hasError,s=n.isStopped,a=n.observers;return i||s?Tr:(this.currentObservers=null,a.push(r),new je(function(){o.currentObservers=null,ze(a,r)}))},t.prototype._checkFinalizedStatuses=function(r){var o=this,n=o.hasError,i=o.thrownError,s=o.isStopped;n?r.error(i):s&&r.complete()},t.prototype.asObservable=function(){var r=new I;return r.source=this,r},t.create=function(r,o){return new xo(r,o)},t}(I);var xo=function(e){se(t,e);function t(r,o){var n=e.call(this)||this;return n.destination=r,n.source=o,n}return t.prototype.next=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.next)===null||n===void 0||n.call(o,r)},t.prototype.error=function(r){var o,n;(n=(o=this.destination)===null||o===void 0?void 0:o.error)===null||n===void 0||n.call(o,r)},t.prototype.complete=function(){var r,o;(o=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||o===void 0||o.call(r)},t.prototype._subscribe=function(r){var o,n;return(n=(o=this.source)===null||o===void 0?void 0:o.subscribe(r))!==null&&n!==void 0?n:Tr},t}(x);var St={now:function(){return(St.delegate||Date).now()},delegate:void 0};var Ot=function(e){se(t,e);function t(r,o,n){r===void 0&&(r=1/0),o===void 0&&(o=1/0),n===void 0&&(n=St);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=o,i._timestampProvider=n,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=o===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,o),i}return t.prototype.next=function(r){var o=this,n=o.isStopped,i=o._buffer,s=o._infiniteTimeWindow,a=o._timestampProvider,c=o._windowTime;n||(i.push(r),!s&&i.push(a.now()+c)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var o=this._innerSubscribe(r),n=this,i=n._infiniteTimeWindow,s=n._buffer,a=s.slice(),c=0;c0?e.prototype.requestAsyncId.call(this,r,o,n):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,o,n){var i;if(n===void 0&&(n=0),n!=null?n>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,o,n);var s=r.actions;o!=null&&((i=s[s.length-1])===null||i===void 0?void 0:i.id)!==o&&(ut.cancelAnimationFrame(o),r._scheduled=void 0)},t}(zt);var wo=function(e){se(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var o=this._scheduled;this._scheduled=void 0;var n=this.actions,i;r=r||n.shift();do if(i=r.execute(r.state,r.delay))break;while((r=n[0])&&r.id===o&&n.shift());if(this._active=!1,i){for(;(r=n[0])&&r.id===o&&n.shift();)r.unsubscribe();throw i}},t}(qt);var ge=new wo(Eo);var M=new I(function(e){return e.complete()});function Kt(e){return e&&k(e.schedule)}function Cr(e){return e[e.length-1]}function Ge(e){return k(Cr(e))?e.pop():void 0}function Ae(e){return Kt(Cr(e))?e.pop():void 0}function Qt(e,t){return typeof Cr(e)=="number"?e.pop():t}var dt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function Yt(e){return k(e==null?void 0:e.then)}function Bt(e){return k(e[ft])}function Gt(e){return Symbol.asyncIterator&&k(e==null?void 0:e[Symbol.asyncIterator])}function Jt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Wi(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Xt=Wi();function Zt(e){return k(e==null?void 0:e[Xt])}function er(e){return co(this,arguments,function(){var r,o,n,i;return Wt(this,function(s){switch(s.label){case 0:r=e.getReader(),s.label=1;case 1:s.trys.push([1,,9,10]),s.label=2;case 2:return[4,ot(r.read())];case 3:return o=s.sent(),n=o.value,i=o.done,i?[4,ot(void 0)]:[3,5];case 4:return[2,s.sent()];case 5:return[4,ot(n)];case 6:return[4,s.sent()];case 7:return s.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function tr(e){return k(e==null?void 0:e.getReader)}function F(e){if(e instanceof I)return e;if(e!=null){if(Bt(e))return Ui(e);if(dt(e))return Ni(e);if(Yt(e))return Di(e);if(Gt(e))return To(e);if(Zt(e))return Vi(e);if(tr(e))return zi(e)}throw Jt(e)}function Ui(e){return new I(function(t){var r=e[ft]();if(k(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Ni(e){return new I(function(t){for(var r=0;r=2;return function(o){return o.pipe(e?v(function(n,i){return e(n,i,o)}):pe,ue(1),r?$e(t):Uo(function(){return new or}))}}function Rr(e){return e<=0?function(){return M}:g(function(t,r){var o=[];t.subscribe(E(r,function(n){o.push(n),e=2,!0))}function de(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new x}:t,o=e.resetOnError,n=o===void 0?!0:o,i=e.resetOnComplete,s=i===void 0?!0:i,a=e.resetOnRefCountZero,c=a===void 0?!0:a;return function(p){var l,f,u,d=0,y=!1,b=!1,D=function(){f==null||f.unsubscribe(),f=void 0},Q=function(){D(),l=u=void 0,y=b=!1},J=function(){var C=l;Q(),C==null||C.unsubscribe()};return g(function(C,ct){d++,!b&&!y&&D();var Ve=u=u!=null?u:r();ct.add(function(){d--,d===0&&!b&&!y&&(f=jr(J,c))}),Ve.subscribe(ct),!l&&d>0&&(l=new it({next:function(Fe){return Ve.next(Fe)},error:function(Fe){b=!0,D(),f=jr(Q,n,Fe),Ve.error(Fe)},complete:function(){y=!0,D(),f=jr(Q,s),Ve.complete()}}),F(C).subscribe(l))})(p)}}function jr(e,t){for(var r=[],o=2;oe.next(document)),e}function W(e,t=document){return Array.from(t.querySelectorAll(e))}function U(e,t=document){let r=ce(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function ce(e,t=document){return t.querySelector(e)||void 0}function Ie(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}var ca=L(h(document.body,"focusin"),h(document.body,"focusout")).pipe(ye(1),q(void 0),m(()=>Ie()||document.body),Z(1));function vt(e){return ca.pipe(m(t=>e.contains(t)),X())}function qo(e,t){return L(h(e,"mouseenter").pipe(m(()=>!0)),h(e,"mouseleave").pipe(m(()=>!1))).pipe(t?ye(t):pe,q(!1))}function Ue(e){return{x:e.offsetLeft,y:e.offsetTop}}function Ko(e){return L(h(window,"load"),h(window,"resize")).pipe(Le(0,ge),m(()=>Ue(e)),q(Ue(e)))}function ir(e){return{x:e.scrollLeft,y:e.scrollTop}}function et(e){return L(h(e,"scroll"),h(window,"resize")).pipe(Le(0,ge),m(()=>ir(e)),q(ir(e)))}function Qo(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)Qo(e,r)}function S(e,t,...r){let o=document.createElement(e);if(t)for(let n of Object.keys(t))typeof t[n]!="undefined"&&(typeof t[n]!="boolean"?o.setAttribute(n,t[n]):o.setAttribute(n,""));for(let n of r)Qo(o,n);return o}function ar(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function gt(e){let t=S("script",{src:e});return H(()=>(document.head.appendChild(t),L(h(t,"load"),h(t,"error").pipe(w(()=>kr(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(m(()=>{}),A(()=>document.head.removeChild(t)),ue(1))))}var Yo=new x,pa=H(()=>typeof ResizeObserver=="undefined"?gt("https://unpkg.com/resize-observer-polyfill"):R(void 0)).pipe(m(()=>new ResizeObserver(e=>{for(let t of e)Yo.next(t)})),w(e=>L(Ke,R(e)).pipe(A(()=>e.disconnect()))),Z(1));function le(e){return{width:e.offsetWidth,height:e.offsetHeight}}function Se(e){return pa.pipe(T(t=>t.observe(e)),w(t=>Yo.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(()=>le(e)))),q(le(e)))}function xt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function sr(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var Bo=new x,la=H(()=>R(new IntersectionObserver(e=>{for(let t of e)Bo.next(t)},{threshold:0}))).pipe(w(e=>L(Ke,R(e)).pipe(A(()=>e.disconnect()))),Z(1));function yt(e){return la.pipe(T(t=>t.observe(e)),w(t=>Bo.pipe(v(({target:r})=>r===e),A(()=>t.unobserve(e)),m(({isIntersecting:r})=>r))))}function Go(e,t=16){return et(e).pipe(m(({y:r})=>{let o=le(e),n=xt(e);return r>=n.height-o.height-t}),X())}var cr={drawer:U("[data-md-toggle=drawer]"),search:U("[data-md-toggle=search]")};function Jo(e){return cr[e].checked}function Ye(e,t){cr[e].checked!==t&&cr[e].click()}function Ne(e){let t=cr[e];return h(t,"change").pipe(m(()=>t.checked),q(t.checked))}function ma(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function fa(){return L(h(window,"compositionstart").pipe(m(()=>!0)),h(window,"compositionend").pipe(m(()=>!1))).pipe(q(!1))}function Xo(){let e=h(window,"keydown").pipe(v(t=>!(t.metaKey||t.ctrlKey)),m(t=>({mode:Jo("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),v(({mode:t,type:r})=>{if(t==="global"){let o=Ie();if(typeof o!="undefined")return!ma(o,r)}return!0}),de());return fa().pipe(w(t=>t?M:e))}function me(){return new URL(location.href)}function st(e,t=!1){if(G("navigation.instant")&&!t){let r=S("a",{href:e.href});document.body.appendChild(r),r.click(),r.remove()}else location.href=e.href}function Zo(){return new x}function en(){return location.hash.slice(1)}function pr(e){let t=S("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function ua(e){return L(h(window,"hashchange"),e).pipe(m(en),q(en()),v(t=>t.length>0),Z(1))}function tn(e){return ua(e).pipe(m(t=>ce(`[id="${t}"]`)),v(t=>typeof t!="undefined"))}function At(e){let t=matchMedia(e);return nr(r=>t.addListener(()=>r(t.matches))).pipe(q(t.matches))}function rn(){let e=matchMedia("print");return L(h(window,"beforeprint").pipe(m(()=>!0)),h(window,"afterprint").pipe(m(()=>!1))).pipe(q(e.matches))}function Dr(e,t){return e.pipe(w(r=>r?t():M))}function lr(e,t){return new I(r=>{let o=new XMLHttpRequest;o.open("GET",`${e}`),o.responseType="blob",o.addEventListener("load",()=>{o.status>=200&&o.status<300?(r.next(o.response),r.complete()):r.error(new Error(o.statusText))}),o.addEventListener("error",()=>{r.error(new Error("Network Error"))}),o.addEventListener("abort",()=>{r.error(new Error("Request aborted"))}),typeof(t==null?void 0:t.progress$)!="undefined"&&(o.addEventListener("progress",n=>{if(n.lengthComputable)t.progress$.next(n.loaded/n.total*100);else{let i=Number(o.getResponseHeader("Content-Length"))||0;t.progress$.next(n.loaded/i*100)}}),t.progress$.next(5)),o.send()})}function De(e,t){return lr(e,t).pipe(w(r=>r.text()),m(r=>JSON.parse(r)),Z(1))}function on(e,t){let r=new DOMParser;return lr(e,t).pipe(w(o=>o.text()),m(o=>r.parseFromString(o,"text/xml")),Z(1))}function nn(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function an(){return L(h(window,"scroll",{passive:!0}),h(window,"resize",{passive:!0})).pipe(m(nn),q(nn()))}function sn(){return{width:innerWidth,height:innerHeight}}function cn(){return h(window,"resize",{passive:!0}).pipe(m(sn),q(sn()))}function pn(){return B([an(),cn()]).pipe(m(([e,t])=>({offset:e,size:t})),Z(1))}function mr(e,{viewport$:t,header$:r}){let o=t.pipe(te("size")),n=B([o,r]).pipe(m(()=>Ue(e)));return B([r,t,n]).pipe(m(([{height:i},{offset:s,size:a},{x:c,y:p}])=>({offset:{x:s.x-c,y:s.y-p+i},size:a})))}function da(e){return h(e,"message",t=>t.data)}function ha(e){let t=new x;return t.subscribe(r=>e.postMessage(r)),t}function ln(e,t=new Worker(e)){let r=da(t),o=ha(t),n=new x;n.subscribe(o);let i=o.pipe(ee(),oe(!0));return n.pipe(ee(),Re(r.pipe(j(i))),de())}var ba=U("#__config"),Et=JSON.parse(ba.textContent);Et.base=`${new URL(Et.base,me())}`;function he(){return Et}function G(e){return Et.features.includes(e)}function we(e,t){return typeof t!="undefined"?Et.translations[e].replace("#",t.toString()):Et.translations[e]}function Oe(e,t=document){return U(`[data-md-component=${e}]`,t)}function ne(e,t=document){return W(`[data-md-component=${e}]`,t)}function va(e){let t=U(".md-typeset > :first-child",e);return h(t,"click",{once:!0}).pipe(m(()=>U(".md-typeset",e)),m(r=>({hash:__md_hash(r.innerHTML)})))}function mn(e){if(!G("announce.dismiss")||!e.childElementCount)return M;if(!e.hidden){let t=U(".md-typeset",e);__md_hash(t.innerHTML)===__md_get("__announce")&&(e.hidden=!0)}return H(()=>{let t=new x;return t.subscribe(({hash:r})=>{e.hidden=!0,__md_set("__announce",r)}),va(e).pipe(T(r=>t.next(r)),A(()=>t.complete()),m(r=>P({ref:e},r)))})}function ga(e,{target$:t}){return t.pipe(m(r=>({hidden:r!==e})))}function fn(e,t){let r=new x;return r.subscribe(({hidden:o})=>{e.hidden=o}),ga(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))}function Ct(e,t){return t==="inline"?S("div",{class:"md-tooltip md-tooltip--inline",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"})):S("div",{class:"md-tooltip",id:e,role:"tooltip"},S("div",{class:"md-tooltip__inner md-typeset"}))}function un(e,t){if(t=t?`${t}_annotation_${e}`:void 0,t){let r=t?`#${t}`:void 0;return S("aside",{class:"md-annotation",tabIndex:0},Ct(t),S("a",{href:r,class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}else return S("aside",{class:"md-annotation",tabIndex:0},Ct(t),S("span",{class:"md-annotation__index",tabIndex:-1},S("span",{"data-md-annotation-id":e})))}function dn(e){return S("button",{class:"md-clipboard md-icon",title:we("clipboard.copy"),"data-clipboard-target":`#${e} > code`})}function Vr(e,t){let r=t&2,o=t&1,n=Object.keys(e.terms).filter(c=>!e.terms[c]).reduce((c,p)=>[...c,S("del",null,p)," "],[]).slice(0,-1),i=he(),s=new URL(e.location,i.base);G("search.highlight")&&s.searchParams.set("h",Object.entries(e.terms).filter(([,c])=>c).reduce((c,[p])=>`${c} ${p}`.trim(),""));let{tags:a}=he();return S("a",{href:`${s}`,class:"md-search-result__link",tabIndex:-1},S("article",{class:"md-search-result__article md-typeset","data-md-score":e.score.toFixed(2)},r>0&&S("div",{class:"md-search-result__icon md-icon"}),r>0&&S("h1",null,e.title),r<=0&&S("h2",null,e.title),o>0&&e.text.length>0&&e.text,e.tags&&e.tags.map(c=>{let p=a?c in a?`md-tag-icon md-tag--${a[c]}`:"md-tag-icon":"";return S("span",{class:`md-tag ${p}`},c)}),o>0&&n.length>0&&S("p",{class:"md-search-result__terms"},we("search.result.term.missing"),": ",...n)))}function hn(e){let t=e[0].score,r=[...e],o=he(),n=r.findIndex(l=>!`${new URL(l.location,o.base)}`.includes("#")),[i]=r.splice(n,1),s=r.findIndex(l=>l.scoreVr(l,1)),...c.length?[S("details",{class:"md-search-result__more"},S("summary",{tabIndex:-1},S("div",null,c.length>0&&c.length===1?we("search.result.more.one"):we("search.result.more.other",c.length))),...c.map(l=>Vr(l,1)))]:[]];return S("li",{class:"md-search-result__item"},p)}function bn(e){return S("ul",{class:"md-source__facts"},Object.entries(e).map(([t,r])=>S("li",{class:`md-source__fact md-source__fact--${t}`},typeof r=="number"?ar(r):r)))}function zr(e){let t=`tabbed-control tabbed-control--${e}`;return S("div",{class:t,hidden:!0},S("button",{class:"tabbed-button",tabIndex:-1,"aria-hidden":"true"}))}function vn(e){return S("div",{class:"md-typeset__scrollwrap"},S("div",{class:"md-typeset__table"},e))}function xa(e){let t=he(),r=new URL(`../${e.version}/`,t.base);return S("li",{class:"md-version__item"},S("a",{href:`${r}`,class:"md-version__link"},e.title))}function gn(e,t){return S("div",{class:"md-version"},S("button",{class:"md-version__current","aria-label":we("select.version")},t.title),S("ul",{class:"md-version__list"},e.map(xa)))}var ya=0;function Ea(e,t){document.body.append(e);let{width:r}=le(e);e.style.setProperty("--md-tooltip-width",`${r}px`),e.remove();let o=sr(t),n=typeof o!="undefined"?et(o):R({x:0,y:0}),i=L(vt(t),qo(t)).pipe(X());return B([i,n]).pipe(m(([s,a])=>{let{x:c,y:p}=Ue(t),l=le(t),f=t.closest("table");return f&&t.parentElement&&(c+=f.offsetLeft+t.parentElement.offsetLeft,p+=f.offsetTop+t.parentElement.offsetTop),{active:s,offset:{x:c-a.x+l.width/2-r/2,y:p-a.y+l.height+8}}}))}function Be(e){let t=e.title;if(!t.length)return M;let r=`__tooltip_${ya++}`,o=Ct(r,"inline"),n=U(".md-typeset",o);return n.innerHTML=t,H(()=>{let i=new x;return i.subscribe({next({offset:s}){o.style.setProperty("--md-tooltip-x",`${s.x}px`),o.style.setProperty("--md-tooltip-y",`${s.y}px`)},complete(){o.style.removeProperty("--md-tooltip-x"),o.style.removeProperty("--md-tooltip-y")}}),L(i.pipe(v(({active:s})=>s)),i.pipe(ye(250),v(({active:s})=>!s))).subscribe({next({active:s}){s?(e.insertAdjacentElement("afterend",o),e.setAttribute("aria-describedby",r),e.removeAttribute("title")):(o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t))},complete(){o.remove(),e.removeAttribute("aria-describedby"),e.setAttribute("title",t)}}),i.pipe(Le(16,ge)).subscribe(({active:s})=>{o.classList.toggle("md-tooltip--active",s)}),i.pipe(_t(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:s})=>s)).subscribe({next(s){s?o.style.setProperty("--md-tooltip-0",`${-s}px`):o.style.removeProperty("--md-tooltip-0")},complete(){o.style.removeProperty("--md-tooltip-0")}}),Ea(o,e).pipe(T(s=>i.next(s)),A(()=>i.complete()),m(s=>P({ref:e},s)))}).pipe(qe(ie))}function wa(e,t){let r=H(()=>B([Ko(e),et(t)])).pipe(m(([{x:o,y:n},i])=>{let{width:s,height:a}=le(e);return{x:o-i.x+s/2,y:n-i.y+a/2}}));return vt(e).pipe(w(o=>r.pipe(m(n=>({active:o,offset:n})),ue(+!o||1/0))))}function xn(e,t,{target$:r}){let[o,n]=Array.from(e.children);return H(()=>{let i=new x,s=i.pipe(ee(),oe(!0));return i.subscribe({next({offset:a}){e.style.setProperty("--md-tooltip-x",`${a.x}px`),e.style.setProperty("--md-tooltip-y",`${a.y}px`)},complete(){e.style.removeProperty("--md-tooltip-x"),e.style.removeProperty("--md-tooltip-y")}}),yt(e).pipe(j(s)).subscribe(a=>{e.toggleAttribute("data-md-visible",a)}),L(i.pipe(v(({active:a})=>a)),i.pipe(ye(250),v(({active:a})=>!a))).subscribe({next({active:a}){a?e.prepend(o):o.remove()},complete(){e.prepend(o)}}),i.pipe(Le(16,ge)).subscribe(({active:a})=>{o.classList.toggle("md-tooltip--active",a)}),i.pipe(_t(125,ge),v(()=>!!e.offsetParent),m(()=>e.offsetParent.getBoundingClientRect()),m(({x:a})=>a)).subscribe({next(a){a?e.style.setProperty("--md-tooltip-0",`${-a}px`):e.style.removeProperty("--md-tooltip-0")},complete(){e.style.removeProperty("--md-tooltip-0")}}),h(n,"click").pipe(j(s),v(a=>!(a.metaKey||a.ctrlKey))).subscribe(a=>{a.stopPropagation(),a.preventDefault()}),h(n,"mousedown").pipe(j(s),ae(i)).subscribe(([a,{active:c}])=>{var p;if(a.button!==0||a.metaKey||a.ctrlKey)a.preventDefault();else if(c){a.preventDefault();let l=e.parentElement.closest(".md-annotation");l instanceof HTMLElement?l.focus():(p=Ie())==null||p.blur()}}),r.pipe(j(s),v(a=>a===o),Qe(125)).subscribe(()=>e.focus()),wa(e,t).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))})}function Ta(e){return e.tagName==="CODE"?W(".c, .c1, .cm",e):[e]}function Sa(e){let t=[];for(let r of Ta(e)){let o=[],n=document.createNodeIterator(r,NodeFilter.SHOW_TEXT);for(let i=n.nextNode();i;i=n.nextNode())o.push(i);for(let i of o){let s;for(;s=/(\(\d+\))(!)?/.exec(i.textContent);){let[,a,c]=s;if(typeof c=="undefined"){let p=i.splitText(s.index);i=p.splitText(a.length),t.push(p)}else{i.textContent=a,t.push(i);break}}}}return t}function yn(e,t){t.append(...Array.from(e.childNodes))}function fr(e,t,{target$:r,print$:o}){let n=t.closest("[id]"),i=n==null?void 0:n.id,s=new Map;for(let a of Sa(t)){let[,c]=a.textContent.match(/\((\d+)\)/);ce(`:scope > li:nth-child(${c})`,e)&&(s.set(c,un(c,i)),a.replaceWith(s.get(c)))}return s.size===0?M:H(()=>{let a=new x,c=a.pipe(ee(),oe(!0)),p=[];for(let[l,f]of s)p.push([U(".md-typeset",f),U(`:scope > li:nth-child(${l})`,e)]);return o.pipe(j(c)).subscribe(l=>{e.hidden=!l,e.classList.toggle("md-annotation-list",l);for(let[f,u]of p)l?yn(f,u):yn(u,f)}),L(...[...s].map(([,l])=>xn(l,t,{target$:r}))).pipe(A(()=>a.complete()),de())})}function En(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return En(t)}}function wn(e,t){return H(()=>{let r=En(e);return typeof r!="undefined"?fr(r,e,t):M})}var Tn=jt(Kr());var Oa=0;function Sn(e){if(e.nextElementSibling){let t=e.nextElementSibling;if(t.tagName==="OL")return t;if(t.tagName==="P"&&!t.children.length)return Sn(t)}}function Ma(e){return Se(e).pipe(m(({width:t})=>({scrollable:xt(e).width>t})),te("scrollable"))}function On(e,t){let{matches:r}=matchMedia("(hover)"),o=H(()=>{let n=new x,i=n.pipe(Rr(1));n.subscribe(({scrollable:c})=>{c&&r?e.setAttribute("tabindex","0"):e.removeAttribute("tabindex")});let s=[];if(Tn.default.isSupported()&&(e.closest(".copy")||G("content.code.copy")&&!e.closest(".no-copy"))){let c=e.closest("pre");c.id=`__code_${Oa++}`;let p=dn(c.id);c.insertBefore(p,e),G("content.tooltips")&&s.push(Be(p))}let a=e.closest(".highlight");if(a instanceof HTMLElement){let c=Sn(a);if(typeof c!="undefined"&&(a.classList.contains("annotate")||G("content.code.annotate"))){let p=fr(c,e,t);s.push(Se(a).pipe(j(i),m(({width:l,height:f})=>l&&f),X(),w(l=>l?p:M)))}}return Ma(e).pipe(T(c=>n.next(c)),A(()=>n.complete()),m(c=>P({ref:e},c)),Re(...s))});return G("content.lazy")?yt(e).pipe(v(n=>n),ue(1),w(()=>o)):o}function La(e,{target$:t,print$:r}){let o=!0;return L(t.pipe(m(n=>n.closest("details:not([open])")),v(n=>e===n),m(()=>({action:"open",reveal:!0}))),r.pipe(v(n=>n||!o),T(()=>o=e.open),m(n=>({action:n?"open":"close"}))))}function Mn(e,t){return H(()=>{let r=new x;return r.subscribe(({action:o,reveal:n})=>{e.toggleAttribute("open",o==="open"),n&&e.scrollIntoView()}),La(e,t).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}var Ln=".node circle,.node ellipse,.node path,.node polygon,.node rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}marker{fill:var(--md-mermaid-edge-color)!important}.edgeLabel .label rect{fill:#0000}.label{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.label foreignObject{line-height:normal;overflow:visible}.label div .edgeLabel{color:var(--md-mermaid-label-fg-color)}.edgeLabel,.edgeLabel rect,.label div .edgeLabel{background-color:var(--md-mermaid-label-bg-color)}.edgeLabel,.edgeLabel rect{fill:var(--md-mermaid-label-bg-color);color:var(--md-mermaid-edge-color)}.edgePath .path,.flowchart-link{stroke:var(--md-mermaid-edge-color);stroke-width:.05rem}.edgePath .arrowheadPath{fill:var(--md-mermaid-edge-color);stroke:none}.cluster rect{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}.cluster span{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}g #flowchart-circleEnd,g #flowchart-circleStart,g #flowchart-crossEnd,g #flowchart-crossStart,g #flowchart-pointEnd,g #flowchart-pointStart{stroke:none}g.classGroup line,g.classGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.classGroup text{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.classLabel .box{fill:var(--md-mermaid-label-bg-color);background-color:var(--md-mermaid-label-bg-color);opacity:1}.classLabel .label{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node .divider{stroke:var(--md-mermaid-node-fg-color)}.relation{stroke:var(--md-mermaid-edge-color)}.cardinality{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.cardinality text{fill:inherit!important}defs #classDiagram-compositionEnd,defs #classDiagram-compositionStart,defs #classDiagram-dependencyEnd,defs #classDiagram-dependencyStart,defs #classDiagram-extensionEnd,defs #classDiagram-extensionStart{fill:var(--md-mermaid-edge-color)!important;stroke:var(--md-mermaid-edge-color)!important}defs #classDiagram-aggregationEnd,defs #classDiagram-aggregationStart{fill:var(--md-mermaid-label-bg-color)!important;stroke:var(--md-mermaid-edge-color)!important}g.stateGroup rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}g.stateGroup .state-title{fill:var(--md-mermaid-label-fg-color)!important;font-family:var(--md-mermaid-font-family)}g.stateGroup .composit{fill:var(--md-mermaid-label-bg-color)}.nodeLabel{color:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.node circle.state-end,.node circle.state-start,.start-state{fill:var(--md-mermaid-edge-color);stroke:none}.end-state-inner,.end-state-outer{fill:var(--md-mermaid-edge-color)}.end-state-inner,.node circle.state-end{stroke:var(--md-mermaid-label-bg-color)}.transition{stroke:var(--md-mermaid-edge-color)}[id^=state-fork] rect,[id^=state-join] rect{fill:var(--md-mermaid-edge-color)!important;stroke:none!important}.statediagram-cluster.statediagram-cluster .inner{fill:var(--md-default-bg-color)}.statediagram-cluster rect{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.statediagram-state rect.divider{fill:var(--md-default-fg-color--lightest);stroke:var(--md-default-fg-color--lighter)}defs #statediagram-barbEnd{stroke:var(--md-mermaid-edge-color)}.attributeBoxEven,.attributeBoxOdd{fill:var(--md-mermaid-node-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityBox{fill:var(--md-mermaid-label-bg-color);stroke:var(--md-mermaid-node-fg-color)}.entityLabel{fill:var(--md-mermaid-label-fg-color);font-family:var(--md-mermaid-font-family)}.relationshipLabelBox{fill:var(--md-mermaid-label-bg-color);fill-opacity:1;background-color:var(--md-mermaid-label-bg-color);opacity:1}.relationshipLabel{fill:var(--md-mermaid-label-fg-color)}.relationshipLine{stroke:var(--md-mermaid-edge-color)}defs #ONE_OR_MORE_END *,defs #ONE_OR_MORE_START *,defs #ONLY_ONE_END *,defs #ONLY_ONE_START *,defs #ZERO_OR_MORE_END *,defs #ZERO_OR_MORE_START *,defs #ZERO_OR_ONE_END *,defs #ZERO_OR_ONE_START *{stroke:var(--md-mermaid-edge-color)!important}defs #ZERO_OR_MORE_END circle,defs #ZERO_OR_MORE_START circle{fill:var(--md-mermaid-label-bg-color)}.actor{fill:var(--md-mermaid-sequence-actor-bg-color);stroke:var(--md-mermaid-sequence-actor-border-color)}text.actor>tspan{fill:var(--md-mermaid-sequence-actor-fg-color);font-family:var(--md-mermaid-font-family)}line{stroke:var(--md-mermaid-sequence-actor-line-color)}.actor-man circle,.actor-man line{fill:var(--md-mermaid-sequence-actorman-bg-color);stroke:var(--md-mermaid-sequence-actorman-line-color)}.messageLine0,.messageLine1{stroke:var(--md-mermaid-sequence-message-line-color)}.note{fill:var(--md-mermaid-sequence-note-bg-color);stroke:var(--md-mermaid-sequence-note-border-color)}.loopText,.loopText>tspan,.messageText,.noteText>tspan{stroke:none;font-family:var(--md-mermaid-font-family)!important}.messageText{fill:var(--md-mermaid-sequence-message-fg-color)}.loopText,.loopText>tspan{fill:var(--md-mermaid-sequence-loop-fg-color)}.noteText>tspan{fill:var(--md-mermaid-sequence-note-fg-color)}#arrowhead path{fill:var(--md-mermaid-sequence-message-line-color);stroke:none}.loopLine{fill:var(--md-mermaid-sequence-loop-bg-color);stroke:var(--md-mermaid-sequence-loop-border-color)}.labelBox{fill:var(--md-mermaid-sequence-label-bg-color);stroke:none}.labelText,.labelText>span{fill:var(--md-mermaid-sequence-label-fg-color);font-family:var(--md-mermaid-font-family)}.sequenceNumber{fill:var(--md-mermaid-sequence-number-fg-color)}rect.rect{fill:var(--md-mermaid-sequence-box-bg-color);stroke:none}rect.rect+text.text{fill:var(--md-mermaid-sequence-box-fg-color)}defs #sequencenumber{fill:var(--md-mermaid-sequence-number-bg-color)!important}";var Qr,Aa=0;function Ca(){return typeof mermaid=="undefined"||mermaid instanceof Element?gt("https://unpkg.com/mermaid@10.6.1/dist/mermaid.min.js"):R(void 0)}function _n(e){return e.classList.remove("mermaid"),Qr||(Qr=Ca().pipe(T(()=>mermaid.initialize({startOnLoad:!1,themeCSS:Ln,sequence:{actorFontSize:"16px",messageFontSize:"16px",noteFontSize:"16px"}})),m(()=>{}),Z(1))),Qr.subscribe(()=>no(this,null,function*(){e.classList.add("mermaid");let t=`__mermaid_${Aa++}`,r=S("div",{class:"mermaid"}),o=e.textContent,{svg:n,fn:i}=yield mermaid.render(t,o),s=r.attachShadow({mode:"closed"});s.innerHTML=n,e.replaceWith(r),i==null||i(s)})),Qr.pipe(m(()=>({ref:e})))}var An=S("table");function Cn(e){return e.replaceWith(An),An.replaceWith(vn(e)),R({ref:e})}function ka(e){let t=e.find(r=>r.checked)||e[0];return L(...e.map(r=>h(r,"change").pipe(m(()=>U(`label[for="${r.id}"]`))))).pipe(q(U(`label[for="${t.id}"]`)),m(r=>({active:r})))}function kn(e,{viewport$:t,target$:r}){let o=U(".tabbed-labels",e),n=W(":scope > input",e),i=zr("prev");e.append(i);let s=zr("next");return e.append(s),H(()=>{let a=new x,c=a.pipe(ee(),oe(!0));B([a,Se(e)]).pipe(j(c),Le(1,ge)).subscribe({next([{active:p},l]){let f=Ue(p),{width:u}=le(p);e.style.setProperty("--md-indicator-x",`${f.x}px`),e.style.setProperty("--md-indicator-width",`${u}px`);let d=ir(o);(f.xd.x+l.width)&&o.scrollTo({left:Math.max(0,f.x-16),behavior:"smooth"})},complete(){e.style.removeProperty("--md-indicator-x"),e.style.removeProperty("--md-indicator-width")}}),B([et(o),Se(o)]).pipe(j(c)).subscribe(([p,l])=>{let f=xt(o);i.hidden=p.x<16,s.hidden=p.x>f.width-l.width-16}),L(h(i,"click").pipe(m(()=>-1)),h(s,"click").pipe(m(()=>1))).pipe(j(c)).subscribe(p=>{let{width:l}=le(o);o.scrollBy({left:l*p,behavior:"smooth"})}),r.pipe(j(c),v(p=>n.includes(p))).subscribe(p=>p.click()),o.classList.add("tabbed-labels--linked");for(let p of n){let l=U(`label[for="${p.id}"]`);l.replaceChildren(S("a",{href:`#${l.htmlFor}`,tabIndex:-1},...Array.from(l.childNodes))),h(l.firstElementChild,"click").pipe(j(c),v(f=>!(f.metaKey||f.ctrlKey)),T(f=>{f.preventDefault(),f.stopPropagation()})).subscribe(()=>{history.replaceState({},"",`#${l.htmlFor}`),l.click()})}return G("content.tabs.link")&&a.pipe(Ee(1),ae(t)).subscribe(([{active:p},{offset:l}])=>{let f=p.innerText.trim();if(p.hasAttribute("data-md-switching"))p.removeAttribute("data-md-switching");else{let u=e.offsetTop-l.y;for(let y of W("[data-tabs]"))for(let b of W(":scope > input",y)){let D=U(`label[for="${b.id}"]`);if(D!==p&&D.innerText.trim()===f){D.setAttribute("data-md-switching",""),b.click();break}}window.scrollTo({top:e.offsetTop-u});let d=__md_get("__tabs")||[];__md_set("__tabs",[...new Set([f,...d])])}}),a.pipe(j(c)).subscribe(()=>{for(let p of W("audio, video",e))p.pause()}),ka(n).pipe(T(p=>a.next(p)),A(()=>a.complete()),m(p=>P({ref:e},p)))}).pipe(qe(ie))}function Hn(e,{viewport$:t,target$:r,print$:o}){return L(...W(".annotate:not(.highlight)",e).map(n=>wn(n,{target$:r,print$:o})),...W("pre:not(.mermaid) > code",e).map(n=>On(n,{target$:r,print$:o})),...W("pre.mermaid",e).map(n=>_n(n)),...W("table:not([class])",e).map(n=>Cn(n)),...W("details",e).map(n=>Mn(n,{target$:r,print$:o})),...W("[data-tabs]",e).map(n=>kn(n,{viewport$:t,target$:r})),...W("[title]",e).filter(()=>G("content.tooltips")).map(n=>Be(n)))}function Ha(e,{alert$:t}){return t.pipe(w(r=>L(R(!0),R(!1).pipe(Qe(2e3))).pipe(m(o=>({message:r,active:o})))))}function $n(e,t){let r=U(".md-typeset",e);return H(()=>{let o=new x;return o.subscribe(({message:n,active:i})=>{e.classList.toggle("md-dialog--active",i),r.textContent=n}),Ha(e,t).pipe(T(n=>o.next(n)),A(()=>o.complete()),m(n=>P({ref:e},n)))})}function $a({viewport$:e}){if(!G("header.autohide"))return R(!1);let t=e.pipe(m(({offset:{y:n}})=>n),Ce(2,1),m(([n,i])=>[nMath.abs(i-n.y)>100),m(([,[n]])=>n),X()),o=Ne("search");return B([e,o]).pipe(m(([{offset:n},i])=>n.y>400&&!i),X(),w(n=>n?r:R(!1)),q(!1))}function Pn(e,t){return H(()=>B([Se(e),$a(t)])).pipe(m(([{height:r},o])=>({height:r,hidden:o})),X((r,o)=>r.height===o.height&&r.hidden===o.hidden),Z(1))}function Rn(e,{header$:t,main$:r}){return H(()=>{let o=new x,n=o.pipe(ee(),oe(!0));o.pipe(te("active"),Ze(t)).subscribe(([{active:s},{hidden:a}])=>{e.classList.toggle("md-header--shadow",s&&!a),e.hidden=a});let i=fe(W("[title]",e)).pipe(v(()=>G("content.tooltips")),re(s=>Be(s)));return r.subscribe(o),t.pipe(j(n),m(s=>P({ref:e},s)),Re(i.pipe(j(n))))})}function Pa(e,{viewport$:t,header$:r}){return mr(e,{viewport$:t,header$:r}).pipe(m(({offset:{y:o}})=>{let{height:n}=le(e);return{active:o>=n}}),te("active"))}function In(e,t){return H(()=>{let r=new x;r.subscribe({next({active:n}){e.classList.toggle("md-header__title--active",n)},complete(){e.classList.remove("md-header__title--active")}});let o=ce(".md-content h1");return typeof o=="undefined"?M:Pa(o,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>P({ref:e},n)))})}function Fn(e,{viewport$:t,header$:r}){let o=r.pipe(m(({height:i})=>i),X()),n=o.pipe(w(()=>Se(e).pipe(m(({height:i})=>({top:e.offsetTop,bottom:e.offsetTop+i})),te("bottom"))));return B([o,n,t]).pipe(m(([i,{top:s,bottom:a},{offset:{y:c},size:{height:p}}])=>(p=Math.max(0,p-Math.max(0,s-c,i)-Math.max(0,p+c-a)),{offset:s-i,height:p,active:s-i<=c})),X((i,s)=>i.offset===s.offset&&i.height===s.height&&i.active===s.active))}function Ra(e){let t=__md_get("__palette")||{index:e.findIndex(r=>matchMedia(r.getAttribute("data-md-color-media")).matches)};return R(...e).pipe(re(r=>h(r,"change").pipe(m(()=>r))),q(e[Math.max(0,t.index)]),m(r=>({index:e.indexOf(r),color:{media:r.getAttribute("data-md-color-media"),scheme:r.getAttribute("data-md-color-scheme"),primary:r.getAttribute("data-md-color-primary"),accent:r.getAttribute("data-md-color-accent")}})),Z(1))}function jn(e){let t=W("input",e),r=S("meta",{name:"theme-color"});document.head.appendChild(r);let o=S("meta",{name:"color-scheme"});document.head.appendChild(o);let n=At("(prefers-color-scheme: light)");return H(()=>{let i=new x;return i.subscribe(s=>{if(document.body.setAttribute("data-md-color-switching",""),s.color.media==="(prefers-color-scheme)"){let a=matchMedia("(prefers-color-scheme: light)"),c=document.querySelector(a.matches?"[data-md-color-media='(prefers-color-scheme: light)']":"[data-md-color-media='(prefers-color-scheme: dark)']");s.color.scheme=c.getAttribute("data-md-color-scheme"),s.color.primary=c.getAttribute("data-md-color-primary"),s.color.accent=c.getAttribute("data-md-color-accent")}for(let[a,c]of Object.entries(s.color))document.body.setAttribute(`data-md-color-${a}`,c);for(let a=0;a{let s=Oe("header"),a=window.getComputedStyle(s);return o.content=a.colorScheme,a.backgroundColor.match(/\d+/g).map(c=>(+c).toString(16).padStart(2,"0")).join("")})).subscribe(s=>r.content=`#${s}`),i.pipe(Me(ie)).subscribe(()=>{document.body.removeAttribute("data-md-color-switching")}),Ra(t).pipe(j(n.pipe(Ee(1))),at(),T(s=>i.next(s)),A(()=>i.complete()),m(s=>P({ref:e},s)))})}function Wn(e,{progress$:t}){return H(()=>{let r=new x;return r.subscribe(({value:o})=>{e.style.setProperty("--md-progress-value",`${o}`)}),t.pipe(T(o=>r.next({value:o})),A(()=>r.complete()),m(o=>({ref:e,value:o})))})}var Yr=jt(Kr());function Ia(e){e.setAttribute("data-md-copying","");let t=e.closest("[data-copy]"),r=t?t.getAttribute("data-copy"):e.innerText;return e.removeAttribute("data-md-copying"),r.trimEnd()}function Un({alert$:e}){Yr.default.isSupported()&&new I(t=>{new Yr.default("[data-clipboard-target], [data-clipboard-text]",{text:r=>r.getAttribute("data-clipboard-text")||Ia(U(r.getAttribute("data-clipboard-target")))}).on("success",r=>t.next(r))}).pipe(T(t=>{t.trigger.focus()}),m(()=>we("clipboard.copied"))).subscribe(e)}function Fa(e){if(e.length<2)return[""];let[t,r]=[...e].sort((n,i)=>n.length-i.length).map(n=>n.replace(/[^/]+$/,"")),o=0;if(t===r)o=t.length;else for(;t.charCodeAt(o)===r.charCodeAt(o);)o++;return e.map(n=>n.replace(t.slice(0,o),""))}function ur(e){let t=__md_get("__sitemap",sessionStorage,e);if(t)return R(t);{let r=he();return on(new URL("sitemap.xml",e||r.base)).pipe(m(o=>Fa(W("loc",o).map(n=>n.textContent))),xe(()=>M),$e([]),T(o=>__md_set("__sitemap",o,sessionStorage,e)))}}function Nn(e){let t=ce("[rel=canonical]",e);typeof t!="undefined"&&(t.href=t.href.replace("//localhost:","//127.0.0.1:"));let r=new Map;for(let o of W(":scope > *",e)){let n=o.outerHTML;for(let i of["href","src"]){let s=o.getAttribute(i);if(s===null)continue;let a=new URL(s,t==null?void 0:t.href),c=o.cloneNode();c.setAttribute(i,`${a}`),n=c.outerHTML;break}r.set(n,o)}return r}function Dn({location$:e,viewport$:t,progress$:r}){let o=he();if(location.protocol==="file:")return M;let n=ur().pipe(m(l=>l.map(f=>`${new URL(f,o.base)}`))),i=h(document.body,"click").pipe(ae(n),w(([l,f])=>{if(!(l.target instanceof Element))return M;let u=l.target.closest("a");if(u===null)return M;if(u.target||l.metaKey||l.ctrlKey)return M;let d=new URL(u.href);return d.search=d.hash="",f.includes(`${d}`)?(l.preventDefault(),R(new URL(u.href))):M}),de());i.pipe(ue(1)).subscribe(()=>{let l=ce("link[rel=icon]");typeof l!="undefined"&&(l.href=l.href)}),h(window,"beforeunload").subscribe(()=>{history.scrollRestoration="auto"}),i.pipe(ae(t)).subscribe(([l,{offset:f}])=>{history.scrollRestoration="manual",history.replaceState(f,""),history.pushState(null,"",l)}),i.subscribe(e);let s=e.pipe(q(me()),te("pathname"),Ee(1),w(l=>lr(l,{progress$:r}).pipe(xe(()=>(st(l,!0),M))))),a=new DOMParser,c=s.pipe(w(l=>l.text()),w(l=>{let f=a.parseFromString(l,"text/html");for(let b of["[data-md-component=announce]","[data-md-component=container]","[data-md-component=header-topic]","[data-md-component=outdated]","[data-md-component=logo]","[data-md-component=skip]",...G("navigation.tabs.sticky")?["[data-md-component=tabs]"]:[]]){let D=ce(b),Q=ce(b,f);typeof D!="undefined"&&typeof Q!="undefined"&&D.replaceWith(Q)}let u=Nn(document.head),d=Nn(f.head);for(let[b,D]of d)D.getAttribute("rel")==="stylesheet"||D.hasAttribute("src")||(u.has(b)?u.delete(b):document.head.appendChild(D));for(let b of u.values())b.getAttribute("rel")==="stylesheet"||b.hasAttribute("src")||b.remove();let y=Oe("container");return We(W("script",y)).pipe(w(b=>{let D=f.createElement("script");if(b.src){for(let Q of b.getAttributeNames())D.setAttribute(Q,b.getAttribute(Q));return b.replaceWith(D),new I(Q=>{D.onload=()=>Q.complete()})}else return D.textContent=b.textContent,b.replaceWith(D),M}),ee(),oe(f))}),de());return h(window,"popstate").pipe(m(me)).subscribe(e),e.pipe(q(me()),Ce(2,1),v(([l,f])=>l.pathname===f.pathname&&l.hash!==f.hash),m(([,l])=>l)).subscribe(l=>{var f,u;history.state!==null||!l.hash?window.scrollTo(0,(u=(f=history.state)==null?void 0:f.y)!=null?u:0):(history.scrollRestoration="auto",pr(l.hash),history.scrollRestoration="manual")}),e.pipe(Ir(i),q(me()),Ce(2,1),v(([l,f])=>l.pathname===f.pathname&&l.hash===f.hash),m(([,l])=>l)).subscribe(l=>{history.scrollRestoration="auto",pr(l.hash),history.scrollRestoration="manual",history.back()}),c.pipe(ae(e)).subscribe(([,l])=>{var f,u;history.state!==null||!l.hash?window.scrollTo(0,(u=(f=history.state)==null?void 0:f.y)!=null?u:0):pr(l.hash)}),t.pipe(te("offset"),ye(100)).subscribe(({offset:l})=>{history.replaceState(l,"")}),c}var qn=jt(zn());function Kn(e){let t=e.separator.split("|").map(n=>n.replace(/(\(\?[!=<][^)]+\))/g,"").length===0?"\uFFFD":n).join("|"),r=new RegExp(t,"img"),o=(n,i,s)=>`${i}${s}`;return n=>{n=n.replace(/[\s*+\-:~^]+/g," ").trim();let i=new RegExp(`(^|${e.separator}|)(${n.replace(/[|\\{}()[\]^$+*?.-]/g,"\\$&").replace(r,"|")})`,"img");return s=>(0,qn.default)(s).replace(i,o).replace(/<\/mark>(\s+)]*>/img,"$1")}}function Ht(e){return e.type===1}function dr(e){return e.type===3}function Qn(e,t){let r=ln(e);return L(R(location.protocol!=="file:"),Ne("search")).pipe(Pe(o=>o),w(()=>t)).subscribe(({config:o,docs:n})=>r.next({type:0,data:{config:o,docs:n,options:{suggest:G("search.suggest")}}})),r}function Yn({document$:e}){let t=he(),r=De(new URL("../versions.json",t.base)).pipe(xe(()=>M)),o=r.pipe(m(n=>{let[,i]=t.base.match(/([^/]+)\/?$/);return n.find(({version:s,aliases:a})=>s===i||a.includes(i))||n[0]}));r.pipe(m(n=>new Map(n.map(i=>[`${new URL(`../${i.version}/`,t.base)}`,i]))),w(n=>h(document.body,"click").pipe(v(i=>!i.metaKey&&!i.ctrlKey),ae(o),w(([i,s])=>{if(i.target instanceof Element){let a=i.target.closest("a");if(a&&!a.target&&n.has(a.href)){let c=a.href;return!i.target.closest(".md-version")&&n.get(c)===s?M:(i.preventDefault(),R(c))}}return M}),w(i=>{let{version:s}=n.get(i);return ur(new URL(i)).pipe(m(a=>{let p=me().href.replace(t.base,"");return a.includes(p.split("#")[0])?new URL(`../${s}/${p}`,t.base):new URL(i)}))})))).subscribe(n=>st(n,!0)),B([r,o]).subscribe(([n,i])=>{U(".md-header__topic").appendChild(gn(n,i))}),e.pipe(w(()=>o)).subscribe(n=>{var s;let i=__md_get("__outdated",sessionStorage);if(i===null){i=!0;let a=((s=t.version)==null?void 0:s.default)||"latest";Array.isArray(a)||(a=[a]);e:for(let c of a)for(let p of n.aliases.concat(n.version))if(new RegExp(c,"i").test(p)){i=!1;break e}__md_set("__outdated",i,sessionStorage)}if(i)for(let a of ne("outdated"))a.hidden=!1})}function Da(e,{worker$:t}){let{searchParams:r}=me();r.has("q")&&(Ye("search",!0),e.value=r.get("q"),e.focus(),Ne("search").pipe(Pe(i=>!i)).subscribe(()=>{let i=me();i.searchParams.delete("q"),history.replaceState({},"",`${i}`)}));let o=vt(e),n=L(t.pipe(Pe(Ht)),h(e,"keyup"),o).pipe(m(()=>e.value),X());return B([n,o]).pipe(m(([i,s])=>({value:i,focus:s})),Z(1))}function Bn(e,{worker$:t}){let r=new x,o=r.pipe(ee(),oe(!0));B([t.pipe(Pe(Ht)),r],(i,s)=>s).pipe(te("value")).subscribe(({value:i})=>t.next({type:2,data:i})),r.pipe(te("focus")).subscribe(({focus:i})=>{i&&Ye("search",i)}),h(e.form,"reset").pipe(j(o)).subscribe(()=>e.focus());let n=U("header [for=__search]");return h(n,"click").subscribe(()=>e.focus()),Da(e,{worker$:t}).pipe(T(i=>r.next(i)),A(()=>r.complete()),m(i=>P({ref:e},i)),Z(1))}function Gn(e,{worker$:t,query$:r}){let o=new x,n=Go(e.parentElement).pipe(v(Boolean)),i=e.parentElement,s=U(":scope > :first-child",e),a=U(":scope > :last-child",e);Ne("search").subscribe(l=>a.setAttribute("role",l?"list":"presentation")),o.pipe(ae(r),Wr(t.pipe(Pe(Ht)))).subscribe(([{items:l},{value:f}])=>{switch(l.length){case 0:s.textContent=f.length?we("search.result.none"):we("search.result.placeholder");break;case 1:s.textContent=we("search.result.one");break;default:let u=ar(l.length);s.textContent=we("search.result.other",u)}});let c=o.pipe(T(()=>a.innerHTML=""),w(({items:l})=>L(R(...l.slice(0,10)),R(...l.slice(10)).pipe(Ce(4),Nr(n),w(([f])=>f)))),m(hn),de());return c.subscribe(l=>a.appendChild(l)),c.pipe(re(l=>{let f=ce("details",l);return typeof f=="undefined"?M:h(f,"toggle").pipe(j(o),m(()=>f))})).subscribe(l=>{l.open===!1&&l.offsetTop<=i.scrollTop&&i.scrollTo({top:l.offsetTop})}),t.pipe(v(dr),m(({data:l})=>l)).pipe(T(l=>o.next(l)),A(()=>o.complete()),m(l=>P({ref:e},l)))}function Va(e,{query$:t}){return t.pipe(m(({value:r})=>{let o=me();return o.hash="",r=r.replace(/\s+/g,"+").replace(/&/g,"%26").replace(/=/g,"%3D"),o.search=`q=${r}`,{url:o}}))}function Jn(e,t){let r=new x,o=r.pipe(ee(),oe(!0));return r.subscribe(({url:n})=>{e.setAttribute("data-clipboard-text",e.href),e.href=`${n}`}),h(e,"click").pipe(j(o)).subscribe(n=>n.preventDefault()),Va(e,t).pipe(T(n=>r.next(n)),A(()=>r.complete()),m(n=>P({ref:e},n)))}function Xn(e,{worker$:t,keyboard$:r}){let o=new x,n=Oe("search-query"),i=L(h(n,"keydown"),h(n,"focus")).pipe(Me(ie),m(()=>n.value),X());return o.pipe(Ze(i),m(([{suggest:a},c])=>{let p=c.split(/([\s-]+)/);if(a!=null&&a.length&&p[p.length-1]){let l=a[a.length-1];l.startsWith(p[p.length-1])&&(p[p.length-1]=l)}else p.length=0;return p})).subscribe(a=>e.innerHTML=a.join("").replace(/\s/g," ")),r.pipe(v(({mode:a})=>a==="search")).subscribe(a=>{switch(a.type){case"ArrowRight":e.innerText.length&&n.selectionStart===n.value.length&&(n.value=e.innerText);break}}),t.pipe(v(dr),m(({data:a})=>a)).pipe(T(a=>o.next(a)),A(()=>o.complete()),m(()=>({ref:e})))}function Zn(e,{index$:t,keyboard$:r}){let o=he();try{let n=Qn(o.search,t),i=Oe("search-query",e),s=Oe("search-result",e);h(e,"click").pipe(v(({target:c})=>c instanceof Element&&!!c.closest("a"))).subscribe(()=>Ye("search",!1)),r.pipe(v(({mode:c})=>c==="search")).subscribe(c=>{let p=Ie();switch(c.type){case"Enter":if(p===i){let l=new Map;for(let f of W(":first-child [href]",s)){let u=f.firstElementChild;l.set(f,parseFloat(u.getAttribute("data-md-score")))}if(l.size){let[[f]]=[...l].sort(([,u],[,d])=>d-u);f.click()}c.claim()}break;case"Escape":case"Tab":Ye("search",!1),i.blur();break;case"ArrowUp":case"ArrowDown":if(typeof p=="undefined")i.focus();else{let l=[i,...W(":not(details) > [href], summary, details[open] [href]",s)],f=Math.max(0,(Math.max(0,l.indexOf(p))+l.length+(c.type==="ArrowUp"?-1:1))%l.length);l[f].focus()}c.claim();break;default:i!==Ie()&&i.focus()}}),r.pipe(v(({mode:c})=>c==="global")).subscribe(c=>{switch(c.type){case"f":case"s":case"/":i.focus(),i.select(),c.claim();break}});let a=Bn(i,{worker$:n});return L(a,Gn(s,{worker$:n,query$:a})).pipe(Re(...ne("search-share",e).map(c=>Jn(c,{query$:a})),...ne("search-suggest",e).map(c=>Xn(c,{worker$:n,keyboard$:r}))))}catch(n){return e.hidden=!0,Ke}}function ei(e,{index$:t,location$:r}){return B([t,r.pipe(q(me()),v(o=>!!o.searchParams.get("h")))]).pipe(m(([o,n])=>Kn(o.config)(n.searchParams.get("h"))),m(o=>{var s;let n=new Map,i=document.createNodeIterator(e,NodeFilter.SHOW_TEXT);for(let a=i.nextNode();a;a=i.nextNode())if((s=a.parentElement)!=null&&s.offsetHeight){let c=a.textContent,p=o(c);p.length>c.length&&n.set(a,p)}for(let[a,c]of n){let{childNodes:p}=S("span",null,c);a.replaceWith(...Array.from(p))}return{ref:e,nodes:n}}))}function za(e,{viewport$:t,main$:r}){let o=e.closest(".md-grid"),n=o.offsetTop-o.parentElement.offsetTop;return B([r,t]).pipe(m(([{offset:i,height:s},{offset:{y:a}}])=>(s=s+Math.min(n,Math.max(0,a-i))-n,{height:s,locked:a>=i+n})),X((i,s)=>i.height===s.height&&i.locked===s.locked))}function Br(e,o){var n=o,{header$:t}=n,r=oo(n,["header$"]);let i=U(".md-sidebar__scrollwrap",e),{y:s}=Ue(i);return H(()=>{let a=new x,c=a.pipe(ee(),oe(!0)),p=a.pipe(Le(0,ge));return p.pipe(ae(t)).subscribe({next([{height:l},{height:f}]){i.style.height=`${l-2*s}px`,e.style.top=`${f}px`},complete(){i.style.height="",e.style.top=""}}),p.pipe(Pe()).subscribe(()=>{for(let l of W(".md-nav__link--active[href]",e)){if(!l.clientHeight)continue;let f=l.closest(".md-sidebar__scrollwrap");if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=le(f);f.scrollTo({top:u-d/2})}}}),fe(W("label[tabindex]",e)).pipe(re(l=>h(l,"click").pipe(Me(ie),m(()=>l),j(c)))).subscribe(l=>{let f=U(`[id="${l.htmlFor}"]`);U(`[aria-labelledby="${l.id}"]`).setAttribute("aria-expanded",`${f.checked}`)}),za(e,r).pipe(T(l=>a.next(l)),A(()=>a.complete()),m(l=>P({ref:e},l)))})}function ti(e,t){if(typeof t!="undefined"){let r=`https://api.github.com/repos/${e}/${t}`;return Lt(De(`${r}/releases/latest`).pipe(xe(()=>M),m(o=>({version:o.tag_name})),$e({})),De(r).pipe(xe(()=>M),m(o=>({stars:o.stargazers_count,forks:o.forks_count})),$e({}))).pipe(m(([o,n])=>P(P({},o),n)))}else{let r=`https://api.github.com/users/${e}`;return De(r).pipe(m(o=>({repositories:o.public_repos})),$e({}))}}function ri(e,t){let r=`https://${e}/api/v4/projects/${encodeURIComponent(t)}`;return De(r).pipe(xe(()=>M),m(({star_count:o,forks_count:n})=>({stars:o,forks:n})),$e({}))}function oi(e){let t=e.match(/^.+github\.com\/([^/]+)\/?([^/]+)?/i);if(t){let[,r,o]=t;return ti(r,o)}if(t=e.match(/^.+?([^/]*gitlab[^/]+)\/(.+?)\/?$/i),t){let[,r,o]=t;return ri(r,o)}return M}var qa;function Ka(e){return qa||(qa=H(()=>{let t=__md_get("__source",sessionStorage);if(t)return R(t);if(ne("consent").length){let o=__md_get("__consent");if(!(o&&o.github))return M}return oi(e.href).pipe(T(o=>__md_set("__source",o,sessionStorage)))}).pipe(xe(()=>M),v(t=>Object.keys(t).length>0),m(t=>({facts:t})),Z(1)))}function ni(e){let t=U(":scope > :last-child",e);return H(()=>{let r=new x;return r.subscribe(({facts:o})=>{t.appendChild(bn(o)),t.classList.add("md-source__repository--active")}),Ka(e).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}function Qa(e,{viewport$:t,header$:r}){return Se(document.body).pipe(w(()=>mr(e,{header$:r,viewport$:t})),m(({offset:{y:o}})=>({hidden:o>=10})),te("hidden"))}function ii(e,t){return H(()=>{let r=new x;return r.subscribe({next({hidden:o}){e.hidden=o},complete(){e.hidden=!1}}),(G("navigation.tabs.sticky")?R({hidden:!1}):Qa(e,t)).pipe(T(o=>r.next(o)),A(()=>r.complete()),m(o=>P({ref:e},o)))})}function Ya(e,{viewport$:t,header$:r}){let o=new Map,n=W("[href^=\\#]",e);for(let a of n){let c=decodeURIComponent(a.hash.substring(1)),p=ce(`[id="${c}"]`);typeof p!="undefined"&&o.set(a,p)}let i=r.pipe(te("height"),m(({height:a})=>{let c=Oe("main"),p=U(":scope > :first-child",c);return a+.8*(p.offsetTop-c.offsetTop)}),de());return Se(document.body).pipe(te("height"),w(a=>H(()=>{let c=[];return R([...o].reduce((p,[l,f])=>{for(;c.length&&o.get(c[c.length-1]).tagName>=f.tagName;)c.pop();let u=f.offsetTop;for(;!u&&f.parentElement;)f=f.parentElement,u=f.offsetTop;let d=f.offsetParent;for(;d;d=d.offsetParent)u+=d.offsetTop;return p.set([...c=[...c,l]].reverse(),u)},new Map))}).pipe(m(c=>new Map([...c].sort(([,p],[,l])=>p-l))),Ze(i),w(([c,p])=>t.pipe(Fr(([l,f],{offset:{y:u},size:d})=>{let y=u+d.height>=Math.floor(a.height);for(;f.length;){let[,b]=f[0];if(b-p=u&&!y)f=[l.pop(),...f];else break}return[l,f]},[[],[...c]]),X((l,f)=>l[0]===f[0]&&l[1]===f[1])))))).pipe(m(([a,c])=>({prev:a.map(([p])=>p),next:c.map(([p])=>p)})),q({prev:[],next:[]}),Ce(2,1),m(([a,c])=>a.prev.length{let i=new x,s=i.pipe(ee(),oe(!0));if(i.subscribe(({prev:a,next:c})=>{for(let[p]of c)p.classList.remove("md-nav__link--passed"),p.classList.remove("md-nav__link--active");for(let[p,[l]]of a.entries())l.classList.add("md-nav__link--passed"),l.classList.toggle("md-nav__link--active",p===a.length-1)}),G("toc.follow")){let a=L(t.pipe(ye(1),m(()=>{})),t.pipe(ye(250),m(()=>"smooth")));i.pipe(v(({prev:c})=>c.length>0),Ze(o.pipe(Me(ie))),ae(a)).subscribe(([[{prev:c}],p])=>{let[l]=c[c.length-1];if(l.offsetHeight){let f=sr(l);if(typeof f!="undefined"){let u=l.offsetTop-f.offsetTop,{height:d}=le(f);f.scrollTo({top:u-d/2,behavior:p})}}})}return G("navigation.tracking")&&t.pipe(j(s),te("offset"),ye(250),Ee(1),j(n.pipe(Ee(1))),at({delay:250}),ae(i)).subscribe(([,{prev:a}])=>{let c=me(),p=a[a.length-1];if(p&&p.length){let[l]=p,{hash:f}=new URL(l.href);c.hash!==f&&(c.hash=f,history.replaceState({},"",`${c}`))}else c.hash="",history.replaceState({},"",`${c}`)}),Ya(e,{viewport$:t,header$:r}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))})}function Ba(e,{viewport$:t,main$:r,target$:o}){let n=t.pipe(m(({offset:{y:s}})=>s),Ce(2,1),m(([s,a])=>s>a&&a>0),X()),i=r.pipe(m(({active:s})=>s));return B([i,n]).pipe(m(([s,a])=>!(s&&a)),X(),j(o.pipe(Ee(1))),oe(!0),at({delay:250}),m(s=>({hidden:s})))}function si(e,{viewport$:t,header$:r,main$:o,target$:n}){let i=new x,s=i.pipe(ee(),oe(!0));return i.subscribe({next({hidden:a}){e.hidden=a,a?(e.setAttribute("tabindex","-1"),e.blur()):e.removeAttribute("tabindex")},complete(){e.style.top="",e.hidden=!0,e.removeAttribute("tabindex")}}),r.pipe(j(s),te("height")).subscribe(({height:a})=>{e.style.top=`${a+16}px`}),h(e,"click").subscribe(a=>{a.preventDefault(),window.scrollTo({top:0})}),Ba(e,{viewport$:t,main$:o,target$:n}).pipe(T(a=>i.next(a)),A(()=>i.complete()),m(a=>P({ref:e},a)))}function ci({document$:e}){e.pipe(w(()=>W(".md-ellipsis")),re(t=>yt(t).pipe(j(e.pipe(Ee(1))),v(r=>r),m(()=>t),ue(1))),v(t=>t.offsetWidth{let r=t.innerText,o=t.closest("a")||t;return o.title=r,Be(o).pipe(j(e.pipe(Ee(1))),A(()=>o.removeAttribute("title")))})).subscribe(),e.pipe(w(()=>W(".md-status")),re(t=>Be(t))).subscribe()}function pi({document$:e,tablet$:t}){e.pipe(w(()=>W(".md-toggle--indeterminate")),T(r=>{r.indeterminate=!0,r.checked=!1}),re(r=>h(r,"change").pipe(Ur(()=>r.classList.contains("md-toggle--indeterminate")),m(()=>r))),ae(t)).subscribe(([r,o])=>{r.classList.remove("md-toggle--indeterminate"),o&&(r.checked=!1)})}function Ga(){return/(iPad|iPhone|iPod)/.test(navigator.userAgent)}function li({document$:e}){e.pipe(w(()=>W("[data-md-scrollfix]")),T(t=>t.removeAttribute("data-md-scrollfix")),v(Ga),re(t=>h(t,"touchstart").pipe(m(()=>t)))).subscribe(t=>{let r=t.scrollTop;r===0?t.scrollTop=1:r+t.offsetHeight===t.scrollHeight&&(t.scrollTop=r-1)})}function mi({viewport$:e,tablet$:t}){B([Ne("search"),t]).pipe(m(([r,o])=>r&&!o),w(r=>R(r).pipe(Qe(r?400:100))),ae(e)).subscribe(([r,{offset:{y:o}}])=>{if(r)document.body.setAttribute("data-md-scrolllock",""),document.body.style.top=`-${o}px`;else{let n=-1*parseInt(document.body.style.top,10);document.body.removeAttribute("data-md-scrolllock"),document.body.style.top="",n&&window.scrollTo(0,n)}})}Object.entries||(Object.entries=function(e){let t=[];for(let r of Object.keys(e))t.push([r,e[r]]);return t});Object.values||(Object.values=function(e){let t=[];for(let r of Object.keys(e))t.push(e[r]);return t});typeof Element!="undefined"&&(Element.prototype.scrollTo||(Element.prototype.scrollTo=function(e,t){typeof e=="object"?(this.scrollLeft=e.left,this.scrollTop=e.top):(this.scrollLeft=e,this.scrollTop=t)}),Element.prototype.replaceWith||(Element.prototype.replaceWith=function(...e){let t=this.parentNode;if(t){e.length===0&&t.removeChild(this);for(let r=e.length-1;r>=0;r--){let o=e[r];typeof o=="string"?o=document.createTextNode(o):o.parentNode&&o.parentNode.removeChild(o),r?t.insertBefore(this.previousSibling,o):t.replaceChild(o,this)}}}));function Ja(){return location.protocol==="file:"?gt(`${new URL("search/search_index.js",Gr.base)}`).pipe(m(()=>__index),Z(1)):De(new URL("search/search_index.json",Gr.base))}document.documentElement.classList.remove("no-js");document.documentElement.classList.add("js");var rt=zo(),Pt=Zo(),wt=tn(Pt),Jr=Xo(),_e=pn(),hr=At("(min-width: 960px)"),ui=At("(min-width: 1220px)"),di=rn(),Gr=he(),hi=document.forms.namedItem("search")?Ja():Ke,Xr=new x;Un({alert$:Xr});var Zr=new x;G("navigation.instant")&&Dn({location$:Pt,viewport$:_e,progress$:Zr}).subscribe(rt);var fi;((fi=Gr.version)==null?void 0:fi.provider)==="mike"&&Yn({document$:rt});L(Pt,wt).pipe(Qe(125)).subscribe(()=>{Ye("drawer",!1),Ye("search",!1)});Jr.pipe(v(({mode:e})=>e==="global")).subscribe(e=>{switch(e.type){case"p":case",":let t=ce("link[rel=prev]");typeof t!="undefined"&&st(t);break;case"n":case".":let r=ce("link[rel=next]");typeof r!="undefined"&&st(r);break;case"Enter":let o=Ie();o instanceof HTMLLabelElement&&o.click()}});ci({document$:rt});pi({document$:rt,tablet$:hr});li({document$:rt});mi({viewport$:_e,tablet$:hr});var tt=Pn(Oe("header"),{viewport$:_e}),$t=rt.pipe(m(()=>Oe("main")),w(e=>Fn(e,{viewport$:_e,header$:tt})),Z(1)),Xa=L(...ne("consent").map(e=>fn(e,{target$:wt})),...ne("dialog").map(e=>$n(e,{alert$:Xr})),...ne("header").map(e=>Rn(e,{viewport$:_e,header$:tt,main$:$t})),...ne("palette").map(e=>jn(e)),...ne("progress").map(e=>Wn(e,{progress$:Zr})),...ne("search").map(e=>Zn(e,{index$:hi,keyboard$:Jr})),...ne("source").map(e=>ni(e))),Za=H(()=>L(...ne("announce").map(e=>mn(e)),...ne("content").map(e=>Hn(e,{viewport$:_e,target$:wt,print$:di})),...ne("content").map(e=>G("search.highlight")?ei(e,{index$:hi,location$:Pt}):M),...ne("header-title").map(e=>In(e,{viewport$:_e,header$:tt})),...ne("sidebar").map(e=>e.getAttribute("data-md-type")==="navigation"?Dr(ui,()=>Br(e,{viewport$:_e,header$:tt,main$:$t})):Dr(hr,()=>Br(e,{viewport$:_e,header$:tt,main$:$t}))),...ne("tabs").map(e=>ii(e,{viewport$:_e,header$:tt})),...ne("toc").map(e=>ai(e,{viewport$:_e,header$:tt,main$:$t,target$:wt})),...ne("top").map(e=>si(e,{viewport$:_e,header$:tt,main$:$t,target$:wt})))),bi=rt.pipe(w(()=>Za),Re(Xa),Z(1));bi.subscribe();window.document$=rt;window.location$=Pt;window.target$=wt;window.keyboard$=Jr;window.viewport$=_e;window.tablet$=hr;window.screen$=ui;window.print$=di;window.alert$=Xr;window.progress$=Zr;window.component$=bi;})(); +//# sourceMappingURL=bundle.d7c377c4.min.js.map + diff --git a/assets/javascripts/bundle.d7c377c4.min.js.map b/assets/javascripts/bundle.d7c377c4.min.js.map new file mode 100644 index 0000000..a57d388 --- /dev/null +++ b/assets/javascripts/bundle.d7c377c4.min.js.map @@ -0,0 +1,7 @@ +{ + "version": 3, + "sources": ["node_modules/focus-visible/dist/focus-visible.js", "node_modules/clipboard/dist/clipboard.js", "node_modules/escape-html/index.js", "src/templates/assets/javascripts/bundle.ts", "node_modules/rxjs/node_modules/tslib/tslib.es6.js", "node_modules/rxjs/src/internal/util/isFunction.ts", "node_modules/rxjs/src/internal/util/createErrorClass.ts", "node_modules/rxjs/src/internal/util/UnsubscriptionError.ts", "node_modules/rxjs/src/internal/util/arrRemove.ts", "node_modules/rxjs/src/internal/Subscription.ts", "node_modules/rxjs/src/internal/config.ts", "node_modules/rxjs/src/internal/scheduler/timeoutProvider.ts", "node_modules/rxjs/src/internal/util/reportUnhandledError.ts", "node_modules/rxjs/src/internal/util/noop.ts", "node_modules/rxjs/src/internal/NotificationFactories.ts", "node_modules/rxjs/src/internal/util/errorContext.ts", "node_modules/rxjs/src/internal/Subscriber.ts", "node_modules/rxjs/src/internal/symbol/observable.ts", "node_modules/rxjs/src/internal/util/identity.ts", "node_modules/rxjs/src/internal/util/pipe.ts", "node_modules/rxjs/src/internal/Observable.ts", "node_modules/rxjs/src/internal/util/lift.ts", "node_modules/rxjs/src/internal/operators/OperatorSubscriber.ts", "node_modules/rxjs/src/internal/scheduler/animationFrameProvider.ts", "node_modules/rxjs/src/internal/util/ObjectUnsubscribedError.ts", "node_modules/rxjs/src/internal/Subject.ts", "node_modules/rxjs/src/internal/scheduler/dateTimestampProvider.ts", "node_modules/rxjs/src/internal/ReplaySubject.ts", "node_modules/rxjs/src/internal/scheduler/Action.ts", "node_modules/rxjs/src/internal/scheduler/intervalProvider.ts", "node_modules/rxjs/src/internal/scheduler/AsyncAction.ts", "node_modules/rxjs/src/internal/Scheduler.ts", "node_modules/rxjs/src/internal/scheduler/AsyncScheduler.ts", "node_modules/rxjs/src/internal/scheduler/async.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameAction.ts", "node_modules/rxjs/src/internal/scheduler/AnimationFrameScheduler.ts", "node_modules/rxjs/src/internal/scheduler/animationFrame.ts", "node_modules/rxjs/src/internal/observable/empty.ts", "node_modules/rxjs/src/internal/util/isScheduler.ts", "node_modules/rxjs/src/internal/util/args.ts", "node_modules/rxjs/src/internal/util/isArrayLike.ts", "node_modules/rxjs/src/internal/util/isPromise.ts", "node_modules/rxjs/src/internal/util/isInteropObservable.ts", "node_modules/rxjs/src/internal/util/isAsyncIterable.ts", "node_modules/rxjs/src/internal/util/throwUnobservableError.ts", "node_modules/rxjs/src/internal/symbol/iterator.ts", "node_modules/rxjs/src/internal/util/isIterable.ts", "node_modules/rxjs/src/internal/util/isReadableStreamLike.ts", "node_modules/rxjs/src/internal/observable/innerFrom.ts", "node_modules/rxjs/src/internal/util/executeSchedule.ts", "node_modules/rxjs/src/internal/operators/observeOn.ts", "node_modules/rxjs/src/internal/operators/subscribeOn.ts", "node_modules/rxjs/src/internal/scheduled/scheduleObservable.ts", "node_modules/rxjs/src/internal/scheduled/schedulePromise.ts", "node_modules/rxjs/src/internal/scheduled/scheduleArray.ts", "node_modules/rxjs/src/internal/scheduled/scheduleIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleAsyncIterable.ts", "node_modules/rxjs/src/internal/scheduled/scheduleReadableStreamLike.ts", "node_modules/rxjs/src/internal/scheduled/scheduled.ts", "node_modules/rxjs/src/internal/observable/from.ts", "node_modules/rxjs/src/internal/observable/of.ts", "node_modules/rxjs/src/internal/observable/throwError.ts", "node_modules/rxjs/src/internal/util/EmptyError.ts", "node_modules/rxjs/src/internal/util/isDate.ts", "node_modules/rxjs/src/internal/operators/map.ts", "node_modules/rxjs/src/internal/util/mapOneOrManyArgs.ts", "node_modules/rxjs/src/internal/util/argsArgArrayOrObject.ts", "node_modules/rxjs/src/internal/util/createObject.ts", "node_modules/rxjs/src/internal/observable/combineLatest.ts", "node_modules/rxjs/src/internal/operators/mergeInternals.ts", "node_modules/rxjs/src/internal/operators/mergeMap.ts", "node_modules/rxjs/src/internal/operators/mergeAll.ts", "node_modules/rxjs/src/internal/operators/concatAll.ts", "node_modules/rxjs/src/internal/observable/concat.ts", "node_modules/rxjs/src/internal/observable/defer.ts", "node_modules/rxjs/src/internal/observable/fromEvent.ts", "node_modules/rxjs/src/internal/observable/fromEventPattern.ts", "node_modules/rxjs/src/internal/observable/timer.ts", "node_modules/rxjs/src/internal/observable/merge.ts", "node_modules/rxjs/src/internal/observable/never.ts", "node_modules/rxjs/src/internal/util/argsOrArgArray.ts", "node_modules/rxjs/src/internal/operators/filter.ts", "node_modules/rxjs/src/internal/observable/zip.ts", "node_modules/rxjs/src/internal/operators/audit.ts", "node_modules/rxjs/src/internal/operators/auditTime.ts", "node_modules/rxjs/src/internal/operators/bufferCount.ts", "node_modules/rxjs/src/internal/operators/catchError.ts", "node_modules/rxjs/src/internal/operators/scanInternals.ts", "node_modules/rxjs/src/internal/operators/combineLatest.ts", "node_modules/rxjs/src/internal/operators/combineLatestWith.ts", "node_modules/rxjs/src/internal/operators/debounceTime.ts", "node_modules/rxjs/src/internal/operators/defaultIfEmpty.ts", "node_modules/rxjs/src/internal/operators/take.ts", "node_modules/rxjs/src/internal/operators/ignoreElements.ts", "node_modules/rxjs/src/internal/operators/mapTo.ts", "node_modules/rxjs/src/internal/operators/delayWhen.ts", "node_modules/rxjs/src/internal/operators/delay.ts", "node_modules/rxjs/src/internal/operators/distinctUntilChanged.ts", "node_modules/rxjs/src/internal/operators/distinctUntilKeyChanged.ts", "node_modules/rxjs/src/internal/operators/throwIfEmpty.ts", "node_modules/rxjs/src/internal/operators/endWith.ts", "node_modules/rxjs/src/internal/operators/finalize.ts", "node_modules/rxjs/src/internal/operators/first.ts", "node_modules/rxjs/src/internal/operators/takeLast.ts", "node_modules/rxjs/src/internal/operators/merge.ts", "node_modules/rxjs/src/internal/operators/mergeWith.ts", "node_modules/rxjs/src/internal/operators/repeat.ts", "node_modules/rxjs/src/internal/operators/sample.ts", "node_modules/rxjs/src/internal/operators/scan.ts", "node_modules/rxjs/src/internal/operators/share.ts", "node_modules/rxjs/src/internal/operators/shareReplay.ts", "node_modules/rxjs/src/internal/operators/skip.ts", "node_modules/rxjs/src/internal/operators/skipUntil.ts", "node_modules/rxjs/src/internal/operators/startWith.ts", "node_modules/rxjs/src/internal/operators/switchMap.ts", "node_modules/rxjs/src/internal/operators/takeUntil.ts", "node_modules/rxjs/src/internal/operators/takeWhile.ts", "node_modules/rxjs/src/internal/operators/tap.ts", "node_modules/rxjs/src/internal/operators/throttle.ts", "node_modules/rxjs/src/internal/operators/throttleTime.ts", "node_modules/rxjs/src/internal/operators/withLatestFrom.ts", "node_modules/rxjs/src/internal/operators/zip.ts", "node_modules/rxjs/src/internal/operators/zipWith.ts", "src/templates/assets/javascripts/browser/document/index.ts", "src/templates/assets/javascripts/browser/element/_/index.ts", "src/templates/assets/javascripts/browser/element/focus/index.ts", "src/templates/assets/javascripts/browser/element/hover/index.ts", "src/templates/assets/javascripts/browser/element/offset/_/index.ts", "src/templates/assets/javascripts/browser/element/offset/content/index.ts", "src/templates/assets/javascripts/utilities/h/index.ts", "src/templates/assets/javascripts/utilities/round/index.ts", "src/templates/assets/javascripts/browser/script/index.ts", "src/templates/assets/javascripts/browser/element/size/_/index.ts", "src/templates/assets/javascripts/browser/element/size/content/index.ts", "src/templates/assets/javascripts/browser/element/visibility/index.ts", "src/templates/assets/javascripts/browser/toggle/index.ts", "src/templates/assets/javascripts/browser/keyboard/index.ts", "src/templates/assets/javascripts/browser/location/_/index.ts", "src/templates/assets/javascripts/browser/location/hash/index.ts", "src/templates/assets/javascripts/browser/media/index.ts", "src/templates/assets/javascripts/browser/request/index.ts", "src/templates/assets/javascripts/browser/viewport/offset/index.ts", "src/templates/assets/javascripts/browser/viewport/size/index.ts", "src/templates/assets/javascripts/browser/viewport/_/index.ts", "src/templates/assets/javascripts/browser/viewport/at/index.ts", "src/templates/assets/javascripts/browser/worker/index.ts", "src/templates/assets/javascripts/_/index.ts", "src/templates/assets/javascripts/components/_/index.ts", "src/templates/assets/javascripts/components/announce/index.ts", "src/templates/assets/javascripts/components/consent/index.ts", "src/templates/assets/javascripts/templates/tooltip/index.tsx", "src/templates/assets/javascripts/templates/annotation/index.tsx", "src/templates/assets/javascripts/templates/clipboard/index.tsx", "src/templates/assets/javascripts/templates/search/index.tsx", "src/templates/assets/javascripts/templates/source/index.tsx", "src/templates/assets/javascripts/templates/tabbed/index.tsx", "src/templates/assets/javascripts/templates/table/index.tsx", "src/templates/assets/javascripts/templates/version/index.tsx", "src/templates/assets/javascripts/components/tooltip/index.ts", "src/templates/assets/javascripts/components/content/annotation/_/index.ts", "src/templates/assets/javascripts/components/content/annotation/list/index.ts", "src/templates/assets/javascripts/components/content/annotation/block/index.ts", "src/templates/assets/javascripts/components/content/code/_/index.ts", "src/templates/assets/javascripts/components/content/details/index.ts", "src/templates/assets/javascripts/components/content/mermaid/index.css", "src/templates/assets/javascripts/components/content/mermaid/index.ts", "src/templates/assets/javascripts/components/content/table/index.ts", "src/templates/assets/javascripts/components/content/tabs/index.ts", "src/templates/assets/javascripts/components/content/_/index.ts", "src/templates/assets/javascripts/components/dialog/index.ts", "src/templates/assets/javascripts/components/header/_/index.ts", "src/templates/assets/javascripts/components/header/title/index.ts", "src/templates/assets/javascripts/components/main/index.ts", "src/templates/assets/javascripts/components/palette/index.ts", "src/templates/assets/javascripts/components/progress/index.ts", "src/templates/assets/javascripts/integrations/clipboard/index.ts", "src/templates/assets/javascripts/integrations/sitemap/index.ts", "src/templates/assets/javascripts/integrations/instant/index.ts", "src/templates/assets/javascripts/integrations/search/highlighter/index.ts", "src/templates/assets/javascripts/integrations/search/worker/message/index.ts", "src/templates/assets/javascripts/integrations/search/worker/_/index.ts", "src/templates/assets/javascripts/integrations/version/index.ts", "src/templates/assets/javascripts/components/search/query/index.ts", "src/templates/assets/javascripts/components/search/result/index.ts", "src/templates/assets/javascripts/components/search/share/index.ts", "src/templates/assets/javascripts/components/search/suggest/index.ts", "src/templates/assets/javascripts/components/search/_/index.ts", "src/templates/assets/javascripts/components/search/highlight/index.ts", "src/templates/assets/javascripts/components/sidebar/index.ts", "src/templates/assets/javascripts/components/source/facts/github/index.ts", "src/templates/assets/javascripts/components/source/facts/gitlab/index.ts", "src/templates/assets/javascripts/components/source/facts/_/index.ts", "src/templates/assets/javascripts/components/source/_/index.ts", "src/templates/assets/javascripts/components/tabs/index.ts", "src/templates/assets/javascripts/components/toc/index.ts", "src/templates/assets/javascripts/components/top/index.ts", "src/templates/assets/javascripts/patches/ellipsis/index.ts", "src/templates/assets/javascripts/patches/indeterminate/index.ts", "src/templates/assets/javascripts/patches/scrollfix/index.ts", "src/templates/assets/javascripts/patches/scrolllock/index.ts", "src/templates/assets/javascripts/polyfills/index.ts"], + "sourcesContent": ["(function (global, factory) {\n typeof exports === 'object' && typeof module !== 'undefined' ? factory() :\n typeof define === 'function' && define.amd ? define(factory) :\n (factory());\n}(this, (function () { 'use strict';\n\n /**\n * Applies the :focus-visible polyfill at the given scope.\n * A scope in this case is either the top-level Document or a Shadow Root.\n *\n * @param {(Document|ShadowRoot)} scope\n * @see https://github.com/WICG/focus-visible\n */\n function applyFocusVisiblePolyfill(scope) {\n var hadKeyboardEvent = true;\n var hadFocusVisibleRecently = false;\n var hadFocusVisibleRecentlyTimeout = null;\n\n var inputTypesAllowlist = {\n text: true,\n search: true,\n url: true,\n tel: true,\n email: true,\n password: true,\n number: true,\n date: true,\n month: true,\n week: true,\n time: true,\n datetime: true,\n 'datetime-local': true\n };\n\n /**\n * Helper function for legacy browsers and iframes which sometimes focus\n * elements like document, body, and non-interactive SVG.\n * @param {Element} el\n */\n function isValidFocusTarget(el) {\n if (\n el &&\n el !== document &&\n el.nodeName !== 'HTML' &&\n el.nodeName !== 'BODY' &&\n 'classList' in el &&\n 'contains' in el.classList\n ) {\n return true;\n }\n return false;\n }\n\n /**\n * Computes whether the given element should automatically trigger the\n * `focus-visible` class being added, i.e. whether it should always match\n * `:focus-visible` when focused.\n * @param {Element} el\n * @return {boolean}\n */\n function focusTriggersKeyboardModality(el) {\n var type = el.type;\n var tagName = el.tagName;\n\n if (tagName === 'INPUT' && inputTypesAllowlist[type] && !el.readOnly) {\n return true;\n }\n\n if (tagName === 'TEXTAREA' && !el.readOnly) {\n return true;\n }\n\n if (el.isContentEditable) {\n return true;\n }\n\n return false;\n }\n\n /**\n * Add the `focus-visible` class to the given element if it was not added by\n * the author.\n * @param {Element} el\n */\n function addFocusVisibleClass(el) {\n if (el.classList.contains('focus-visible')) {\n return;\n }\n el.classList.add('focus-visible');\n el.setAttribute('data-focus-visible-added', '');\n }\n\n /**\n * Remove the `focus-visible` class from the given element if it was not\n * originally added by the author.\n * @param {Element} el\n */\n function removeFocusVisibleClass(el) {\n if (!el.hasAttribute('data-focus-visible-added')) {\n return;\n }\n el.classList.remove('focus-visible');\n el.removeAttribute('data-focus-visible-added');\n }\n\n /**\n * If the most recent user interaction was via the keyboard;\n * and the key press did not include a meta, alt/option, or control key;\n * then the modality is keyboard. Otherwise, the modality is not keyboard.\n * Apply `focus-visible` to any current active element and keep track\n * of our keyboard modality state with `hadKeyboardEvent`.\n * @param {KeyboardEvent} e\n */\n function onKeyDown(e) {\n if (e.metaKey || e.altKey || e.ctrlKey) {\n return;\n }\n\n if (isValidFocusTarget(scope.activeElement)) {\n addFocusVisibleClass(scope.activeElement);\n }\n\n hadKeyboardEvent = true;\n }\n\n /**\n * If at any point a user clicks with a pointing device, ensure that we change\n * the modality away from keyboard.\n * This avoids the situation where a user presses a key on an already focused\n * element, and then clicks on a different element, focusing it with a\n * pointing device, while we still think we're in keyboard modality.\n * @param {Event} e\n */\n function onPointerDown(e) {\n hadKeyboardEvent = false;\n }\n\n /**\n * On `focus`, add the `focus-visible` class to the target if:\n * - the target received focus as a result of keyboard navigation, or\n * - the event target is an element that will likely require interaction\n * via the keyboard (e.g. a text box)\n * @param {Event} e\n */\n function onFocus(e) {\n // Prevent IE from focusing the document or HTML element.\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (hadKeyboardEvent || focusTriggersKeyboardModality(e.target)) {\n addFocusVisibleClass(e.target);\n }\n }\n\n /**\n * On `blur`, remove the `focus-visible` class from the target.\n * @param {Event} e\n */\n function onBlur(e) {\n if (!isValidFocusTarget(e.target)) {\n return;\n }\n\n if (\n e.target.classList.contains('focus-visible') ||\n e.target.hasAttribute('data-focus-visible-added')\n ) {\n // To detect a tab/window switch, we look for a blur event followed\n // rapidly by a visibility change.\n // If we don't see a visibility change within 100ms, it's probably a\n // regular focus change.\n hadFocusVisibleRecently = true;\n window.clearTimeout(hadFocusVisibleRecentlyTimeout);\n hadFocusVisibleRecentlyTimeout = window.setTimeout(function() {\n hadFocusVisibleRecently = false;\n }, 100);\n removeFocusVisibleClass(e.target);\n }\n }\n\n /**\n * If the user changes tabs, keep track of whether or not the previously\n * focused element had .focus-visible.\n * @param {Event} e\n */\n function onVisibilityChange(e) {\n if (document.visibilityState === 'hidden') {\n // If the tab becomes active again, the browser will handle calling focus\n // on the element (Safari actually calls it twice).\n // If this tab change caused a blur on an element with focus-visible,\n // re-apply the class when the user switches back to the tab.\n if (hadFocusVisibleRecently) {\n hadKeyboardEvent = true;\n }\n addInitialPointerMoveListeners();\n }\n }\n\n /**\n * Add a group of listeners to detect usage of any pointing devices.\n * These listeners will be added when the polyfill first loads, and anytime\n * the window is blurred, so that they are active when the window regains\n * focus.\n */\n function addInitialPointerMoveListeners() {\n document.addEventListener('mousemove', onInitialPointerMove);\n document.addEventListener('mousedown', onInitialPointerMove);\n document.addEventListener('mouseup', onInitialPointerMove);\n document.addEventListener('pointermove', onInitialPointerMove);\n document.addEventListener('pointerdown', onInitialPointerMove);\n document.addEventListener('pointerup', onInitialPointerMove);\n document.addEventListener('touchmove', onInitialPointerMove);\n document.addEventListener('touchstart', onInitialPointerMove);\n document.addEventListener('touchend', onInitialPointerMove);\n }\n\n function removeInitialPointerMoveListeners() {\n document.removeEventListener('mousemove', onInitialPointerMove);\n document.removeEventListener('mousedown', onInitialPointerMove);\n document.removeEventListener('mouseup', onInitialPointerMove);\n document.removeEventListener('pointermove', onInitialPointerMove);\n document.removeEventListener('pointerdown', onInitialPointerMove);\n document.removeEventListener('pointerup', onInitialPointerMove);\n document.removeEventListener('touchmove', onInitialPointerMove);\n document.removeEventListener('touchstart', onInitialPointerMove);\n document.removeEventListener('touchend', onInitialPointerMove);\n }\n\n /**\n * When the polfyill first loads, assume the user is in keyboard modality.\n * If any event is received from a pointing device (e.g. mouse, pointer,\n * touch), turn off keyboard modality.\n * This accounts for situations where focus enters the page from the URL bar.\n * @param {Event} e\n */\n function onInitialPointerMove(e) {\n // Work around a Safari quirk that fires a mousemove on whenever the\n // window blurs, even if you're tabbing out of the page. \u00AF\\_(\u30C4)_/\u00AF\n if (e.target.nodeName && e.target.nodeName.toLowerCase() === 'html') {\n return;\n }\n\n hadKeyboardEvent = false;\n removeInitialPointerMoveListeners();\n }\n\n // For some kinds of state, we are interested in changes at the global scope\n // only. For example, global pointer input, global key presses and global\n // visibility change should affect the state at every scope:\n document.addEventListener('keydown', onKeyDown, true);\n document.addEventListener('mousedown', onPointerDown, true);\n document.addEventListener('pointerdown', onPointerDown, true);\n document.addEventListener('touchstart', onPointerDown, true);\n document.addEventListener('visibilitychange', onVisibilityChange, true);\n\n addInitialPointerMoveListeners();\n\n // For focus and blur, we specifically care about state changes in the local\n // scope. This is because focus / blur events that originate from within a\n // shadow root are not re-dispatched from the host element if it was already\n // the active element in its own scope:\n scope.addEventListener('focus', onFocus, true);\n scope.addEventListener('blur', onBlur, true);\n\n // We detect that a node is a ShadowRoot by ensuring that it is a\n // DocumentFragment and also has a host property. This check covers native\n // implementation and polyfill implementation transparently. If we only cared\n // about the native implementation, we could just check if the scope was\n // an instance of a ShadowRoot.\n if (scope.nodeType === Node.DOCUMENT_FRAGMENT_NODE && scope.host) {\n // Since a ShadowRoot is a special kind of DocumentFragment, it does not\n // have a root element to add a class to. So, we add this attribute to the\n // host element instead:\n scope.host.setAttribute('data-js-focus-visible', '');\n } else if (scope.nodeType === Node.DOCUMENT_NODE) {\n document.documentElement.classList.add('js-focus-visible');\n document.documentElement.setAttribute('data-js-focus-visible', '');\n }\n }\n\n // It is important to wrap all references to global window and document in\n // these checks to support server-side rendering use cases\n // @see https://github.com/WICG/focus-visible/issues/199\n if (typeof window !== 'undefined' && typeof document !== 'undefined') {\n // Make the polyfill helper globally available. This can be used as a signal\n // to interested libraries that wish to coordinate with the polyfill for e.g.,\n // applying the polyfill to a shadow root:\n window.applyFocusVisiblePolyfill = applyFocusVisiblePolyfill;\n\n // Notify interested libraries of the polyfill's presence, in case the\n // polyfill was loaded lazily:\n var event;\n\n try {\n event = new CustomEvent('focus-visible-polyfill-ready');\n } catch (error) {\n // IE11 does not support using CustomEvent as a constructor directly:\n event = document.createEvent('CustomEvent');\n event.initCustomEvent('focus-visible-polyfill-ready', false, false, {});\n }\n\n window.dispatchEvent(event);\n }\n\n if (typeof document !== 'undefined') {\n // Apply the polyfill to the global document, so that no JavaScript\n // coordination is required to use the polyfill in the top-level document:\n applyFocusVisiblePolyfill(document);\n }\n\n})));\n", "/*!\n * clipboard.js v2.0.11\n * https://clipboardjs.com/\n *\n * Licensed MIT \u00A9 Zeno Rocha\n */\n(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ClipboardJS\"] = factory();\n\telse\n\t\troot[\"ClipboardJS\"] = factory();\n})(this, function() {\nreturn /******/ (function() { // webpackBootstrap\n/******/ \tvar __webpack_modules__ = ({\n\n/***/ 686:\n/***/ (function(__unused_webpack_module, __webpack_exports__, __webpack_require__) {\n\n\"use strict\";\n\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n \"default\": function() { return /* binding */ clipboard; }\n});\n\n// EXTERNAL MODULE: ./node_modules/tiny-emitter/index.js\nvar tiny_emitter = __webpack_require__(279);\nvar tiny_emitter_default = /*#__PURE__*/__webpack_require__.n(tiny_emitter);\n// EXTERNAL MODULE: ./node_modules/good-listener/src/listen.js\nvar listen = __webpack_require__(370);\nvar listen_default = /*#__PURE__*/__webpack_require__.n(listen);\n// EXTERNAL MODULE: ./node_modules/select/src/select.js\nvar src_select = __webpack_require__(817);\nvar select_default = /*#__PURE__*/__webpack_require__.n(src_select);\n;// CONCATENATED MODULE: ./src/common/command.js\n/**\n * Executes a given operation type.\n * @param {String} type\n * @return {Boolean}\n */\nfunction command(type) {\n try {\n return document.execCommand(type);\n } catch (err) {\n return false;\n }\n}\n;// CONCATENATED MODULE: ./src/actions/cut.js\n\n\n/**\n * Cut action wrapper.\n * @param {String|HTMLElement} target\n * @return {String}\n */\n\nvar ClipboardActionCut = function ClipboardActionCut(target) {\n var selectedText = select_default()(target);\n command('cut');\n return selectedText;\n};\n\n/* harmony default export */ var actions_cut = (ClipboardActionCut);\n;// CONCATENATED MODULE: ./src/common/create-fake-element.js\n/**\n * Creates a fake textarea element with a value.\n * @param {String} value\n * @return {HTMLElement}\n */\nfunction createFakeElement(value) {\n var isRTL = document.documentElement.getAttribute('dir') === 'rtl';\n var fakeElement = document.createElement('textarea'); // Prevent zooming on iOS\n\n fakeElement.style.fontSize = '12pt'; // Reset box model\n\n fakeElement.style.border = '0';\n fakeElement.style.padding = '0';\n fakeElement.style.margin = '0'; // Move element out of screen horizontally\n\n fakeElement.style.position = 'absolute';\n fakeElement.style[isRTL ? 'right' : 'left'] = '-9999px'; // Move element to the same position vertically\n\n var yPosition = window.pageYOffset || document.documentElement.scrollTop;\n fakeElement.style.top = \"\".concat(yPosition, \"px\");\n fakeElement.setAttribute('readonly', '');\n fakeElement.value = value;\n return fakeElement;\n}\n;// CONCATENATED MODULE: ./src/actions/copy.js\n\n\n\n/**\n * Create fake copy action wrapper using a fake element.\n * @param {String} target\n * @param {Object} options\n * @return {String}\n */\n\nvar fakeCopyAction = function fakeCopyAction(value, options) {\n var fakeElement = createFakeElement(value);\n options.container.appendChild(fakeElement);\n var selectedText = select_default()(fakeElement);\n command('copy');\n fakeElement.remove();\n return selectedText;\n};\n/**\n * Copy action wrapper.\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @return {String}\n */\n\n\nvar ClipboardActionCopy = function ClipboardActionCopy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n var selectedText = '';\n\n if (typeof target === 'string') {\n selectedText = fakeCopyAction(target, options);\n } else if (target instanceof HTMLInputElement && !['text', 'search', 'url', 'tel', 'password'].includes(target === null || target === void 0 ? void 0 : target.type)) {\n // If input type doesn't support `setSelectionRange`. Simulate it. https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setSelectionRange\n selectedText = fakeCopyAction(target.value, options);\n } else {\n selectedText = select_default()(target);\n command('copy');\n }\n\n return selectedText;\n};\n\n/* harmony default export */ var actions_copy = (ClipboardActionCopy);\n;// CONCATENATED MODULE: ./src/actions/default.js\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return _typeof(obj); }\n\n\n\n/**\n * Inner function which performs selection from either `text` or `target`\n * properties and then executes copy or cut operations.\n * @param {Object} options\n */\n\nvar ClipboardActionDefault = function ClipboardActionDefault() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n // Defines base properties passed from constructor.\n var _options$action = options.action,\n action = _options$action === void 0 ? 'copy' : _options$action,\n container = options.container,\n target = options.target,\n text = options.text; // Sets the `action` to be performed which can be either 'copy' or 'cut'.\n\n if (action !== 'copy' && action !== 'cut') {\n throw new Error('Invalid \"action\" value, use either \"copy\" or \"cut\"');\n } // Sets the `target` property using an element that will be have its content copied.\n\n\n if (target !== undefined) {\n if (target && _typeof(target) === 'object' && target.nodeType === 1) {\n if (action === 'copy' && target.hasAttribute('disabled')) {\n throw new Error('Invalid \"target\" attribute. Please use \"readonly\" instead of \"disabled\" attribute');\n }\n\n if (action === 'cut' && (target.hasAttribute('readonly') || target.hasAttribute('disabled'))) {\n throw new Error('Invalid \"target\" attribute. You can\\'t cut text from elements with \"readonly\" or \"disabled\" attributes');\n }\n } else {\n throw new Error('Invalid \"target\" value, use a valid Element');\n }\n } // Define selection strategy based on `text` property.\n\n\n if (text) {\n return actions_copy(text, {\n container: container\n });\n } // Defines which selection strategy based on `target` property.\n\n\n if (target) {\n return action === 'cut' ? actions_cut(target) : actions_copy(target, {\n container: container\n });\n }\n};\n\n/* harmony default export */ var actions_default = (ClipboardActionDefault);\n;// CONCATENATED MODULE: ./src/clipboard.js\nfunction clipboard_typeof(obj) { \"@babel/helpers - typeof\"; if (typeof Symbol === \"function\" && typeof Symbol.iterator === \"symbol\") { clipboard_typeof = function _typeof(obj) { return typeof obj; }; } else { clipboard_typeof = function _typeof(obj) { return obj && typeof Symbol === \"function\" && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }; } return clipboard_typeof(obj); }\n\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\n\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\n\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }\n\nfunction _inherits(subClass, superClass) { if (typeof superClass !== \"function\" && superClass !== null) { throw new TypeError(\"Super expression must either be null or a function\"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }\n\nfunction _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }\n\nfunction _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }\n\nfunction _possibleConstructorReturn(self, call) { if (call && (clipboard_typeof(call) === \"object\" || typeof call === \"function\")) { return call; } return _assertThisInitialized(self); }\n\nfunction _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError(\"this hasn't been initialised - super() hasn't been called\"); } return self; }\n\nfunction _isNativeReflectConstruct() { if (typeof Reflect === \"undefined\" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === \"function\") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } }\n\nfunction _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }\n\n\n\n\n\n\n/**\n * Helper function to retrieve attribute value.\n * @param {String} suffix\n * @param {Element} element\n */\n\nfunction getAttributeValue(suffix, element) {\n var attribute = \"data-clipboard-\".concat(suffix);\n\n if (!element.hasAttribute(attribute)) {\n return;\n }\n\n return element.getAttribute(attribute);\n}\n/**\n * Base class which takes one or more elements, adds event listeners to them,\n * and instantiates a new `ClipboardAction` on each click.\n */\n\n\nvar Clipboard = /*#__PURE__*/function (_Emitter) {\n _inherits(Clipboard, _Emitter);\n\n var _super = _createSuper(Clipboard);\n\n /**\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n * @param {Object} options\n */\n function Clipboard(trigger, options) {\n var _this;\n\n _classCallCheck(this, Clipboard);\n\n _this = _super.call(this);\n\n _this.resolveOptions(options);\n\n _this.listenClick(trigger);\n\n return _this;\n }\n /**\n * Defines if attributes would be resolved using internal setter functions\n * or custom functions that were passed in the constructor.\n * @param {Object} options\n */\n\n\n _createClass(Clipboard, [{\n key: \"resolveOptions\",\n value: function resolveOptions() {\n var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};\n this.action = typeof options.action === 'function' ? options.action : this.defaultAction;\n this.target = typeof options.target === 'function' ? options.target : this.defaultTarget;\n this.text = typeof options.text === 'function' ? options.text : this.defaultText;\n this.container = clipboard_typeof(options.container) === 'object' ? options.container : document.body;\n }\n /**\n * Adds a click event listener to the passed trigger.\n * @param {String|HTMLElement|HTMLCollection|NodeList} trigger\n */\n\n }, {\n key: \"listenClick\",\n value: function listenClick(trigger) {\n var _this2 = this;\n\n this.listener = listen_default()(trigger, 'click', function (e) {\n return _this2.onClick(e);\n });\n }\n /**\n * Defines a new `ClipboardAction` on each click event.\n * @param {Event} e\n */\n\n }, {\n key: \"onClick\",\n value: function onClick(e) {\n var trigger = e.delegateTarget || e.currentTarget;\n var action = this.action(trigger) || 'copy';\n var text = actions_default({\n action: action,\n container: this.container,\n target: this.target(trigger),\n text: this.text(trigger)\n }); // Fires an event based on the copy operation result.\n\n this.emit(text ? 'success' : 'error', {\n action: action,\n text: text,\n trigger: trigger,\n clearSelection: function clearSelection() {\n if (trigger) {\n trigger.focus();\n }\n\n window.getSelection().removeAllRanges();\n }\n });\n }\n /**\n * Default `action` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultAction\",\n value: function defaultAction(trigger) {\n return getAttributeValue('action', trigger);\n }\n /**\n * Default `target` lookup function.\n * @param {Element} trigger\n */\n\n }, {\n key: \"defaultTarget\",\n value: function defaultTarget(trigger) {\n var selector = getAttributeValue('target', trigger);\n\n if (selector) {\n return document.querySelector(selector);\n }\n }\n /**\n * Allow fire programmatically a copy action\n * @param {String|HTMLElement} target\n * @param {Object} options\n * @returns Text copied.\n */\n\n }, {\n key: \"defaultText\",\n\n /**\n * Default `text` lookup function.\n * @param {Element} trigger\n */\n value: function defaultText(trigger) {\n return getAttributeValue('text', trigger);\n }\n /**\n * Destroy lifecycle.\n */\n\n }, {\n key: \"destroy\",\n value: function destroy() {\n this.listener.destroy();\n }\n }], [{\n key: \"copy\",\n value: function copy(target) {\n var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {\n container: document.body\n };\n return actions_copy(target, options);\n }\n /**\n * Allow fire programmatically a cut action\n * @param {String|HTMLElement} target\n * @returns Text cutted.\n */\n\n }, {\n key: \"cut\",\n value: function cut(target) {\n return actions_cut(target);\n }\n /**\n * Returns the support of the given action, or all actions if no action is\n * given.\n * @param {String} [action]\n */\n\n }, {\n key: \"isSupported\",\n value: function isSupported() {\n var action = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : ['copy', 'cut'];\n var actions = typeof action === 'string' ? [action] : action;\n var support = !!document.queryCommandSupported;\n actions.forEach(function (action) {\n support = support && !!document.queryCommandSupported(action);\n });\n return support;\n }\n }]);\n\n return Clipboard;\n}((tiny_emitter_default()));\n\n/* harmony default export */ var clipboard = (Clipboard);\n\n/***/ }),\n\n/***/ 828:\n/***/ (function(module) {\n\nvar DOCUMENT_NODE_TYPE = 9;\n\n/**\n * A polyfill for Element.matches()\n */\nif (typeof Element !== 'undefined' && !Element.prototype.matches) {\n var proto = Element.prototype;\n\n proto.matches = proto.matchesSelector ||\n proto.mozMatchesSelector ||\n proto.msMatchesSelector ||\n proto.oMatchesSelector ||\n proto.webkitMatchesSelector;\n}\n\n/**\n * Finds the closest parent that matches a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @return {Function}\n */\nfunction closest (element, selector) {\n while (element && element.nodeType !== DOCUMENT_NODE_TYPE) {\n if (typeof element.matches === 'function' &&\n element.matches(selector)) {\n return element;\n }\n element = element.parentNode;\n }\n}\n\nmodule.exports = closest;\n\n\n/***/ }),\n\n/***/ 438:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar closest = __webpack_require__(828);\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction _delegate(element, selector, type, callback, useCapture) {\n var listenerFn = listener.apply(this, arguments);\n\n element.addEventListener(type, listenerFn, useCapture);\n\n return {\n destroy: function() {\n element.removeEventListener(type, listenerFn, useCapture);\n }\n }\n}\n\n/**\n * Delegates event to a selector.\n *\n * @param {Element|String|Array} [elements]\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @param {Boolean} useCapture\n * @return {Object}\n */\nfunction delegate(elements, selector, type, callback, useCapture) {\n // Handle the regular Element usage\n if (typeof elements.addEventListener === 'function') {\n return _delegate.apply(null, arguments);\n }\n\n // Handle Element-less usage, it defaults to global delegation\n if (typeof type === 'function') {\n // Use `document` as the first parameter, then apply arguments\n // This is a short way to .unshift `arguments` without running into deoptimizations\n return _delegate.bind(null, document).apply(null, arguments);\n }\n\n // Handle Selector-based usage\n if (typeof elements === 'string') {\n elements = document.querySelectorAll(elements);\n }\n\n // Handle Array-like based usage\n return Array.prototype.map.call(elements, function (element) {\n return _delegate(element, selector, type, callback, useCapture);\n });\n}\n\n/**\n * Finds closest match and invokes callback.\n *\n * @param {Element} element\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Function}\n */\nfunction listener(element, selector, type, callback) {\n return function(e) {\n e.delegateTarget = closest(e.target, selector);\n\n if (e.delegateTarget) {\n callback.call(element, e);\n }\n }\n}\n\nmodule.exports = delegate;\n\n\n/***/ }),\n\n/***/ 879:\n/***/ (function(__unused_webpack_module, exports) {\n\n/**\n * Check if argument is a HTML element.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.node = function(value) {\n return value !== undefined\n && value instanceof HTMLElement\n && value.nodeType === 1;\n};\n\n/**\n * Check if argument is a list of HTML elements.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.nodeList = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return value !== undefined\n && (type === '[object NodeList]' || type === '[object HTMLCollection]')\n && ('length' in value)\n && (value.length === 0 || exports.node(value[0]));\n};\n\n/**\n * Check if argument is a string.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.string = function(value) {\n return typeof value === 'string'\n || value instanceof String;\n};\n\n/**\n * Check if argument is a function.\n *\n * @param {Object} value\n * @return {Boolean}\n */\nexports.fn = function(value) {\n var type = Object.prototype.toString.call(value);\n\n return type === '[object Function]';\n};\n\n\n/***/ }),\n\n/***/ 370:\n/***/ (function(module, __unused_webpack_exports, __webpack_require__) {\n\nvar is = __webpack_require__(879);\nvar delegate = __webpack_require__(438);\n\n/**\n * Validates all params and calls the right\n * listener function based on its target type.\n *\n * @param {String|HTMLElement|HTMLCollection|NodeList} target\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listen(target, type, callback) {\n if (!target && !type && !callback) {\n throw new Error('Missing required arguments');\n }\n\n if (!is.string(type)) {\n throw new TypeError('Second argument must be a String');\n }\n\n if (!is.fn(callback)) {\n throw new TypeError('Third argument must be a Function');\n }\n\n if (is.node(target)) {\n return listenNode(target, type, callback);\n }\n else if (is.nodeList(target)) {\n return listenNodeList(target, type, callback);\n }\n else if (is.string(target)) {\n return listenSelector(target, type, callback);\n }\n else {\n throw new TypeError('First argument must be a String, HTMLElement, HTMLCollection, or NodeList');\n }\n}\n\n/**\n * Adds an event listener to a HTML element\n * and returns a remove listener function.\n *\n * @param {HTMLElement} node\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNode(node, type, callback) {\n node.addEventListener(type, callback);\n\n return {\n destroy: function() {\n node.removeEventListener(type, callback);\n }\n }\n}\n\n/**\n * Add an event listener to a list of HTML elements\n * and returns a remove listener function.\n *\n * @param {NodeList|HTMLCollection} nodeList\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenNodeList(nodeList, type, callback) {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.addEventListener(type, callback);\n });\n\n return {\n destroy: function() {\n Array.prototype.forEach.call(nodeList, function(node) {\n node.removeEventListener(type, callback);\n });\n }\n }\n}\n\n/**\n * Add an event listener to a selector\n * and returns a remove listener function.\n *\n * @param {String} selector\n * @param {String} type\n * @param {Function} callback\n * @return {Object}\n */\nfunction listenSelector(selector, type, callback) {\n return delegate(document.body, selector, type, callback);\n}\n\nmodule.exports = listen;\n\n\n/***/ }),\n\n/***/ 817:\n/***/ (function(module) {\n\nfunction select(element) {\n var selectedText;\n\n if (element.nodeName === 'SELECT') {\n element.focus();\n\n selectedText = element.value;\n }\n else if (element.nodeName === 'INPUT' || element.nodeName === 'TEXTAREA') {\n var isReadOnly = element.hasAttribute('readonly');\n\n if (!isReadOnly) {\n element.setAttribute('readonly', '');\n }\n\n element.select();\n element.setSelectionRange(0, element.value.length);\n\n if (!isReadOnly) {\n element.removeAttribute('readonly');\n }\n\n selectedText = element.value;\n }\n else {\n if (element.hasAttribute('contenteditable')) {\n element.focus();\n }\n\n var selection = window.getSelection();\n var range = document.createRange();\n\n range.selectNodeContents(element);\n selection.removeAllRanges();\n selection.addRange(range);\n\n selectedText = selection.toString();\n }\n\n return selectedText;\n}\n\nmodule.exports = select;\n\n\n/***/ }),\n\n/***/ 279:\n/***/ (function(module) {\n\nfunction E () {\n // Keep this empty so it's easier to inherit from\n // (via https://github.com/lipsmack from https://github.com/scottcorgan/tiny-emitter/issues/3)\n}\n\nE.prototype = {\n on: function (name, callback, ctx) {\n var e = this.e || (this.e = {});\n\n (e[name] || (e[name] = [])).push({\n fn: callback,\n ctx: ctx\n });\n\n return this;\n },\n\n once: function (name, callback, ctx) {\n var self = this;\n function listener () {\n self.off(name, listener);\n callback.apply(ctx, arguments);\n };\n\n listener._ = callback\n return this.on(name, listener, ctx);\n },\n\n emit: function (name) {\n var data = [].slice.call(arguments, 1);\n var evtArr = ((this.e || (this.e = {}))[name] || []).slice();\n var i = 0;\n var len = evtArr.length;\n\n for (i; i < len; i++) {\n evtArr[i].fn.apply(evtArr[i].ctx, data);\n }\n\n return this;\n },\n\n off: function (name, callback) {\n var e = this.e || (this.e = {});\n var evts = e[name];\n var liveEvents = [];\n\n if (evts && callback) {\n for (var i = 0, len = evts.length; i < len; i++) {\n if (evts[i].fn !== callback && evts[i].fn._ !== callback)\n liveEvents.push(evts[i]);\n }\n }\n\n // Remove event from queue to prevent memory leak\n // Suggested by https://github.com/lazd\n // Ref: https://github.com/scottcorgan/tiny-emitter/commit/c6ebfaa9bc973b33d110a84a307742b7cf94c953#commitcomment-5024910\n\n (liveEvents.length)\n ? e[name] = liveEvents\n : delete e[name];\n\n return this;\n }\n};\n\nmodule.exports = E;\nmodule.exports.TinyEmitter = E;\n\n\n/***/ })\n\n/******/ \t});\n/************************************************************************/\n/******/ \t// The module cache\n/******/ \tvar __webpack_module_cache__ = {};\n/******/ \t\n/******/ \t// The require function\n/******/ \tfunction __webpack_require__(moduleId) {\n/******/ \t\t// Check if module is in cache\n/******/ \t\tif(__webpack_module_cache__[moduleId]) {\n/******/ \t\t\treturn __webpack_module_cache__[moduleId].exports;\n/******/ \t\t}\n/******/ \t\t// Create a new module (and put it into the cache)\n/******/ \t\tvar module = __webpack_module_cache__[moduleId] = {\n/******/ \t\t\t// no module.id needed\n/******/ \t\t\t// no module.loaded needed\n/******/ \t\t\texports: {}\n/******/ \t\t};\n/******/ \t\n/******/ \t\t// Execute the module function\n/******/ \t\t__webpack_modules__[moduleId](module, module.exports, __webpack_require__);\n/******/ \t\n/******/ \t\t// Return the exports of the module\n/******/ \t\treturn module.exports;\n/******/ \t}\n/******/ \t\n/************************************************************************/\n/******/ \t/* webpack/runtime/compat get default export */\n/******/ \t!function() {\n/******/ \t\t// getDefaultExport function for compatibility with non-harmony modules\n/******/ \t\t__webpack_require__.n = function(module) {\n/******/ \t\t\tvar getter = module && module.__esModule ?\n/******/ \t\t\t\tfunction() { return module['default']; } :\n/******/ \t\t\t\tfunction() { return module; };\n/******/ \t\t\t__webpack_require__.d(getter, { a: getter });\n/******/ \t\t\treturn getter;\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/define property getters */\n/******/ \t!function() {\n/******/ \t\t// define getter functions for harmony exports\n/******/ \t\t__webpack_require__.d = function(exports, definition) {\n/******/ \t\t\tfor(var key in definition) {\n/******/ \t\t\t\tif(__webpack_require__.o(definition, key) && !__webpack_require__.o(exports, key)) {\n/******/ \t\t\t\t\tObject.defineProperty(exports, key, { enumerable: true, get: definition[key] });\n/******/ \t\t\t\t}\n/******/ \t\t\t}\n/******/ \t\t};\n/******/ \t}();\n/******/ \t\n/******/ \t/* webpack/runtime/hasOwnProperty shorthand */\n/******/ \t!function() {\n/******/ \t\t__webpack_require__.o = function(obj, prop) { return Object.prototype.hasOwnProperty.call(obj, prop); }\n/******/ \t}();\n/******/ \t\n/************************************************************************/\n/******/ \t// module exports must be returned from runtime so entry inlining is disabled\n/******/ \t// startup\n/******/ \t// Load entry module and return exports\n/******/ \treturn __webpack_require__(686);\n/******/ })()\n.default;\n});", "/*!\n * escape-html\n * Copyright(c) 2012-2013 TJ Holowaychuk\n * Copyright(c) 2015 Andreas Lubbe\n * Copyright(c) 2015 Tiancheng \"Timothy\" Gu\n * MIT Licensed\n */\n\n'use strict';\n\n/**\n * Module variables.\n * @private\n */\n\nvar matchHtmlRegExp = /[\"'&<>]/;\n\n/**\n * Module exports.\n * @public\n */\n\nmodule.exports = escapeHtml;\n\n/**\n * Escape special characters in the given string of html.\n *\n * @param {string} string The string to escape for inserting into HTML\n * @return {string}\n * @public\n */\n\nfunction escapeHtml(string) {\n var str = '' + string;\n var match = matchHtmlRegExp.exec(str);\n\n if (!match) {\n return str;\n }\n\n var escape;\n var html = '';\n var index = 0;\n var lastIndex = 0;\n\n for (index = match.index; index < str.length; index++) {\n switch (str.charCodeAt(index)) {\n case 34: // \"\n escape = '"';\n break;\n case 38: // &\n escape = '&';\n break;\n case 39: // '\n escape = ''';\n break;\n case 60: // <\n escape = '<';\n break;\n case 62: // >\n escape = '>';\n break;\n default:\n continue;\n }\n\n if (lastIndex !== index) {\n html += str.substring(lastIndex, index);\n }\n\n lastIndex = index + 1;\n html += escape;\n }\n\n return lastIndex !== index\n ? html + str.substring(lastIndex, index)\n : html;\n}\n", "/*\n * Copyright (c) 2016-2023 Martin Donath \n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \"Software\"), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\nimport \"focus-visible\"\n\nimport {\n EMPTY,\n NEVER,\n Observable,\n Subject,\n defer,\n delay,\n filter,\n map,\n merge,\n mergeWith,\n shareReplay,\n switchMap\n} from \"rxjs\"\n\nimport { configuration, feature } from \"./_\"\nimport {\n at,\n getActiveElement,\n getOptionalElement,\n requestJSON,\n setLocation,\n setToggle,\n watchDocument,\n watchKeyboard,\n watchLocation,\n watchLocationTarget,\n watchMedia,\n watchPrint,\n watchScript,\n watchViewport\n} from \"./browser\"\nimport {\n getComponentElement,\n getComponentElements,\n mountAnnounce,\n mountBackToTop,\n mountConsent,\n mountContent,\n mountDialog,\n mountHeader,\n mountHeaderTitle,\n mountPalette,\n mountProgress,\n mountSearch,\n mountSearchHiglight,\n mountSidebar,\n mountSource,\n mountTableOfContents,\n mountTabs,\n watchHeader,\n watchMain\n} from \"./components\"\nimport {\n SearchIndex,\n setupClipboardJS,\n setupInstantNavigation,\n setupVersionSelector\n} from \"./integrations\"\nimport {\n patchEllipsis,\n patchIndeterminate,\n patchScrollfix,\n patchScrolllock\n} from \"./patches\"\nimport \"./polyfills\"\n\n/* ----------------------------------------------------------------------------\n * Functions - @todo refactor\n * ------------------------------------------------------------------------- */\n\n/**\n * Fetch search index\n *\n * @returns Search index observable\n */\nfunction fetchSearchIndex(): Observable {\n if (location.protocol === \"file:\") {\n return watchScript(\n `${new URL(\"search/search_index.js\", config.base)}`\n )\n .pipe(\n // @ts-ignore - @todo fix typings\n map(() => __index),\n shareReplay(1)\n )\n } else {\n return requestJSON(\n new URL(\"search/search_index.json\", config.base)\n )\n }\n}\n\n/* ----------------------------------------------------------------------------\n * Application\n * ------------------------------------------------------------------------- */\n\n/* Yay, JavaScript is available */\ndocument.documentElement.classList.remove(\"no-js\")\ndocument.documentElement.classList.add(\"js\")\n\n/* Set up navigation observables and subjects */\nconst document$ = watchDocument()\nconst location$ = watchLocation()\nconst target$ = watchLocationTarget(location$)\nconst keyboard$ = watchKeyboard()\n\n/* Set up media observables */\nconst viewport$ = watchViewport()\nconst tablet$ = watchMedia(\"(min-width: 960px)\")\nconst screen$ = watchMedia(\"(min-width: 1220px)\")\nconst print$ = watchPrint()\n\n/* Retrieve search index, if search is enabled */\nconst config = configuration()\nconst index$ = document.forms.namedItem(\"search\")\n ? fetchSearchIndex()\n : NEVER\n\n/* Set up Clipboard.js integration */\nconst alert$ = new Subject()\nsetupClipboardJS({ alert$ })\n\n/* Set up progress indicator */\nconst progress$ = new Subject()\n\n/* Set up instant navigation, if enabled */\nif (feature(\"navigation.instant\"))\n setupInstantNavigation({ location$, viewport$, progress$ })\n .subscribe(document$)\n\n/* Set up version selector */\nif (config.version?.provider === \"mike\")\n setupVersionSelector({ document$ })\n\n/* Always close drawer and search on navigation */\nmerge(location$, target$)\n .pipe(\n delay(125)\n )\n .subscribe(() => {\n setToggle(\"drawer\", false)\n setToggle(\"search\", false)\n })\n\n/* Set up global keyboard handlers */\nkeyboard$\n .pipe(\n filter(({ mode }) => mode === \"global\")\n )\n .subscribe(key => {\n switch (key.type) {\n\n /* Go to previous page */\n case \"p\":\n case \",\":\n const prev = getOptionalElement(\"link[rel=prev]\")\n if (typeof prev !== \"undefined\")\n setLocation(prev)\n break\n\n /* Go to next page */\n case \"n\":\n case \".\":\n const next = getOptionalElement(\"link[rel=next]\")\n if (typeof next !== \"undefined\")\n setLocation(next)\n break\n\n /* Expand navigation, see https://bit.ly/3ZjG5io */\n case \"Enter\":\n const active = getActiveElement()\n if (active instanceof HTMLLabelElement)\n active.click()\n }\n })\n\n/* Set up patches */\npatchEllipsis({ document$ })\npatchIndeterminate({ document$, tablet$ })\npatchScrollfix({ document$ })\npatchScrolllock({ viewport$, tablet$ })\n\n/* Set up header and main area observable */\nconst header$ = watchHeader(getComponentElement(\"header\"), { viewport$ })\nconst main$ = document$\n .pipe(\n map(() => getComponentElement(\"main\")),\n switchMap(el => watchMain(el, { viewport$, header$ })),\n shareReplay(1)\n )\n\n/* Set up control component observables */\nconst control$ = merge(\n\n /* Consent */\n ...getComponentElements(\"consent\")\n .map(el => mountConsent(el, { target$ })),\n\n /* Dialog */\n ...getComponentElements(\"dialog\")\n .map(el => mountDialog(el, { alert$ })),\n\n /* Header */\n ...getComponentElements(\"header\")\n .map(el => mountHeader(el, { viewport$, header$, main$ })),\n\n /* Color palette */\n ...getComponentElements(\"palette\")\n .map(el => mountPalette(el)),\n\n /* Progress bar */\n ...getComponentElements(\"progress\")\n .map(el => mountProgress(el, { progress$ })),\n\n /* Search */\n ...getComponentElements(\"search\")\n .map(el => mountSearch(el, { index$, keyboard$ })),\n\n /* Repository information */\n ...getComponentElements(\"source\")\n .map(el => mountSource(el))\n)\n\n/* Set up content component observables */\nconst content$ = defer(() => merge(\n\n /* Announcement bar */\n ...getComponentElements(\"announce\")\n .map(el => mountAnnounce(el)),\n\n /* Content */\n ...getComponentElements(\"content\")\n .map(el => mountContent(el, { viewport$, target$, print$ })),\n\n /* Search highlighting */\n ...getComponentElements(\"content\")\n .map(el => feature(\"search.highlight\")\n ? mountSearchHiglight(el, { index$, location$ })\n : EMPTY\n ),\n\n /* Header title */\n ...getComponentElements(\"header-title\")\n .map(el => mountHeaderTitle(el, { viewport$, header$ })),\n\n /* Sidebar */\n ...getComponentElements(\"sidebar\")\n .map(el => el.getAttribute(\"data-md-type\") === \"navigation\"\n ? at(screen$, () => mountSidebar(el, { viewport$, header$, main$ }))\n : at(tablet$, () => mountSidebar(el, { viewport$, header$, main$ }))\n ),\n\n /* Navigation tabs */\n ...getComponentElements(\"tabs\")\n .map(el => mountTabs(el, { viewport$, header$ })),\n\n /* Table of contents */\n ...getComponentElements(\"toc\")\n .map(el => mountTableOfContents(el, {\n viewport$, header$, main$, target$\n })),\n\n /* Back-to-top button */\n ...getComponentElements(\"top\")\n .map(el => mountBackToTop(el, { viewport$, header$, main$, target$ }))\n))\n\n/* Set up component observables */\nconst component$ = document$\n .pipe(\n switchMap(() => content$),\n mergeWith(control$),\n shareReplay(1)\n )\n\n/* Subscribe to all components */\ncomponent$.subscribe()\n\n/* ----------------------------------------------------------------------------\n * Exports\n * ------------------------------------------------------------------------- */\n\nwindow.document$ = document$ /* Document observable */\nwindow.location$ = location$ /* Location subject */\nwindow.target$ = target$ /* Location target observable */\nwindow.keyboard$ = keyboard$ /* Keyboard observable */\nwindow.viewport$ = viewport$ /* Viewport observable */\nwindow.tablet$ = tablet$ /* Media tablet observable */\nwindow.screen$ = screen$ /* Media screen observable */\nwindow.print$ = print$ /* Media print observable */\nwindow.alert$ = alert$ /* Alert subject */\nwindow.progress$ = progress$ /* Progress indicator subject */\nwindow.component$ = component$ /* Component observable */\n", "/*! *****************************************************************************\r\nCopyright (c) Microsoft Corporation.\r\n\r\nPermission to use, copy, modify, and/or distribute this software for any\r\npurpose with or without fee is hereby granted.\r\n\r\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH\r\nREGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY\r\nAND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,\r\nINDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM\r\nLOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR\r\nOTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR\r\nPERFORMANCE OF THIS SOFTWARE.\r\n***************************************************************************** */\r\n/* global Reflect, Promise */\r\n\r\nvar extendStatics = function(d, b) {\r\n extendStatics = Object.setPrototypeOf ||\r\n ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||\r\n function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };\r\n return extendStatics(d, b);\r\n};\r\n\r\nexport function __extends(d, b) {\r\n if (typeof b !== \"function\" && b !== null)\r\n throw new TypeError(\"Class extends value \" + String(b) + \" is not a constructor or null\");\r\n extendStatics(d, b);\r\n function __() { this.constructor = d; }\r\n d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());\r\n}\r\n\r\nexport var __assign = function() {\r\n __assign = Object.assign || function __assign(t) {\r\n for (var s, i = 1, n = arguments.length; i < n; i++) {\r\n s = arguments[i];\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];\r\n }\r\n return t;\r\n }\r\n return __assign.apply(this, arguments);\r\n}\r\n\r\nexport function __rest(s, e) {\r\n var t = {};\r\n for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)\r\n t[p] = s[p];\r\n if (s != null && typeof Object.getOwnPropertySymbols === \"function\")\r\n for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {\r\n if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))\r\n t[p[i]] = s[p[i]];\r\n }\r\n return t;\r\n}\r\n\r\nexport function __decorate(decorators, target, key, desc) {\r\n var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;\r\n if (typeof Reflect === \"object\" && typeof Reflect.decorate === \"function\") r = Reflect.decorate(decorators, target, key, desc);\r\n else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;\r\n return c > 3 && r && Object.defineProperty(target, key, r), r;\r\n}\r\n\r\nexport function __param(paramIndex, decorator) {\r\n return function (target, key) { decorator(target, key, paramIndex); }\r\n}\r\n\r\nexport function __metadata(metadataKey, metadataValue) {\r\n if (typeof Reflect === \"object\" && typeof Reflect.metadata === \"function\") return Reflect.metadata(metadataKey, metadataValue);\r\n}\r\n\r\nexport function __awaiter(thisArg, _arguments, P, generator) {\r\n function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }\r\n return new (P || (P = Promise))(function (resolve, reject) {\r\n function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }\r\n function rejected(value) { try { step(generator[\"throw\"](value)); } catch (e) { reject(e); } }\r\n function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }\r\n step((generator = generator.apply(thisArg, _arguments || [])).next());\r\n });\r\n}\r\n\r\nexport function __generator(thisArg, body) {\r\n var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;\r\n return g = { next: verb(0), \"throw\": verb(1), \"return\": verb(2) }, typeof Symbol === \"function\" && (g[Symbol.iterator] = function() { return this; }), g;\r\n function verb(n) { return function (v) { return step([n, v]); }; }\r\n function step(op) {\r\n if (f) throw new TypeError(\"Generator is already executing.\");\r\n while (_) try {\r\n if (f = 1, y && (t = op[0] & 2 ? y[\"return\"] : op[0] ? y[\"throw\"] || ((t = y[\"return\"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;\r\n if (y = 0, t) op = [op[0] & 2, t.value];\r\n switch (op[0]) {\r\n case 0: case 1: t = op; break;\r\n case 4: _.label++; return { value: op[1], done: false };\r\n case 5: _.label++; y = op[1]; op = [0]; continue;\r\n case 7: op = _.ops.pop(); _.trys.pop(); continue;\r\n default:\r\n if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }\r\n if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }\r\n if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }\r\n if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }\r\n if (t[2]) _.ops.pop();\r\n _.trys.pop(); continue;\r\n }\r\n op = body.call(thisArg, _);\r\n } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }\r\n if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };\r\n }\r\n}\r\n\r\nexport var __createBinding = Object.create ? (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });\r\n}) : (function(o, m, k, k2) {\r\n if (k2 === undefined) k2 = k;\r\n o[k2] = m[k];\r\n});\r\n\r\nexport function __exportStar(m, o) {\r\n for (var p in m) if (p !== \"default\" && !Object.prototype.hasOwnProperty.call(o, p)) __createBinding(o, m, p);\r\n}\r\n\r\nexport function __values(o) {\r\n var s = typeof Symbol === \"function\" && Symbol.iterator, m = s && o[s], i = 0;\r\n if (m) return m.call(o);\r\n if (o && typeof o.length === \"number\") return {\r\n next: function () {\r\n if (o && i >= o.length) o = void 0;\r\n return { value: o && o[i++], done: !o };\r\n }\r\n };\r\n throw new TypeError(s ? \"Object is not iterable.\" : \"Symbol.iterator is not defined.\");\r\n}\r\n\r\nexport function __read(o, n) {\r\n var m = typeof Symbol === \"function\" && o[Symbol.iterator];\r\n if (!m) return o;\r\n var i = m.call(o), r, ar = [], e;\r\n try {\r\n while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);\r\n }\r\n catch (error) { e = { error: error }; }\r\n finally {\r\n try {\r\n if (r && !r.done && (m = i[\"return\"])) m.call(i);\r\n }\r\n finally { if (e) throw e.error; }\r\n }\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spread() {\r\n for (var ar = [], i = 0; i < arguments.length; i++)\r\n ar = ar.concat(__read(arguments[i]));\r\n return ar;\r\n}\r\n\r\n/** @deprecated */\r\nexport function __spreadArrays() {\r\n for (var s = 0, i = 0, il = arguments.length; i < il; i++) s += arguments[i].length;\r\n for (var r = Array(s), k = 0, i = 0; i < il; i++)\r\n for (var a = arguments[i], j = 0, jl = a.length; j < jl; j++, k++)\r\n r[k] = a[j];\r\n return r;\r\n}\r\n\r\nexport function __spreadArray(to, from, pack) {\r\n if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {\r\n if (ar || !(i in from)) {\r\n if (!ar) ar = Array.prototype.slice.call(from, 0, i);\r\n ar[i] = from[i];\r\n }\r\n }\r\n return to.concat(ar || Array.prototype.slice.call(from));\r\n}\r\n\r\nexport function __await(v) {\r\n return this instanceof __await ? (this.v = v, this) : new __await(v);\r\n}\r\n\r\nexport function __asyncGenerator(thisArg, _arguments, generator) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var g = generator.apply(thisArg, _arguments || []), i, q = [];\r\n return i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i;\r\n function verb(n) { if (g[n]) i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; }\r\n function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }\r\n function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }\r\n function fulfill(value) { resume(\"next\", value); }\r\n function reject(value) { resume(\"throw\", value); }\r\n function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }\r\n}\r\n\r\nexport function __asyncDelegator(o) {\r\n var i, p;\r\n return i = {}, verb(\"next\"), verb(\"throw\", function (e) { throw e; }), verb(\"return\"), i[Symbol.iterator] = function () { return this; }, i;\r\n function verb(n, f) { i[n] = o[n] ? function (v) { return (p = !p) ? { value: __await(o[n](v)), done: n === \"return\" } : f ? f(v) : v; } : f; }\r\n}\r\n\r\nexport function __asyncValues(o) {\r\n if (!Symbol.asyncIterator) throw new TypeError(\"Symbol.asyncIterator is not defined.\");\r\n var m = o[Symbol.asyncIterator], i;\r\n return m ? m.call(o) : (o = typeof __values === \"function\" ? __values(o) : o[Symbol.iterator](), i = {}, verb(\"next\"), verb(\"throw\"), verb(\"return\"), i[Symbol.asyncIterator] = function () { return this; }, i);\r\n function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }\r\n function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }\r\n}\r\n\r\nexport function __makeTemplateObject(cooked, raw) {\r\n if (Object.defineProperty) { Object.defineProperty(cooked, \"raw\", { value: raw }); } else { cooked.raw = raw; }\r\n return cooked;\r\n};\r\n\r\nvar __setModuleDefault = Object.create ? (function(o, v) {\r\n Object.defineProperty(o, \"default\", { enumerable: true, value: v });\r\n}) : function(o, v) {\r\n o[\"default\"] = v;\r\n};\r\n\r\nexport function __importStar(mod) {\r\n if (mod && mod.__esModule) return mod;\r\n var result = {};\r\n if (mod != null) for (var k in mod) if (k !== \"default\" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);\r\n __setModuleDefault(result, mod);\r\n return result;\r\n}\r\n\r\nexport function __importDefault(mod) {\r\n return (mod && mod.__esModule) ? mod : { default: mod };\r\n}\r\n\r\nexport function __classPrivateFieldGet(receiver, state, kind, f) {\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a getter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot read private member from an object whose class did not declare it\");\r\n return kind === \"m\" ? f : kind === \"a\" ? f.call(receiver) : f ? f.value : state.get(receiver);\r\n}\r\n\r\nexport function __classPrivateFieldSet(receiver, state, value, kind, f) {\r\n if (kind === \"m\") throw new TypeError(\"Private method is not writable\");\r\n if (kind === \"a\" && !f) throw new TypeError(\"Private accessor was defined without a setter\");\r\n if (typeof state === \"function\" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError(\"Cannot write private member to an object whose class did not declare it\");\r\n return (kind === \"a\" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;\r\n}\r\n", "/**\n * Returns true if the object is a function.\n * @param value The value to check\n */\nexport function isFunction(value: any): value is (...args: any[]) => any {\n return typeof value === 'function';\n}\n", "/**\n * Used to create Error subclasses until the community moves away from ES5.\n *\n * This is because compiling from TypeScript down to ES5 has issues with subclassing Errors\n * as well as other built-in types: https://github.com/Microsoft/TypeScript/issues/12123\n *\n * @param createImpl A factory function to create the actual constructor implementation. The returned\n * function should be a named function that calls `_super` internally.\n */\nexport function createErrorClass(createImpl: (_super: any) => any): T {\n const _super = (instance: any) => {\n Error.call(instance);\n instance.stack = new Error().stack;\n };\n\n const ctorFunc = createImpl(_super);\n ctorFunc.prototype = Object.create(Error.prototype);\n ctorFunc.prototype.constructor = ctorFunc;\n return ctorFunc;\n}\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface UnsubscriptionError extends Error {\n readonly errors: any[];\n}\n\nexport interface UnsubscriptionErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (errors: any[]): UnsubscriptionError;\n}\n\n/**\n * An error thrown when one or more errors have occurred during the\n * `unsubscribe` of a {@link Subscription}.\n */\nexport const UnsubscriptionError: UnsubscriptionErrorCtor = createErrorClass(\n (_super) =>\n function UnsubscriptionErrorImpl(this: any, errors: (Error | string)[]) {\n _super(this);\n this.message = errors\n ? `${errors.length} errors occurred during unsubscription:\n${errors.map((err, i) => `${i + 1}) ${err.toString()}`).join('\\n ')}`\n : '';\n this.name = 'UnsubscriptionError';\n this.errors = errors;\n }\n);\n", "/**\n * Removes an item from an array, mutating it.\n * @param arr The array to remove the item from\n * @param item The item to remove\n */\nexport function arrRemove(arr: T[] | undefined | null, item: T) {\n if (arr) {\n const index = arr.indexOf(item);\n 0 <= index && arr.splice(index, 1);\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { UnsubscriptionError } from './util/UnsubscriptionError';\nimport { SubscriptionLike, TeardownLogic, Unsubscribable } from './types';\nimport { arrRemove } from './util/arrRemove';\n\n/**\n * Represents a disposable resource, such as the execution of an Observable. A\n * Subscription has one important method, `unsubscribe`, that takes no argument\n * and just disposes the resource held by the subscription.\n *\n * Additionally, subscriptions may be grouped together through the `add()`\n * method, which will attach a child Subscription to the current Subscription.\n * When a Subscription is unsubscribed, all its children (and its grandchildren)\n * will be unsubscribed as well.\n *\n * @class Subscription\n */\nexport class Subscription implements SubscriptionLike {\n /** @nocollapse */\n public static EMPTY = (() => {\n const empty = new Subscription();\n empty.closed = true;\n return empty;\n })();\n\n /**\n * A flag to indicate whether this Subscription has already been unsubscribed.\n */\n public closed = false;\n\n private _parentage: Subscription[] | Subscription | null = null;\n\n /**\n * The list of registered finalizers to execute upon unsubscription. Adding and removing from this\n * list occurs in the {@link #add} and {@link #remove} methods.\n */\n private _finalizers: Exclude[] | null = null;\n\n /**\n * @param initialTeardown A function executed first as part of the finalization\n * process that is kicked off when {@link #unsubscribe} is called.\n */\n constructor(private initialTeardown?: () => void) {}\n\n /**\n * Disposes the resources held by the subscription. May, for instance, cancel\n * an ongoing Observable execution or cancel any other type of work that\n * started when the Subscription was created.\n * @return {void}\n */\n unsubscribe(): void {\n let errors: any[] | undefined;\n\n if (!this.closed) {\n this.closed = true;\n\n // Remove this from it's parents.\n const { _parentage } = this;\n if (_parentage) {\n this._parentage = null;\n if (Array.isArray(_parentage)) {\n for (const parent of _parentage) {\n parent.remove(this);\n }\n } else {\n _parentage.remove(this);\n }\n }\n\n const { initialTeardown: initialFinalizer } = this;\n if (isFunction(initialFinalizer)) {\n try {\n initialFinalizer();\n } catch (e) {\n errors = e instanceof UnsubscriptionError ? e.errors : [e];\n }\n }\n\n const { _finalizers } = this;\n if (_finalizers) {\n this._finalizers = null;\n for (const finalizer of _finalizers) {\n try {\n execFinalizer(finalizer);\n } catch (err) {\n errors = errors ?? [];\n if (err instanceof UnsubscriptionError) {\n errors = [...errors, ...err.errors];\n } else {\n errors.push(err);\n }\n }\n }\n }\n\n if (errors) {\n throw new UnsubscriptionError(errors);\n }\n }\n }\n\n /**\n * Adds a finalizer to this subscription, so that finalization will be unsubscribed/called\n * when this subscription is unsubscribed. If this subscription is already {@link #closed},\n * because it has already been unsubscribed, then whatever finalizer is passed to it\n * will automatically be executed (unless the finalizer itself is also a closed subscription).\n *\n * Closed Subscriptions cannot be added as finalizers to any subscription. Adding a closed\n * subscription to a any subscription will result in no operation. (A noop).\n *\n * Adding a subscription to itself, or adding `null` or `undefined` will not perform any\n * operation at all. (A noop).\n *\n * `Subscription` instances that are added to this instance will automatically remove themselves\n * if they are unsubscribed. Functions and {@link Unsubscribable} objects that you wish to remove\n * will need to be removed manually with {@link #remove}\n *\n * @param teardown The finalization logic to add to this subscription.\n */\n add(teardown: TeardownLogic): void {\n // Only add the finalizer if it's not undefined\n // and don't add a subscription to itself.\n if (teardown && teardown !== this) {\n if (this.closed) {\n // If this subscription is already closed,\n // execute whatever finalizer is handed to it automatically.\n execFinalizer(teardown);\n } else {\n if (teardown instanceof Subscription) {\n // We don't add closed subscriptions, and we don't add the same subscription\n // twice. Subscription unsubscribe is idempotent.\n if (teardown.closed || teardown._hasParent(this)) {\n return;\n }\n teardown._addParent(this);\n }\n (this._finalizers = this._finalizers ?? []).push(teardown);\n }\n }\n }\n\n /**\n * Checks to see if a this subscription already has a particular parent.\n * This will signal that this subscription has already been added to the parent in question.\n * @param parent the parent to check for\n */\n private _hasParent(parent: Subscription) {\n const { _parentage } = this;\n return _parentage === parent || (Array.isArray(_parentage) && _parentage.includes(parent));\n }\n\n /**\n * Adds a parent to this subscription so it can be removed from the parent if it\n * unsubscribes on it's own.\n *\n * NOTE: THIS ASSUMES THAT {@link _hasParent} HAS ALREADY BEEN CHECKED.\n * @param parent The parent subscription to add\n */\n private _addParent(parent: Subscription) {\n const { _parentage } = this;\n this._parentage = Array.isArray(_parentage) ? (_parentage.push(parent), _parentage) : _parentage ? [_parentage, parent] : parent;\n }\n\n /**\n * Called on a child when it is removed via {@link #remove}.\n * @param parent The parent to remove\n */\n private _removeParent(parent: Subscription) {\n const { _parentage } = this;\n if (_parentage === parent) {\n this._parentage = null;\n } else if (Array.isArray(_parentage)) {\n arrRemove(_parentage, parent);\n }\n }\n\n /**\n * Removes a finalizer from this subscription that was previously added with the {@link #add} method.\n *\n * Note that `Subscription` instances, when unsubscribed, will automatically remove themselves\n * from every other `Subscription` they have been added to. This means that using the `remove` method\n * is not a common thing and should be used thoughtfully.\n *\n * If you add the same finalizer instance of a function or an unsubscribable object to a `Subscription` instance\n * more than once, you will need to call `remove` the same number of times to remove all instances.\n *\n * All finalizer instances are removed to free up memory upon unsubscription.\n *\n * @param teardown The finalizer to remove from this subscription\n */\n remove(teardown: Exclude): void {\n const { _finalizers } = this;\n _finalizers && arrRemove(_finalizers, teardown);\n\n if (teardown instanceof Subscription) {\n teardown._removeParent(this);\n }\n }\n}\n\nexport const EMPTY_SUBSCRIPTION = Subscription.EMPTY;\n\nexport function isSubscription(value: any): value is Subscription {\n return (\n value instanceof Subscription ||\n (value && 'closed' in value && isFunction(value.remove) && isFunction(value.add) && isFunction(value.unsubscribe))\n );\n}\n\nfunction execFinalizer(finalizer: Unsubscribable | (() => void)) {\n if (isFunction(finalizer)) {\n finalizer();\n } else {\n finalizer.unsubscribe();\n }\n}\n", "import { Subscriber } from './Subscriber';\nimport { ObservableNotification } from './types';\n\n/**\n * The {@link GlobalConfig} object for RxJS. It is used to configure things\n * like how to react on unhandled errors.\n */\nexport const config: GlobalConfig = {\n onUnhandledError: null,\n onStoppedNotification: null,\n Promise: undefined,\n useDeprecatedSynchronousErrorHandling: false,\n useDeprecatedNextContext: false,\n};\n\n/**\n * The global configuration object for RxJS, used to configure things\n * like how to react on unhandled errors. Accessible via {@link config}\n * object.\n */\nexport interface GlobalConfig {\n /**\n * A registration point for unhandled errors from RxJS. These are errors that\n * cannot were not handled by consuming code in the usual subscription path. For\n * example, if you have this configured, and you subscribe to an observable without\n * providing an error handler, errors from that subscription will end up here. This\n * will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onUnhandledError: ((err: any) => void) | null;\n\n /**\n * A registration point for notifications that cannot be sent to subscribers because they\n * have completed, errored or have been explicitly unsubscribed. By default, next, complete\n * and error notifications sent to stopped subscribers are noops. However, sometimes callers\n * might want a different behavior. For example, with sources that attempt to report errors\n * to stopped subscribers, a caller can configure RxJS to throw an unhandled error instead.\n * This will _always_ be called asynchronously on another job in the runtime. This is because\n * we do not want errors thrown in this user-configured handler to interfere with the\n * behavior of the library.\n */\n onStoppedNotification: ((notification: ObservableNotification, subscriber: Subscriber) => void) | null;\n\n /**\n * The promise constructor used by default for {@link Observable#toPromise toPromise} and {@link Observable#forEach forEach}\n * methods.\n *\n * @deprecated As of version 8, RxJS will no longer support this sort of injection of a\n * Promise constructor. If you need a Promise implementation other than native promises,\n * please polyfill/patch Promise as you see appropriate. Will be removed in v8.\n */\n Promise?: PromiseConstructorLike;\n\n /**\n * If true, turns on synchronous error rethrowing, which is a deprecated behavior\n * in v6 and higher. This behavior enables bad patterns like wrapping a subscribe\n * call in a try/catch block. It also enables producer interference, a nasty bug\n * where a multicast can be broken for all observers by a downstream consumer with\n * an unhandled error. DO NOT USE THIS FLAG UNLESS IT'S NEEDED TO BUY TIME\n * FOR MIGRATION REASONS.\n *\n * @deprecated As of version 8, RxJS will no longer support synchronous throwing\n * of unhandled errors. All errors will be thrown on a separate call stack to prevent bad\n * behaviors described above. Will be removed in v8.\n */\n useDeprecatedSynchronousErrorHandling: boolean;\n\n /**\n * If true, enables an as-of-yet undocumented feature from v5: The ability to access\n * `unsubscribe()` via `this` context in `next` functions created in observers passed\n * to `subscribe`.\n *\n * This is being removed because the performance was severely problematic, and it could also cause\n * issues when types other than POJOs are passed to subscribe as subscribers, as they will likely have\n * their `this` context overwritten.\n *\n * @deprecated As of version 8, RxJS will no longer support altering the\n * context of next functions provided as part of an observer to Subscribe. Instead,\n * you will have access to a subscription or a signal or token that will allow you to do things like\n * unsubscribe and test closed status. Will be removed in v8.\n */\n useDeprecatedNextContext: boolean;\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetTimeoutFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearTimeoutFunction = (handle: TimerHandle) => void;\n\ninterface TimeoutProvider {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n delegate:\n | {\n setTimeout: SetTimeoutFunction;\n clearTimeout: ClearTimeoutFunction;\n }\n | undefined;\n}\n\nexport const timeoutProvider: TimeoutProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setTimeout(handler: () => void, timeout?: number, ...args) {\n const { delegate } = timeoutProvider;\n if (delegate?.setTimeout) {\n return delegate.setTimeout(handler, timeout, ...args);\n }\n return setTimeout(handler, timeout, ...args);\n },\n clearTimeout(handle) {\n const { delegate } = timeoutProvider;\n return (delegate?.clearTimeout || clearTimeout)(handle as any);\n },\n delegate: undefined,\n};\n", "import { config } from '../config';\nimport { timeoutProvider } from '../scheduler/timeoutProvider';\n\n/**\n * Handles an error on another job either with the user-configured {@link onUnhandledError},\n * or by throwing it on that new job so it can be picked up by `window.onerror`, `process.on('error')`, etc.\n *\n * This should be called whenever there is an error that is out-of-band with the subscription\n * or when an error hits a terminal boundary of the subscription and no error handler was provided.\n *\n * @param err the error to report\n */\nexport function reportUnhandledError(err: any) {\n timeoutProvider.setTimeout(() => {\n const { onUnhandledError } = config;\n if (onUnhandledError) {\n // Execute the user-configured error handler.\n onUnhandledError(err);\n } else {\n // Throw so it is picked up by the runtime's uncaught error mechanism.\n throw err;\n }\n });\n}\n", "/* tslint:disable:no-empty */\nexport function noop() { }\n", "import { CompleteNotification, NextNotification, ErrorNotification } from './types';\n\n/**\n * A completion object optimized for memory use and created to be the\n * same \"shape\" as other notifications in v8.\n * @internal\n */\nexport const COMPLETE_NOTIFICATION = (() => createNotification('C', undefined, undefined) as CompleteNotification)();\n\n/**\n * Internal use only. Creates an optimized error notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function errorNotification(error: any): ErrorNotification {\n return createNotification('E', undefined, error) as any;\n}\n\n/**\n * Internal use only. Creates an optimized next notification that is the same \"shape\"\n * as other notifications.\n * @internal\n */\nexport function nextNotification(value: T) {\n return createNotification('N', value, undefined) as NextNotification;\n}\n\n/**\n * Ensures that all notifications created internally have the same \"shape\" in v8.\n *\n * TODO: This is only exported to support a crazy legacy test in `groupBy`.\n * @internal\n */\nexport function createNotification(kind: 'N' | 'E' | 'C', value: any, error: any) {\n return {\n kind,\n value,\n error,\n };\n}\n", "import { config } from '../config';\n\nlet context: { errorThrown: boolean; error: any } | null = null;\n\n/**\n * Handles dealing with errors for super-gross mode. Creates a context, in which\n * any synchronously thrown errors will be passed to {@link captureError}. Which\n * will record the error such that it will be rethrown after the call back is complete.\n * TODO: Remove in v8\n * @param cb An immediately executed function.\n */\nexport function errorContext(cb: () => void) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n const isRoot = !context;\n if (isRoot) {\n context = { errorThrown: false, error: null };\n }\n cb();\n if (isRoot) {\n const { errorThrown, error } = context!;\n context = null;\n if (errorThrown) {\n throw error;\n }\n }\n } else {\n // This is the general non-deprecated path for everyone that\n // isn't crazy enough to use super-gross mode (useDeprecatedSynchronousErrorHandling)\n cb();\n }\n}\n\n/**\n * Captures errors only in super-gross mode.\n * @param err the error to capture\n */\nexport function captureError(err: any) {\n if (config.useDeprecatedSynchronousErrorHandling && context) {\n context.errorThrown = true;\n context.error = err;\n }\n}\n", "import { isFunction } from './util/isFunction';\nimport { Observer, ObservableNotification } from './types';\nimport { isSubscription, Subscription } from './Subscription';\nimport { config } from './config';\nimport { reportUnhandledError } from './util/reportUnhandledError';\nimport { noop } from './util/noop';\nimport { nextNotification, errorNotification, COMPLETE_NOTIFICATION } from './NotificationFactories';\nimport { timeoutProvider } from './scheduler/timeoutProvider';\nimport { captureError } from './util/errorContext';\n\n/**\n * Implements the {@link Observer} interface and extends the\n * {@link Subscription} class. While the {@link Observer} is the public API for\n * consuming the values of an {@link Observable}, all Observers get converted to\n * a Subscriber, in order to provide Subscription-like capabilities such as\n * `unsubscribe`. Subscriber is a common type in RxJS, and crucial for\n * implementing operators, but it is rarely used as a public API.\n *\n * @class Subscriber\n */\nexport class Subscriber extends Subscription implements Observer {\n /**\n * A static factory for a Subscriber, given a (potentially partial) definition\n * of an Observer.\n * @param next The `next` callback of an Observer.\n * @param error The `error` callback of an\n * Observer.\n * @param complete The `complete` callback of an\n * Observer.\n * @return A Subscriber wrapping the (partially defined)\n * Observer represented by the given arguments.\n * @nocollapse\n * @deprecated Do not use. Will be removed in v8. There is no replacement for this\n * method, and there is no reason to be creating instances of `Subscriber` directly.\n * If you have a specific use case, please file an issue.\n */\n static create(next?: (x?: T) => void, error?: (e?: any) => void, complete?: () => void): Subscriber {\n return new SafeSubscriber(next, error, complete);\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected isStopped: boolean = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n protected destination: Subscriber | Observer; // this `any` is the escape hatch to erase extra type param (e.g. R)\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * There is no reason to directly create an instance of Subscriber. This type is exported for typings reasons.\n */\n constructor(destination?: Subscriber | Observer) {\n super();\n if (destination) {\n this.destination = destination;\n // Automatically chain subscriptions together here.\n // if destination is a Subscription, then it is a Subscriber.\n if (isSubscription(destination)) {\n destination.add(this);\n }\n } else {\n this.destination = EMPTY_OBSERVER;\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `next` from\n * the Observable, with a value. The Observable may call this method 0 or more\n * times.\n * @param {T} [value] The `next` value.\n * @return {void}\n */\n next(value?: T): void {\n if (this.isStopped) {\n handleStoppedNotification(nextNotification(value), this);\n } else {\n this._next(value!);\n }\n }\n\n /**\n * The {@link Observer} callback to receive notifications of type `error` from\n * the Observable, with an attached `Error`. Notifies the Observer that\n * the Observable has experienced an error condition.\n * @param {any} [err] The `error` exception.\n * @return {void}\n */\n error(err?: any): void {\n if (this.isStopped) {\n handleStoppedNotification(errorNotification(err), this);\n } else {\n this.isStopped = true;\n this._error(err);\n }\n }\n\n /**\n * The {@link Observer} callback to receive a valueless notification of type\n * `complete` from the Observable. Notifies the Observer that the Observable\n * has finished sending push-based notifications.\n * @return {void}\n */\n complete(): void {\n if (this.isStopped) {\n handleStoppedNotification(COMPLETE_NOTIFICATION, this);\n } else {\n this.isStopped = true;\n this._complete();\n }\n }\n\n unsubscribe(): void {\n if (!this.closed) {\n this.isStopped = true;\n super.unsubscribe();\n this.destination = null!;\n }\n }\n\n protected _next(value: T): void {\n this.destination.next(value);\n }\n\n protected _error(err: any): void {\n try {\n this.destination.error(err);\n } finally {\n this.unsubscribe();\n }\n }\n\n protected _complete(): void {\n try {\n this.destination.complete();\n } finally {\n this.unsubscribe();\n }\n }\n}\n\n/**\n * This bind is captured here because we want to be able to have\n * compatibility with monoid libraries that tend to use a method named\n * `bind`. In particular, a library called Monio requires this.\n */\nconst _bind = Function.prototype.bind;\n\nfunction bind any>(fn: Fn, thisArg: any): Fn {\n return _bind.call(fn, thisArg);\n}\n\n/**\n * Internal optimization only, DO NOT EXPOSE.\n * @internal\n */\nclass ConsumerObserver implements Observer {\n constructor(private partialObserver: Partial>) {}\n\n next(value: T): void {\n const { partialObserver } = this;\n if (partialObserver.next) {\n try {\n partialObserver.next(value);\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n\n error(err: any): void {\n const { partialObserver } = this;\n if (partialObserver.error) {\n try {\n partialObserver.error(err);\n } catch (error) {\n handleUnhandledError(error);\n }\n } else {\n handleUnhandledError(err);\n }\n }\n\n complete(): void {\n const { partialObserver } = this;\n if (partialObserver.complete) {\n try {\n partialObserver.complete();\n } catch (error) {\n handleUnhandledError(error);\n }\n }\n }\n}\n\nexport class SafeSubscriber extends Subscriber {\n constructor(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((e?: any) => void) | null,\n complete?: (() => void) | null\n ) {\n super();\n\n let partialObserver: Partial>;\n if (isFunction(observerOrNext) || !observerOrNext) {\n // The first argument is a function, not an observer. The next\n // two arguments *could* be observers, or they could be empty.\n partialObserver = {\n next: (observerOrNext ?? undefined) as (((value: T) => void) | undefined),\n error: error ?? undefined,\n complete: complete ?? undefined,\n };\n } else {\n // The first argument is a partial observer.\n let context: any;\n if (this && config.useDeprecatedNextContext) {\n // This is a deprecated path that made `this.unsubscribe()` available in\n // next handler functions passed to subscribe. This only exists behind a flag\n // now, as it is *very* slow.\n context = Object.create(observerOrNext);\n context.unsubscribe = () => this.unsubscribe();\n partialObserver = {\n next: observerOrNext.next && bind(observerOrNext.next, context),\n error: observerOrNext.error && bind(observerOrNext.error, context),\n complete: observerOrNext.complete && bind(observerOrNext.complete, context),\n };\n } else {\n // The \"normal\" path. Just use the partial observer directly.\n partialObserver = observerOrNext;\n }\n }\n\n // Wrap the partial observer to ensure it's a full observer, and\n // make sure proper error handling is accounted for.\n this.destination = new ConsumerObserver(partialObserver);\n }\n}\n\nfunction handleUnhandledError(error: any) {\n if (config.useDeprecatedSynchronousErrorHandling) {\n captureError(error);\n } else {\n // Ideal path, we report this as an unhandled error,\n // which is thrown on a new call stack.\n reportUnhandledError(error);\n }\n}\n\n/**\n * An error handler used when no error handler was supplied\n * to the SafeSubscriber -- meaning no error handler was supplied\n * do the `subscribe` call on our observable.\n * @param err The error to handle\n */\nfunction defaultErrorHandler(err: any) {\n throw err;\n}\n\n/**\n * A handler for notifications that cannot be sent to a stopped subscriber.\n * @param notification The notification being sent\n * @param subscriber The stopped subscriber\n */\nfunction handleStoppedNotification(notification: ObservableNotification, subscriber: Subscriber) {\n const { onStoppedNotification } = config;\n onStoppedNotification && timeoutProvider.setTimeout(() => onStoppedNotification(notification, subscriber));\n}\n\n/**\n * The observer used as a stub for subscriptions where the user did not\n * pass any arguments to `subscribe`. Comes with the default error handling\n * behavior.\n */\nexport const EMPTY_OBSERVER: Readonly> & { closed: true } = {\n closed: true,\n next: noop,\n error: defaultErrorHandler,\n complete: noop,\n};\n", "/**\n * Symbol.observable or a string \"@@observable\". Used for interop\n *\n * @deprecated We will no longer be exporting this symbol in upcoming versions of RxJS.\n * Instead polyfill and use Symbol.observable directly *or* use https://www.npmjs.com/package/symbol-observable\n */\nexport const observable: string | symbol = (() => (typeof Symbol === 'function' && Symbol.observable) || '@@observable')();\n", "/**\n * This function takes one parameter and just returns it. Simply put,\n * this is like `(x: T): T => x`.\n *\n * ## Examples\n *\n * This is useful in some cases when using things like `mergeMap`\n *\n * ```ts\n * import { interval, take, map, range, mergeMap, identity } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(5));\n *\n * const result$ = source$.pipe(\n * map(i => range(i)),\n * mergeMap(identity) // same as mergeMap(x => x)\n * );\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * Or when you want to selectively apply an operator\n *\n * ```ts\n * import { interval, take, identity } from 'rxjs';\n *\n * const shouldLimit = () => Math.random() < 0.5;\n *\n * const source$ = interval(1000);\n *\n * const result$ = source$.pipe(shouldLimit() ? take(5) : identity);\n *\n * result$.subscribe({\n * next: console.log\n * });\n * ```\n *\n * @param x Any value that is returned by this function\n * @returns The value passed as the first parameter to this function\n */\nexport function identity(x: T): T {\n return x;\n}\n", "import { identity } from './identity';\nimport { UnaryFunction } from '../types';\n\nexport function pipe(): typeof identity;\nexport function pipe(fn1: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction): UnaryFunction;\nexport function pipe(fn1: UnaryFunction, fn2: UnaryFunction, fn3: UnaryFunction): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction\n): UnaryFunction;\nexport function pipe(\n fn1: UnaryFunction,\n fn2: UnaryFunction,\n fn3: UnaryFunction,\n fn4: UnaryFunction,\n fn5: UnaryFunction,\n fn6: UnaryFunction,\n fn7: UnaryFunction,\n fn8: UnaryFunction,\n fn9: UnaryFunction,\n ...fns: UnaryFunction[]\n): UnaryFunction;\n\n/**\n * pipe() can be called on one or more functions, each of which can take one argument (\"UnaryFunction\")\n * and uses it to return a value.\n * It returns a function that takes one argument, passes it to the first UnaryFunction, and then\n * passes the result to the next one, passes that result to the next one, and so on. \n */\nexport function pipe(...fns: Array>): UnaryFunction {\n return pipeFromArray(fns);\n}\n\n/** @internal */\nexport function pipeFromArray(fns: Array>): UnaryFunction {\n if (fns.length === 0) {\n return identity as UnaryFunction;\n }\n\n if (fns.length === 1) {\n return fns[0];\n }\n\n return function piped(input: T): R {\n return fns.reduce((prev: any, fn: UnaryFunction) => fn(prev), input as any);\n };\n}\n", "import { Operator } from './Operator';\nimport { SafeSubscriber, Subscriber } from './Subscriber';\nimport { isSubscription, Subscription } from './Subscription';\nimport { TeardownLogic, OperatorFunction, Subscribable, Observer } from './types';\nimport { observable as Symbol_observable } from './symbol/observable';\nimport { pipeFromArray } from './util/pipe';\nimport { config } from './config';\nimport { isFunction } from './util/isFunction';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A representation of any set of values over any amount of time. This is the most basic building block\n * of RxJS.\n *\n * @class Observable\n */\nexport class Observable implements Subscribable {\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n source: Observable | undefined;\n\n /**\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n */\n operator: Operator | undefined;\n\n /**\n * @constructor\n * @param {Function} subscribe the function that is called when the Observable is\n * initially subscribed to. This function is given a Subscriber, to which new values\n * can be `next`ed, or an `error` method can be called to raise an error, or\n * `complete` can be called to notify of a successful completion.\n */\n constructor(subscribe?: (this: Observable, subscriber: Subscriber) => TeardownLogic) {\n if (subscribe) {\n this._subscribe = subscribe;\n }\n }\n\n // HACK: Since TypeScript inherits static properties too, we have to\n // fight against TypeScript here so Subject can have a different static create signature\n /**\n * Creates a new Observable by calling the Observable constructor\n * @owner Observable\n * @method create\n * @param {Function} subscribe? the subscriber function to be passed to the Observable constructor\n * @return {Observable} a new observable\n * @nocollapse\n * @deprecated Use `new Observable()` instead. Will be removed in v8.\n */\n static create: (...args: any[]) => any = (subscribe?: (subscriber: Subscriber) => TeardownLogic) => {\n return new Observable(subscribe);\n };\n\n /**\n * Creates a new Observable, with this Observable instance as the source, and the passed\n * operator defined as the new observable's operator.\n * @method lift\n * @param operator the operator defining the operation to take on the observable\n * @return a new observable with the Operator applied\n * @deprecated Internal implementation detail, do not use directly. Will be made internal in v8.\n * If you have implemented an operator using `lift`, it is recommended that you create an\n * operator by simply returning `new Observable()` directly. See \"Creating new operators from\n * scratch\" section here: https://rxjs.dev/guide/operators\n */\n lift(operator?: Operator): Observable {\n const observable = new Observable();\n observable.source = this;\n observable.operator = operator;\n return observable;\n }\n\n subscribe(observerOrNext?: Partial> | ((value: T) => void)): Subscription;\n /** @deprecated Instead of passing separate callback arguments, use an observer argument. Signatures taking separate callback arguments will be removed in v8. Details: https://rxjs.dev/deprecations/subscribe-arguments */\n subscribe(next?: ((value: T) => void) | null, error?: ((error: any) => void) | null, complete?: (() => void) | null): Subscription;\n /**\n * Invokes an execution of an Observable and registers Observer handlers for notifications it will emit.\n *\n * Use it when you have all these Observables, but still nothing is happening.\n *\n * `subscribe` is not a regular operator, but a method that calls Observable's internal `subscribe` function. It\n * might be for example a function that you passed to Observable's constructor, but most of the time it is\n * a library implementation, which defines what will be emitted by an Observable, and when it be will emitted. This means\n * that calling `subscribe` is actually the moment when Observable starts its work, not when it is created, as it is often\n * the thought.\n *\n * Apart from starting the execution of an Observable, this method allows you to listen for values\n * that an Observable emits, as well as for when it completes or errors. You can achieve this in two\n * of the following ways.\n *\n * The first way is creating an object that implements {@link Observer} interface. It should have methods\n * defined by that interface, but note that it should be just a regular JavaScript object, which you can create\n * yourself in any way you want (ES6 class, classic function constructor, object literal etc.). In particular, do\n * not attempt to use any RxJS implementation details to create Observers - you don't need them. Remember also\n * that your object does not have to implement all methods. If you find yourself creating a method that doesn't\n * do anything, you can simply omit it. Note however, if the `error` method is not provided and an error happens,\n * it will be thrown asynchronously. Errors thrown asynchronously cannot be caught using `try`/`catch`. Instead,\n * use the {@link onUnhandledError} configuration option or use a runtime handler (like `window.onerror` or\n * `process.on('error)`) to be notified of unhandled errors. Because of this, it's recommended that you provide\n * an `error` method to avoid missing thrown errors.\n *\n * The second way is to give up on Observer object altogether and simply provide callback functions in place of its methods.\n * This means you can provide three functions as arguments to `subscribe`, where the first function is equivalent\n * of a `next` method, the second of an `error` method and the third of a `complete` method. Just as in case of an Observer,\n * if you do not need to listen for something, you can omit a function by passing `undefined` or `null`,\n * since `subscribe` recognizes these functions by where they were placed in function call. When it comes\n * to the `error` function, as with an Observer, if not provided, errors emitted by an Observable will be thrown asynchronously.\n *\n * You can, however, subscribe with no parameters at all. This may be the case where you're not interested in terminal events\n * and you also handled emissions internally by using operators (e.g. using `tap`).\n *\n * Whichever style of calling `subscribe` you use, in both cases it returns a Subscription object.\n * This object allows you to call `unsubscribe` on it, which in turn will stop the work that an Observable does and will clean\n * up all resources that an Observable used. Note that cancelling a subscription will not call `complete` callback\n * provided to `subscribe` function, which is reserved for a regular completion signal that comes from an Observable.\n *\n * Remember that callbacks provided to `subscribe` are not guaranteed to be called asynchronously.\n * It is an Observable itself that decides when these functions will be called. For example {@link of}\n * by default emits all its values synchronously. Always check documentation for how given Observable\n * will behave when subscribed and if its default behavior can be modified with a `scheduler`.\n *\n * #### Examples\n *\n * Subscribe with an {@link guide/observer Observer}\n *\n * ```ts\n * import { of } from 'rxjs';\n *\n * const sumObserver = {\n * sum: 0,\n * next(value) {\n * console.log('Adding: ' + value);\n * this.sum = this.sum + value;\n * },\n * error() {\n * // We actually could just remove this method,\n * // since we do not really care about errors right now.\n * },\n * complete() {\n * console.log('Sum equals: ' + this.sum);\n * }\n * };\n *\n * of(1, 2, 3) // Synchronously emits 1, 2, 3 and then completes.\n * .subscribe(sumObserver);\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Subscribe with functions ({@link deprecations/subscribe-arguments deprecated})\n *\n * ```ts\n * import { of } from 'rxjs'\n *\n * let sum = 0;\n *\n * of(1, 2, 3).subscribe(\n * value => {\n * console.log('Adding: ' + value);\n * sum = sum + value;\n * },\n * undefined,\n * () => console.log('Sum equals: ' + sum)\n * );\n *\n * // Logs:\n * // 'Adding: 1'\n * // 'Adding: 2'\n * // 'Adding: 3'\n * // 'Sum equals: 6'\n * ```\n *\n * Cancel a subscription\n *\n * ```ts\n * import { interval } from 'rxjs';\n *\n * const subscription = interval(1000).subscribe({\n * next(num) {\n * console.log(num)\n * },\n * complete() {\n * // Will not be called, even when cancelling subscription.\n * console.log('completed!');\n * }\n * });\n *\n * setTimeout(() => {\n * subscription.unsubscribe();\n * console.log('unsubscribed!');\n * }, 2500);\n *\n * // Logs:\n * // 0 after 1s\n * // 1 after 2s\n * // 'unsubscribed!' after 2.5s\n * ```\n *\n * @param {Observer|Function} observerOrNext (optional) Either an observer with methods to be called,\n * or the first of three possible handlers, which is the handler for each value emitted from the subscribed\n * Observable.\n * @param {Function} error (optional) A handler for a terminal event resulting from an error. If no error handler is provided,\n * the error will be thrown asynchronously as unhandled.\n * @param {Function} complete (optional) A handler for a terminal event resulting from successful completion.\n * @return {Subscription} a subscription reference to the registered handlers\n * @method subscribe\n */\n subscribe(\n observerOrNext?: Partial> | ((value: T) => void) | null,\n error?: ((error: any) => void) | null,\n complete?: (() => void) | null\n ): Subscription {\n const subscriber = isSubscriber(observerOrNext) ? observerOrNext : new SafeSubscriber(observerOrNext, error, complete);\n\n errorContext(() => {\n const { operator, source } = this;\n subscriber.add(\n operator\n ? // We're dealing with a subscription in the\n // operator chain to one of our lifted operators.\n operator.call(subscriber, source)\n : source\n ? // If `source` has a value, but `operator` does not, something that\n // had intimate knowledge of our API, like our `Subject`, must have\n // set it. We're going to just call `_subscribe` directly.\n this._subscribe(subscriber)\n : // In all other cases, we're likely wrapping a user-provided initializer\n // function, so we need to catch errors and handle them appropriately.\n this._trySubscribe(subscriber)\n );\n });\n\n return subscriber;\n }\n\n /** @internal */\n protected _trySubscribe(sink: Subscriber): TeardownLogic {\n try {\n return this._subscribe(sink);\n } catch (err) {\n // We don't need to return anything in this case,\n // because it's just going to try to `add()` to a subscription\n // above.\n sink.error(err);\n }\n }\n\n /**\n * Used as a NON-CANCELLABLE means of subscribing to an observable, for use with\n * APIs that expect promises, like `async/await`. You cannot unsubscribe from this.\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * #### Example\n *\n * ```ts\n * import { interval, take } from 'rxjs';\n *\n * const source$ = interval(1000).pipe(take(4));\n *\n * async function getTotal() {\n * let total = 0;\n *\n * await source$.forEach(value => {\n * total += value;\n * console.log('observable -> ' + value);\n * });\n *\n * return total;\n * }\n *\n * getTotal().then(\n * total => console.log('Total: ' + total)\n * );\n *\n * // Expected:\n * // 'observable -> 0'\n * // 'observable -> 1'\n * // 'observable -> 2'\n * // 'observable -> 3'\n * // 'Total: 6'\n * ```\n *\n * @param next a handler for each value emitted by the observable\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n */\n forEach(next: (value: T) => void): Promise;\n\n /**\n * @param next a handler for each value emitted by the observable\n * @param promiseCtor a constructor function used to instantiate the Promise\n * @return a promise that either resolves on observable completion or\n * rejects with the handled error\n * @deprecated Passing a Promise constructor will no longer be available\n * in upcoming versions of RxJS. This is because it adds weight to the library, for very\n * little benefit. If you need this functionality, it is recommended that you either\n * polyfill Promise, or you create an adapter to convert the returned native promise\n * to whatever promise implementation you wanted. Will be removed in v8.\n */\n forEach(next: (value: T) => void, promiseCtor: PromiseConstructorLike): Promise;\n\n forEach(next: (value: T) => void, promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n const subscriber = new SafeSubscriber({\n next: (value) => {\n try {\n next(value);\n } catch (err) {\n reject(err);\n subscriber.unsubscribe();\n }\n },\n error: reject,\n complete: resolve,\n });\n this.subscribe(subscriber);\n }) as Promise;\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): TeardownLogic {\n return this.source?.subscribe(subscriber);\n }\n\n /**\n * An interop point defined by the es7-observable spec https://github.com/zenparsing/es-observable\n * @method Symbol.observable\n * @return {Observable} this instance of the observable\n */\n [Symbol_observable]() {\n return this;\n }\n\n /* tslint:disable:max-line-length */\n pipe(): Observable;\n pipe(op1: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction): Observable;\n pipe(op1: OperatorFunction, op2: OperatorFunction, op3: OperatorFunction): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction\n ): Observable;\n pipe(\n op1: OperatorFunction,\n op2: OperatorFunction,\n op3: OperatorFunction,\n op4: OperatorFunction,\n op5: OperatorFunction,\n op6: OperatorFunction,\n op7: OperatorFunction,\n op8: OperatorFunction,\n op9: OperatorFunction,\n ...operations: OperatorFunction[]\n ): Observable;\n /* tslint:enable:max-line-length */\n\n /**\n * Used to stitch together functional operators into a chain.\n * @method pipe\n * @return {Observable} the Observable result of all of the operators having\n * been called in the order they were passed in.\n *\n * ## Example\n *\n * ```ts\n * import { interval, filter, map, scan } from 'rxjs';\n *\n * interval(1000)\n * .pipe(\n * filter(x => x % 2 === 0),\n * map(x => x + x),\n * scan((acc, x) => acc + x)\n * )\n * .subscribe(x => console.log(x));\n * ```\n */\n pipe(...operations: OperatorFunction[]): Observable {\n return pipeFromArray(operations)(this);\n }\n\n /* tslint:disable:max-line-length */\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: typeof Promise): Promise;\n /** @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise */\n toPromise(PromiseCtor: PromiseConstructorLike): Promise;\n /* tslint:enable:max-line-length */\n\n /**\n * Subscribe to this Observable and get a Promise resolving on\n * `complete` with the last emission (if any).\n *\n * **WARNING**: Only use this with observables you *know* will complete. If the source\n * observable does not complete, you will end up with a promise that is hung up, and\n * potentially all of the state of an async function hanging out in memory. To avoid\n * this situation, look into adding something like {@link timeout}, {@link take},\n * {@link takeWhile}, or {@link takeUntil} amongst others.\n *\n * @method toPromise\n * @param [promiseCtor] a constructor function used to instantiate\n * the Promise\n * @return A Promise that resolves with the last value emit, or\n * rejects on an error. If there were no emissions, Promise\n * resolves with undefined.\n * @deprecated Replaced with {@link firstValueFrom} and {@link lastValueFrom}. Will be removed in v8. Details: https://rxjs.dev/deprecations/to-promise\n */\n toPromise(promiseCtor?: PromiseConstructorLike): Promise {\n promiseCtor = getPromiseCtor(promiseCtor);\n\n return new promiseCtor((resolve, reject) => {\n let value: T | undefined;\n this.subscribe(\n (x: T) => (value = x),\n (err: any) => reject(err),\n () => resolve(value)\n );\n }) as Promise;\n }\n}\n\n/**\n * Decides between a passed promise constructor from consuming code,\n * A default configured promise constructor, and the native promise\n * constructor and returns it. If nothing can be found, it will throw\n * an error.\n * @param promiseCtor The optional promise constructor to passed by consuming code\n */\nfunction getPromiseCtor(promiseCtor: PromiseConstructorLike | undefined) {\n return promiseCtor ?? config.Promise ?? Promise;\n}\n\nfunction isObserver(value: any): value is Observer {\n return value && isFunction(value.next) && isFunction(value.error) && isFunction(value.complete);\n}\n\nfunction isSubscriber(value: any): value is Subscriber {\n return (value && value instanceof Subscriber) || (isObserver(value) && isSubscription(value));\n}\n", "import { Observable } from '../Observable';\nimport { Subscriber } from '../Subscriber';\nimport { OperatorFunction } from '../types';\nimport { isFunction } from './isFunction';\n\n/**\n * Used to determine if an object is an Observable with a lift function.\n */\nexport function hasLift(source: any): source is { lift: InstanceType['lift'] } {\n return isFunction(source?.lift);\n}\n\n/**\n * Creates an `OperatorFunction`. Used to define operators throughout the library in a concise way.\n * @param init The logic to connect the liftedSource to the subscriber at the moment of subscription.\n */\nexport function operate(\n init: (liftedSource: Observable, subscriber: Subscriber) => (() => void) | void\n): OperatorFunction {\n return (source: Observable) => {\n if (hasLift(source)) {\n return source.lift(function (this: Subscriber, liftedSource: Observable) {\n try {\n return init(liftedSource, this);\n } catch (err) {\n this.error(err);\n }\n });\n }\n throw new TypeError('Unable to lift unknown Observable type');\n };\n}\n", "import { Subscriber } from '../Subscriber';\n\n/**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional teardown logic here. This will only be called on teardown if the\n * subscriber itself is not already closed. This is called after all other teardown logic is executed.\n */\nexport function createOperatorSubscriber(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n onFinalize?: () => void\n): Subscriber {\n return new OperatorSubscriber(destination, onNext, onComplete, onError, onFinalize);\n}\n\n/**\n * A generic helper for allowing operators to be created with a Subscriber and\n * use closures to capture necessary state from the operator function itself.\n */\nexport class OperatorSubscriber extends Subscriber {\n /**\n * Creates an instance of an `OperatorSubscriber`.\n * @param destination The downstream subscriber.\n * @param onNext Handles next values, only called if this subscriber is not stopped or closed. Any\n * error that occurs in this function is caught and sent to the `error` method of this subscriber.\n * @param onError Handles errors from the subscription, any errors that occur in this handler are caught\n * and send to the `destination` error handler.\n * @param onComplete Handles completion notification from the subscription. Any errors that occur in\n * this handler are sent to the `destination` error handler.\n * @param onFinalize Additional finalization logic here. This will only be called on finalization if the\n * subscriber itself is not already closed. This is called after all other finalization logic is executed.\n * @param shouldUnsubscribe An optional check to see if an unsubscribe call should truly unsubscribe.\n * NOTE: This currently **ONLY** exists to support the strange behavior of {@link groupBy}, where unsubscription\n * to the resulting observable does not actually disconnect from the source if there are active subscriptions\n * to any grouped observable. (DO NOT EXPOSE OR USE EXTERNALLY!!!)\n */\n constructor(\n destination: Subscriber,\n onNext?: (value: T) => void,\n onComplete?: () => void,\n onError?: (err: any) => void,\n private onFinalize?: () => void,\n private shouldUnsubscribe?: () => boolean\n ) {\n // It's important - for performance reasons - that all of this class's\n // members are initialized and that they are always initialized in the same\n // order. This will ensure that all OperatorSubscriber instances have the\n // same hidden class in V8. This, in turn, will help keep the number of\n // hidden classes involved in property accesses within the base class as\n // low as possible. If the number of hidden classes involved exceeds four,\n // the property accesses will become megamorphic and performance penalties\n // will be incurred - i.e. inline caches won't be used.\n //\n // The reasons for ensuring all instances have the same hidden class are\n // further discussed in this blog post from Benedikt Meurer:\n // https://benediktmeurer.de/2018/03/23/impact-of-polymorphism-on-component-based-frameworks-like-react/\n super(destination);\n this._next = onNext\n ? function (this: OperatorSubscriber, value: T) {\n try {\n onNext(value);\n } catch (err) {\n destination.error(err);\n }\n }\n : super._next;\n this._error = onError\n ? function (this: OperatorSubscriber, err: any) {\n try {\n onError(err);\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._error;\n this._complete = onComplete\n ? function (this: OperatorSubscriber) {\n try {\n onComplete();\n } catch (err) {\n // Send any errors that occur down stream.\n destination.error(err);\n } finally {\n // Ensure finalization.\n this.unsubscribe();\n }\n }\n : super._complete;\n }\n\n unsubscribe() {\n if (!this.shouldUnsubscribe || this.shouldUnsubscribe()) {\n const { closed } = this;\n super.unsubscribe();\n // Execute additional teardown if we have any and we didn't already do so.\n !closed && this.onFinalize?.();\n }\n }\n}\n", "import { Subscription } from '../Subscription';\n\ninterface AnimationFrameProvider {\n schedule(callback: FrameRequestCallback): Subscription;\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n delegate:\n | {\n requestAnimationFrame: typeof requestAnimationFrame;\n cancelAnimationFrame: typeof cancelAnimationFrame;\n }\n | undefined;\n}\n\nexport const animationFrameProvider: AnimationFrameProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n schedule(callback) {\n let request = requestAnimationFrame;\n let cancel: typeof cancelAnimationFrame | undefined = cancelAnimationFrame;\n const { delegate } = animationFrameProvider;\n if (delegate) {\n request = delegate.requestAnimationFrame;\n cancel = delegate.cancelAnimationFrame;\n }\n const handle = request((timestamp) => {\n // Clear the cancel function. The request has been fulfilled, so\n // attempting to cancel the request upon unsubscription would be\n // pointless.\n cancel = undefined;\n callback(timestamp);\n });\n return new Subscription(() => cancel?.(handle));\n },\n requestAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.requestAnimationFrame || requestAnimationFrame)(...args);\n },\n cancelAnimationFrame(...args) {\n const { delegate } = animationFrameProvider;\n return (delegate?.cancelAnimationFrame || cancelAnimationFrame)(...args);\n },\n delegate: undefined,\n};\n", "import { createErrorClass } from './createErrorClass';\n\nexport interface ObjectUnsubscribedError extends Error {}\n\nexport interface ObjectUnsubscribedErrorCtor {\n /**\n * @deprecated Internal implementation detail. Do not construct error instances.\n * Cannot be tagged as internal: https://github.com/ReactiveX/rxjs/issues/6269\n */\n new (): ObjectUnsubscribedError;\n}\n\n/**\n * An error thrown when an action is invalid because the object has been\n * unsubscribed.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n *\n * @class ObjectUnsubscribedError\n */\nexport const ObjectUnsubscribedError: ObjectUnsubscribedErrorCtor = createErrorClass(\n (_super) =>\n function ObjectUnsubscribedErrorImpl(this: any) {\n _super(this);\n this.name = 'ObjectUnsubscribedError';\n this.message = 'object unsubscribed';\n }\n);\n", "import { Operator } from './Operator';\nimport { Observable } from './Observable';\nimport { Subscriber } from './Subscriber';\nimport { Subscription, EMPTY_SUBSCRIPTION } from './Subscription';\nimport { Observer, SubscriptionLike, TeardownLogic } from './types';\nimport { ObjectUnsubscribedError } from './util/ObjectUnsubscribedError';\nimport { arrRemove } from './util/arrRemove';\nimport { errorContext } from './util/errorContext';\n\n/**\n * A Subject is a special type of Observable that allows values to be\n * multicasted to many Observers. Subjects are like EventEmitters.\n *\n * Every Subject is an Observable and an Observer. You can subscribe to a\n * Subject, and you can call next to feed values as well as error and complete.\n */\nexport class Subject extends Observable implements SubscriptionLike {\n closed = false;\n\n private currentObservers: Observer[] | null = null;\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n observers: Observer[] = [];\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n isStopped = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n hasError = false;\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n thrownError: any = null;\n\n /**\n * Creates a \"subject\" by basically gluing an observer to an observable.\n *\n * @nocollapse\n * @deprecated Recommended you do not use. Will be removed at some point in the future. Plans for replacement still under discussion.\n */\n static create: (...args: any[]) => any = (destination: Observer, source: Observable): AnonymousSubject => {\n return new AnonymousSubject(destination, source);\n };\n\n constructor() {\n // NOTE: This must be here to obscure Observable's constructor.\n super();\n }\n\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n lift(operator: Operator): Observable {\n const subject = new AnonymousSubject(this, this);\n subject.operator = operator as any;\n return subject as any;\n }\n\n /** @internal */\n protected _throwIfClosed() {\n if (this.closed) {\n throw new ObjectUnsubscribedError();\n }\n }\n\n next(value: T) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n if (!this.currentObservers) {\n this.currentObservers = Array.from(this.observers);\n }\n for (const observer of this.currentObservers) {\n observer.next(value);\n }\n }\n });\n }\n\n error(err: any) {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.hasError = this.isStopped = true;\n this.thrownError = err;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.error(err);\n }\n }\n });\n }\n\n complete() {\n errorContext(() => {\n this._throwIfClosed();\n if (!this.isStopped) {\n this.isStopped = true;\n const { observers } = this;\n while (observers.length) {\n observers.shift()!.complete();\n }\n }\n });\n }\n\n unsubscribe() {\n this.isStopped = this.closed = true;\n this.observers = this.currentObservers = null!;\n }\n\n get observed() {\n return this.observers?.length > 0;\n }\n\n /** @internal */\n protected _trySubscribe(subscriber: Subscriber): TeardownLogic {\n this._throwIfClosed();\n return super._trySubscribe(subscriber);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._checkFinalizedStatuses(subscriber);\n return this._innerSubscribe(subscriber);\n }\n\n /** @internal */\n protected _innerSubscribe(subscriber: Subscriber) {\n const { hasError, isStopped, observers } = this;\n if (hasError || isStopped) {\n return EMPTY_SUBSCRIPTION;\n }\n this.currentObservers = null;\n observers.push(subscriber);\n return new Subscription(() => {\n this.currentObservers = null;\n arrRemove(observers, subscriber);\n });\n }\n\n /** @internal */\n protected _checkFinalizedStatuses(subscriber: Subscriber) {\n const { hasError, thrownError, isStopped } = this;\n if (hasError) {\n subscriber.error(thrownError);\n } else if (isStopped) {\n subscriber.complete();\n }\n }\n\n /**\n * Creates a new Observable with this Subject as the source. You can do this\n * to create custom Observer-side logic of the Subject and conceal it from\n * code that uses the Observable.\n * @return {Observable} Observable that the Subject casts to\n */\n asObservable(): Observable {\n const observable: any = new Observable();\n observable.source = this;\n return observable;\n }\n}\n\n/**\n * @class AnonymousSubject\n */\nexport class AnonymousSubject extends Subject {\n constructor(\n /** @deprecated Internal implementation detail, do not use directly. Will be made internal in v8. */\n public destination?: Observer,\n source?: Observable\n ) {\n super();\n this.source = source;\n }\n\n next(value: T) {\n this.destination?.next?.(value);\n }\n\n error(err: any) {\n this.destination?.error?.(err);\n }\n\n complete() {\n this.destination?.complete?.();\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n return this.source?.subscribe(subscriber) ?? EMPTY_SUBSCRIPTION;\n }\n}\n", "import { TimestampProvider } from '../types';\n\ninterface DateTimestampProvider extends TimestampProvider {\n delegate: TimestampProvider | undefined;\n}\n\nexport const dateTimestampProvider: DateTimestampProvider = {\n now() {\n // Use the variable rather than `this` so that the function can be called\n // without being bound to the provider.\n return (dateTimestampProvider.delegate || Date).now();\n },\n delegate: undefined,\n};\n", "import { Subject } from './Subject';\nimport { TimestampProvider } from './types';\nimport { Subscriber } from './Subscriber';\nimport { Subscription } from './Subscription';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * A variant of {@link Subject} that \"replays\" old values to new subscribers by emitting them when they first subscribe.\n *\n * `ReplaySubject` has an internal buffer that will store a specified number of values that it has observed. Like `Subject`,\n * `ReplaySubject` \"observes\" values by having them passed to its `next` method. When it observes a value, it will store that\n * value for a time determined by the configuration of the `ReplaySubject`, as passed to its constructor.\n *\n * When a new subscriber subscribes to the `ReplaySubject` instance, it will synchronously emit all values in its buffer in\n * a First-In-First-Out (FIFO) manner. The `ReplaySubject` will also complete, if it has observed completion; and it will\n * error if it has observed an error.\n *\n * There are two main configuration items to be concerned with:\n *\n * 1. `bufferSize` - This will determine how many items are stored in the buffer, defaults to infinite.\n * 2. `windowTime` - The amount of time to hold a value in the buffer before removing it from the buffer.\n *\n * Both configurations may exist simultaneously. So if you would like to buffer a maximum of 3 values, as long as the values\n * are less than 2 seconds old, you could do so with a `new ReplaySubject(3, 2000)`.\n *\n * ### Differences with BehaviorSubject\n *\n * `BehaviorSubject` is similar to `new ReplaySubject(1)`, with a couple of exceptions:\n *\n * 1. `BehaviorSubject` comes \"primed\" with a single value upon construction.\n * 2. `ReplaySubject` will replay values, even after observing an error, where `BehaviorSubject` will not.\n *\n * @see {@link Subject}\n * @see {@link BehaviorSubject}\n * @see {@link shareReplay}\n */\nexport class ReplaySubject extends Subject {\n private _buffer: (T | number)[] = [];\n private _infiniteTimeWindow = true;\n\n /**\n * @param bufferSize The size of the buffer to replay on subscription\n * @param windowTime The amount of time the buffered items will stay buffered\n * @param timestampProvider An object with a `now()` method that provides the current timestamp. This is used to\n * calculate the amount of time something has been buffered.\n */\n constructor(\n private _bufferSize = Infinity,\n private _windowTime = Infinity,\n private _timestampProvider: TimestampProvider = dateTimestampProvider\n ) {\n super();\n this._infiniteTimeWindow = _windowTime === Infinity;\n this._bufferSize = Math.max(1, _bufferSize);\n this._windowTime = Math.max(1, _windowTime);\n }\n\n next(value: T): void {\n const { isStopped, _buffer, _infiniteTimeWindow, _timestampProvider, _windowTime } = this;\n if (!isStopped) {\n _buffer.push(value);\n !_infiniteTimeWindow && _buffer.push(_timestampProvider.now() + _windowTime);\n }\n this._trimBuffer();\n super.next(value);\n }\n\n /** @internal */\n protected _subscribe(subscriber: Subscriber): Subscription {\n this._throwIfClosed();\n this._trimBuffer();\n\n const subscription = this._innerSubscribe(subscriber);\n\n const { _infiniteTimeWindow, _buffer } = this;\n // We use a copy here, so reentrant code does not mutate our array while we're\n // emitting it to a new subscriber.\n const copy = _buffer.slice();\n for (let i = 0; i < copy.length && !subscriber.closed; i += _infiniteTimeWindow ? 1 : 2) {\n subscriber.next(copy[i] as T);\n }\n\n this._checkFinalizedStatuses(subscriber);\n\n return subscription;\n }\n\n private _trimBuffer() {\n const { _bufferSize, _timestampProvider, _buffer, _infiniteTimeWindow } = this;\n // If we don't have an infinite buffer size, and we're over the length,\n // use splice to truncate the old buffer values off. Note that we have to\n // double the size for instances where we're not using an infinite time window\n // because we're storing the values and the timestamps in the same array.\n const adjustedBufferSize = (_infiniteTimeWindow ? 1 : 2) * _bufferSize;\n _bufferSize < Infinity && adjustedBufferSize < _buffer.length && _buffer.splice(0, _buffer.length - adjustedBufferSize);\n\n // Now, if we're not in an infinite time window, remove all values where the time is\n // older than what is allowed.\n if (!_infiniteTimeWindow) {\n const now = _timestampProvider.now();\n let last = 0;\n // Search the array for the first timestamp that isn't expired and\n // truncate the buffer up to that point.\n for (let i = 1; i < _buffer.length && (_buffer[i] as number) <= now; i += 2) {\n last = i;\n }\n last && _buffer.splice(0, last + 1);\n }\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Subscription } from '../Subscription';\nimport { SchedulerAction } from '../types';\n\n/**\n * A unit of work to be executed in a `scheduler`. An action is typically\n * created from within a {@link SchedulerLike} and an RxJS user does not need to concern\n * themselves about creating and manipulating an Action.\n *\n * ```ts\n * class Action extends Subscription {\n * new (scheduler: Scheduler, work: (state?: T) => void);\n * schedule(state?: T, delay: number = 0): Subscription;\n * }\n * ```\n *\n * @class Action\n */\nexport class Action extends Subscription {\n constructor(scheduler: Scheduler, work: (this: SchedulerAction, state?: T) => void) {\n super();\n }\n /**\n * Schedules this action on its parent {@link SchedulerLike} for execution. May be passed\n * some context object, `state`. May happen at some point in the future,\n * according to the `delay` parameter, if specified.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler.\n * @return {void}\n */\n public schedule(state?: T, delay: number = 0): Subscription {\n return this;\n }\n}\n", "import type { TimerHandle } from './timerHandle';\ntype SetIntervalFunction = (handler: () => void, timeout?: number, ...args: any[]) => TimerHandle;\ntype ClearIntervalFunction = (handle: TimerHandle) => void;\n\ninterface IntervalProvider {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n delegate:\n | {\n setInterval: SetIntervalFunction;\n clearInterval: ClearIntervalFunction;\n }\n | undefined;\n}\n\nexport const intervalProvider: IntervalProvider = {\n // When accessing the delegate, use the variable rather than `this` so that\n // the functions can be called without being bound to the provider.\n setInterval(handler: () => void, timeout?: number, ...args) {\n const { delegate } = intervalProvider;\n if (delegate?.setInterval) {\n return delegate.setInterval(handler, timeout, ...args);\n }\n return setInterval(handler, timeout, ...args);\n },\n clearInterval(handle) {\n const { delegate } = intervalProvider;\n return (delegate?.clearInterval || clearInterval)(handle as any);\n },\n delegate: undefined,\n};\n", "import { Action } from './Action';\nimport { SchedulerAction } from '../types';\nimport { Subscription } from '../Subscription';\nimport { AsyncScheduler } from './AsyncScheduler';\nimport { intervalProvider } from './intervalProvider';\nimport { arrRemove } from '../util/arrRemove';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncAction extends Action {\n public id: TimerHandle | undefined;\n public state?: T;\n // @ts-ignore: Property has no initializer and is not definitely assigned\n public delay: number;\n protected pending: boolean = false;\n\n constructor(protected scheduler: AsyncScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n public schedule(state?: T, delay: number = 0): Subscription {\n if (this.closed) {\n return this;\n }\n\n // Always replace the current state with the new state.\n this.state = state;\n\n const id = this.id;\n const scheduler = this.scheduler;\n\n //\n // Important implementation note:\n //\n // Actions only execute once by default, unless rescheduled from within the\n // scheduled callback. This allows us to implement single and repeat\n // actions via the same code path, without adding API surface area, as well\n // as mimic traditional recursion but across asynchronous boundaries.\n //\n // However, JS runtimes and timers distinguish between intervals achieved by\n // serial `setTimeout` calls vs. a single `setInterval` call. An interval of\n // serial `setTimeout` calls can be individually delayed, which delays\n // scheduling the next `setTimeout`, and so on. `setInterval` attempts to\n // guarantee the interval callback will be invoked more precisely to the\n // interval period, regardless of load.\n //\n // Therefore, we use `setInterval` to schedule single and repeat actions.\n // If the action reschedules itself with the same delay, the interval is not\n // canceled. If the action doesn't reschedule, or reschedules with a\n // different delay, the interval will be canceled after scheduled callback\n // execution.\n //\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, delay);\n }\n\n // Set the pending flag indicating that this action has been scheduled, or\n // has recursively rescheduled itself.\n this.pending = true;\n\n this.delay = delay;\n // If this action has already an async Id, don't request a new one.\n this.id = this.id ?? this.requestAsyncId(scheduler, this.id, delay);\n\n return this;\n }\n\n protected requestAsyncId(scheduler: AsyncScheduler, _id?: TimerHandle, delay: number = 0): TimerHandle {\n return intervalProvider.setInterval(scheduler.flush.bind(scheduler, this), delay);\n }\n\n protected recycleAsyncId(_scheduler: AsyncScheduler, id?: TimerHandle, delay: number | null = 0): TimerHandle | undefined {\n // If this action is rescheduled with the same delay time, don't clear the interval id.\n if (delay != null && this.delay === delay && this.pending === false) {\n return id;\n }\n // Otherwise, if the action's delay time is different from the current delay,\n // or the action has been rescheduled before it's executed, clear the interval id\n if (id != null) {\n intervalProvider.clearInterval(id);\n }\n\n return undefined;\n }\n\n /**\n * Immediately executes this action and the `work` it contains.\n * @return {any}\n */\n public execute(state: T, delay: number): any {\n if (this.closed) {\n return new Error('executing a cancelled action');\n }\n\n this.pending = false;\n const error = this._execute(state, delay);\n if (error) {\n return error;\n } else if (this.pending === false && this.id != null) {\n // Dequeue if the action didn't reschedule itself. Don't call\n // unsubscribe(), because the action could reschedule later.\n // For example:\n // ```\n // scheduler.schedule(function doWork(counter) {\n // /* ... I'm a busy worker bee ... */\n // var originalAction = this;\n // /* wait 100ms before rescheduling the action */\n // setTimeout(function () {\n // originalAction.schedule(counter + 1);\n // }, 100);\n // }, 1000);\n // ```\n this.id = this.recycleAsyncId(this.scheduler, this.id, null);\n }\n }\n\n protected _execute(state: T, _delay: number): any {\n let errored: boolean = false;\n let errorValue: any;\n try {\n this.work(state);\n } catch (e) {\n errored = true;\n // HACK: Since code elsewhere is relying on the \"truthiness\" of the\n // return here, we can't have it return \"\" or 0 or false.\n // TODO: Clean this up when we refactor schedulers mid-version-8 or so.\n errorValue = e ? e : new Error('Scheduled action threw falsy error');\n }\n if (errored) {\n this.unsubscribe();\n return errorValue;\n }\n }\n\n unsubscribe() {\n if (!this.closed) {\n const { id, scheduler } = this;\n const { actions } = scheduler;\n\n this.work = this.state = this.scheduler = null!;\n this.pending = false;\n\n arrRemove(actions, this);\n if (id != null) {\n this.id = this.recycleAsyncId(scheduler, id, null);\n }\n\n this.delay = null!;\n super.unsubscribe();\n }\n }\n}\n", "import { Action } from './scheduler/Action';\nimport { Subscription } from './Subscription';\nimport { SchedulerLike, SchedulerAction } from './types';\nimport { dateTimestampProvider } from './scheduler/dateTimestampProvider';\n\n/**\n * An execution context and a data structure to order tasks and schedule their\n * execution. Provides a notion of (potentially virtual) time, through the\n * `now()` getter method.\n *\n * Each unit of work in a Scheduler is called an `Action`.\n *\n * ```ts\n * class Scheduler {\n * now(): number;\n * schedule(work, delay?, state?): Subscription;\n * }\n * ```\n *\n * @class Scheduler\n * @deprecated Scheduler is an internal implementation detail of RxJS, and\n * should not be used directly. Rather, create your own class and implement\n * {@link SchedulerLike}. Will be made internal in v8.\n */\nexport class Scheduler implements SchedulerLike {\n public static now: () => number = dateTimestampProvider.now;\n\n constructor(private schedulerActionCtor: typeof Action, now: () => number = Scheduler.now) {\n this.now = now;\n }\n\n /**\n * A getter method that returns a number representing the current time\n * (at the time this function was called) according to the scheduler's own\n * internal clock.\n * @return {number} A number that represents the current time. May or may not\n * have a relation to wall-clock time. May or may not refer to a time unit\n * (e.g. milliseconds).\n */\n public now: () => number;\n\n /**\n * Schedules a function, `work`, for execution. May happen at some point in\n * the future, according to the `delay` parameter, if specified. May be passed\n * some context object, `state`, which will be passed to the `work` function.\n *\n * The given arguments will be processed an stored as an Action object in a\n * queue of actions.\n *\n * @param {function(state: ?T): ?Subscription} work A function representing a\n * task, or some unit of work to be executed by the Scheduler.\n * @param {number} [delay] Time to wait before executing the work, where the\n * time unit is implicit and defined by the Scheduler itself.\n * @param {T} [state] Some contextual data that the `work` function uses when\n * called by the Scheduler.\n * @return {Subscription} A subscription in order to be able to unsubscribe\n * the scheduled work.\n */\n public schedule(work: (this: SchedulerAction, state?: T) => void, delay: number = 0, state?: T): Subscription {\n return new this.schedulerActionCtor(this, work).schedule(state, delay);\n }\n}\n", "import { Scheduler } from '../Scheduler';\nimport { Action } from './Action';\nimport { AsyncAction } from './AsyncAction';\nimport { TimerHandle } from './timerHandle';\n\nexport class AsyncScheduler extends Scheduler {\n public actions: Array> = [];\n /**\n * A flag to indicate whether the Scheduler is currently executing a batch of\n * queued actions.\n * @type {boolean}\n * @internal\n */\n public _active: boolean = false;\n /**\n * An internal ID used to track the latest asynchronous task such as those\n * coming from `setTimeout`, `setInterval`, `requestAnimationFrame`, and\n * others.\n * @type {any}\n * @internal\n */\n public _scheduled: TimerHandle | undefined;\n\n constructor(SchedulerAction: typeof Action, now: () => number = Scheduler.now) {\n super(SchedulerAction, now);\n }\n\n public flush(action: AsyncAction): void {\n const { actions } = this;\n\n if (this._active) {\n actions.push(action);\n return;\n }\n\n let error: any;\n this._active = true;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions.shift()!)); // exhaust the scheduler queue\n\n this._active = false;\n\n if (error) {\n while ((action = actions.shift()!)) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\n/**\n *\n * Async Scheduler\n *\n * Schedule task as if you used setTimeout(task, duration)\n *\n * `async` scheduler schedules tasks asynchronously, by putting them on the JavaScript\n * event loop queue. It is best used to delay tasks in time or to schedule tasks repeating\n * in intervals.\n *\n * If you just want to \"defer\" task, that is to perform it right after currently\n * executing synchronous code ends (commonly achieved by `setTimeout(deferredTask, 0)`),\n * better choice will be the {@link asapScheduler} scheduler.\n *\n * ## Examples\n * Use async scheduler to delay task\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * const task = () => console.log('it works!');\n *\n * asyncScheduler.schedule(task, 2000);\n *\n * // After 2 seconds logs:\n * // \"it works!\"\n * ```\n *\n * Use async scheduler to repeat task in intervals\n * ```ts\n * import { asyncScheduler } from 'rxjs';\n *\n * function task(state) {\n * console.log(state);\n * this.schedule(state + 1, 1000); // `this` references currently executing Action,\n * // which we reschedule with new state and delay\n * }\n *\n * asyncScheduler.schedule(task, 3000, 0);\n *\n * // Logs:\n * // 0 after 3s\n * // 1 after 4s\n * // 2 after 5s\n * // 3 after 6s\n * ```\n */\n\nexport const asyncScheduler = new AsyncScheduler(AsyncAction);\n\n/**\n * @deprecated Renamed to {@link asyncScheduler}. Will be removed in v8.\n */\nexport const async = asyncScheduler;\n", "import { AsyncAction } from './AsyncAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\nimport { SchedulerAction } from '../types';\nimport { animationFrameProvider } from './animationFrameProvider';\nimport { TimerHandle } from './timerHandle';\n\nexport class AnimationFrameAction extends AsyncAction {\n constructor(protected scheduler: AnimationFrameScheduler, protected work: (this: SchedulerAction, state?: T) => void) {\n super(scheduler, work);\n }\n\n protected requestAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle {\n // If delay is greater than 0, request as an async action.\n if (delay !== null && delay > 0) {\n return super.requestAsyncId(scheduler, id, delay);\n }\n // Push the action to the end of the scheduler queue.\n scheduler.actions.push(this);\n // If an animation frame has already been requested, don't request another\n // one. If an animation frame hasn't been requested yet, request one. Return\n // the current animation frame request id.\n return scheduler._scheduled || (scheduler._scheduled = animationFrameProvider.requestAnimationFrame(() => scheduler.flush(undefined)));\n }\n\n protected recycleAsyncId(scheduler: AnimationFrameScheduler, id?: TimerHandle, delay: number = 0): TimerHandle | undefined {\n // If delay exists and is greater than 0, or if the delay is null (the\n // action wasn't rescheduled) but was originally scheduled as an async\n // action, then recycle as an async action.\n if (delay != null ? delay > 0 : this.delay > 0) {\n return super.recycleAsyncId(scheduler, id, delay);\n }\n // If the scheduler queue has no remaining actions with the same async id,\n // cancel the requested animation frame and set the scheduled flag to\n // undefined so the next AnimationFrameAction will request its own.\n const { actions } = scheduler;\n if (id != null && actions[actions.length - 1]?.id !== id) {\n animationFrameProvider.cancelAnimationFrame(id as number);\n scheduler._scheduled = undefined;\n }\n // Return undefined so the action knows to request a new async id if it's rescheduled.\n return undefined;\n }\n}\n", "import { AsyncAction } from './AsyncAction';\nimport { AsyncScheduler } from './AsyncScheduler';\n\nexport class AnimationFrameScheduler extends AsyncScheduler {\n public flush(action?: AsyncAction): void {\n this._active = true;\n // The async id that effects a call to flush is stored in _scheduled.\n // Before executing an action, it's necessary to check the action's async\n // id to determine whether it's supposed to be executed in the current\n // flush.\n // Previous implementations of this method used a count to determine this,\n // but that was unsound, as actions that are unsubscribed - i.e. cancelled -\n // are removed from the actions array and that can shift actions that are\n // scheduled to be executed in a subsequent flush into positions at which\n // they are executed within the current flush.\n const flushId = this._scheduled;\n this._scheduled = undefined;\n\n const { actions } = this;\n let error: any;\n action = action || actions.shift()!;\n\n do {\n if ((error = action.execute(action.state, action.delay))) {\n break;\n }\n } while ((action = actions[0]) && action.id === flushId && actions.shift());\n\n this._active = false;\n\n if (error) {\n while ((action = actions[0]) && action.id === flushId && actions.shift()) {\n action.unsubscribe();\n }\n throw error;\n }\n }\n}\n", "import { AnimationFrameAction } from './AnimationFrameAction';\nimport { AnimationFrameScheduler } from './AnimationFrameScheduler';\n\n/**\n *\n * Animation Frame Scheduler\n *\n * Perform task when `window.requestAnimationFrame` would fire\n *\n * When `animationFrame` scheduler is used with delay, it will fall back to {@link asyncScheduler} scheduler\n * behaviour.\n *\n * Without delay, `animationFrame` scheduler can be used to create smooth browser animations.\n * It makes sure scheduled task will happen just before next browser content repaint,\n * thus performing animations as efficiently as possible.\n *\n * ## Example\n * Schedule div height animation\n * ```ts\n * // html:

    \n * import { animationFrameScheduler } from 'rxjs';\n *\n * const div = document.querySelector('div');\n *\n * animationFrameScheduler.schedule(function(height) {\n * div.style.height = height + \"px\";\n *\n * this.schedule(height + 1); // `this` references currently executing Action,\n * // which we reschedule with new state\n * }, 0, 0);\n *\n * // You will see a div element growing in height\n * ```\n */\n\nexport const animationFrameScheduler = new AnimationFrameScheduler(AnimationFrameAction);\n\n/**\n * @deprecated Renamed to {@link animationFrameScheduler}. Will be removed in v8.\n */\nexport const animationFrame = animationFrameScheduler;\n", "import { Observable } from '../Observable';\nimport { SchedulerLike } from '../types';\n\n/**\n * A simple Observable that emits no items to the Observer and immediately\n * emits a complete notification.\n *\n * Just emits 'complete', and nothing else.\n *\n * ![](empty.png)\n *\n * A simple Observable that only emits the complete notification. It can be used\n * for composing with other Observables, such as in a {@link mergeMap}.\n *\n * ## Examples\n *\n * Log complete notification\n *\n * ```ts\n * import { EMPTY } from 'rxjs';\n *\n * EMPTY.subscribe({\n * next: () => console.log('Next'),\n * complete: () => console.log('Complete!')\n * });\n *\n * // Outputs\n * // Complete!\n * ```\n *\n * Emit the number 7, then complete\n *\n * ```ts\n * import { EMPTY, startWith } from 'rxjs';\n *\n * const result = EMPTY.pipe(startWith(7));\n * result.subscribe(x => console.log(x));\n *\n * // Outputs\n * // 7\n * ```\n *\n * Map and flatten only odd numbers to the sequence `'a'`, `'b'`, `'c'`\n *\n * ```ts\n * import { interval, mergeMap, of, EMPTY } from 'rxjs';\n *\n * const interval$ = interval(1000);\n * const result = interval$.pipe(\n * mergeMap(x => x % 2 === 1 ? of('a', 'b', 'c') : EMPTY),\n * );\n * result.subscribe(x => console.log(x));\n *\n * // Results in the following to the console:\n * // x is equal to the count on the interval, e.g. (0, 1, 2, 3, ...)\n * // x will occur every 1000ms\n * // if x % 2 is equal to 1, print a, b, c (each on its own)\n * // if x % 2 is not equal to 1, nothing will be output\n * ```\n *\n * @see {@link Observable}\n * @see {@link NEVER}\n * @see {@link of}\n * @see {@link throwError}\n */\nexport const EMPTY = new Observable((subscriber) => subscriber.complete());\n\n/**\n * @param scheduler A {@link SchedulerLike} to use for scheduling\n * the emission of the complete notification.\n * @deprecated Replaced with the {@link EMPTY} constant or {@link scheduled} (e.g. `scheduled([], scheduler)`). Will be removed in v8.\n */\nexport function empty(scheduler?: SchedulerLike) {\n return scheduler ? emptyScheduled(scheduler) : EMPTY;\n}\n\nfunction emptyScheduled(scheduler: SchedulerLike) {\n return new Observable((subscriber) => scheduler.schedule(() => subscriber.complete()));\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport function isScheduler(value: any): value is SchedulerLike {\n return value && isFunction(value.schedule);\n}\n", "import { SchedulerLike } from '../types';\nimport { isFunction } from './isFunction';\nimport { isScheduler } from './isScheduler';\n\nfunction last(arr: T[]): T | undefined {\n return arr[arr.length - 1];\n}\n\nexport function popResultSelector(args: any[]): ((...args: unknown[]) => unknown) | undefined {\n return isFunction(last(args)) ? args.pop() : undefined;\n}\n\nexport function popScheduler(args: any[]): SchedulerLike | undefined {\n return isScheduler(last(args)) ? args.pop() : undefined;\n}\n\nexport function popNumber(args: any[], defaultValue: number): number {\n return typeof last(args) === 'number' ? args.pop()! : defaultValue;\n}\n", "export const isArrayLike = ((x: any): x is ArrayLike => x && typeof x.length === 'number' && typeof x !== 'function');", "import { isFunction } from \"./isFunction\";\n\n/**\n * Tests to see if the object is \"thennable\".\n * @param value the object to test\n */\nexport function isPromise(value: any): value is PromiseLike {\n return isFunction(value?.then);\n}\n", "import { InteropObservable } from '../types';\nimport { observable as Symbol_observable } from '../symbol/observable';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being Observable (but not necessary an Rx Observable) */\nexport function isInteropObservable(input: any): input is InteropObservable {\n return isFunction(input[Symbol_observable]);\n}\n", "import { isFunction } from './isFunction';\n\nexport function isAsyncIterable(obj: any): obj is AsyncIterable {\n return Symbol.asyncIterator && isFunction(obj?.[Symbol.asyncIterator]);\n}\n", "/**\n * Creates the TypeError to throw if an invalid object is passed to `from` or `scheduled`.\n * @param input The object that was passed.\n */\nexport function createInvalidObservableTypeError(input: any) {\n // TODO: We should create error codes that can be looked up, so this can be less verbose.\n return new TypeError(\n `You provided ${\n input !== null && typeof input === 'object' ? 'an invalid object' : `'${input}'`\n } where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.`\n );\n}\n", "export function getSymbolIterator(): symbol {\n if (typeof Symbol !== 'function' || !Symbol.iterator) {\n return '@@iterator' as any;\n }\n\n return Symbol.iterator;\n}\n\nexport const iterator = getSymbolIterator();\n", "import { iterator as Symbol_iterator } from '../symbol/iterator';\nimport { isFunction } from './isFunction';\n\n/** Identifies an input as being an Iterable */\nexport function isIterable(input: any): input is Iterable {\n return isFunction(input?.[Symbol_iterator]);\n}\n", "import { ReadableStreamLike } from '../types';\nimport { isFunction } from './isFunction';\n\nexport async function* readableStreamLikeToAsyncGenerator(readableStream: ReadableStreamLike): AsyncGenerator {\n const reader = readableStream.getReader();\n try {\n while (true) {\n const { value, done } = await reader.read();\n if (done) {\n return;\n }\n yield value!;\n }\n } finally {\n reader.releaseLock();\n }\n}\n\nexport function isReadableStreamLike(obj: any): obj is ReadableStreamLike {\n // We don't want to use instanceof checks because they would return\n // false for instances from another Realm, like an