From b27409efcc744cd1b3cf63d79180d246bd70f657 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 2 Feb 2020 13:46:48 +0100 Subject: [PATCH 1/8] Update dependencies - add pandas 1.0 (for future chapter 09) - add jupyter nbextensions (so that RISE can be configured) --- poetry.lock | 239 ++++++++++++++++++++++++++++++++++++++++++++--- pyproject.toml | 2 + requirements.txt | 17 +++- 3 files changed, 240 insertions(+), 18 deletions(-) diff --git a/poetry.lock b/poetry.lock index 07e1126..4fd7c13 100644 --- a/poetry.lock +++ b/poetry.lock @@ -129,7 +129,7 @@ marker = "python_version < \"3.8\"" name = "importlib-metadata" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" -version = "1.4.0" +version = "1.5.0" [package.dependencies] zipp = ">=0.5" @@ -162,7 +162,7 @@ description = "IPython: Productive Interactive Computing" name = "ipython" optional = false python-versions = ">=3.6" -version = "7.11.1" +version = "7.12.0" [package.dependencies] appnope = "*" @@ -178,7 +178,7 @@ setuptools = ">=18.5" traitlets = ">=4.2" [package.extras] -all = ["ipywidgets", "ipyparallel", "qtconsole", "ipykernel", "nbconvert", "notebook", "nbformat", "testpath", "pygments", "requests", "numpy (>=1.14)", "nose (>=0.10.1)", "Sphinx (>=1.3)"] +all = ["ipyparallel", "requests", "notebook", "qtconsole", "ipywidgets", "pygments", "nbconvert", "testpath", "Sphinx (>=1.3)", "nbformat", "numpy (>=1.14)", "ipykernel", "nose (>=0.10.1)"] doc = ["Sphinx (>=1.3)"] kernel = ["ipykernel"] nbconvert = ["nbconvert"] @@ -217,7 +217,7 @@ description = "A very fast and expressive template engine." name = "jinja2" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" -version = "2.11.0" +version = "2.11.1" [package.dependencies] MarkupSafe = ">=0.23" @@ -231,7 +231,7 @@ description = "A Python implementation of the JSON5 data format." name = "json5" optional = false python-versions = "*" -version = "0.8.5" +version = "0.9.0" [[package]] category = "main" @@ -274,6 +274,49 @@ traitlets = "*" [package.extras] test = ["ipykernel", "ipython", "mock", "pytest"] +[[package]] +category = "dev" +description = "Common utilities for jupyter-contrib projects." +name = "jupyter-contrib-core" +optional = false +python-versions = "*" +version = "0.3.3" + +[package.dependencies] +jupyter-core = "*" +notebook = ">=4.0" +setuptools = "*" +tornado = "*" +traitlets = "*" + +[package.extras] +testing_utils = ["nose", "mock"] + +[[package]] +category = "dev" +description = "A collection of Jupyter nbextensions." +name = "jupyter-contrib-nbextensions" +optional = false +python-versions = "*" +version = "0.5.1" + +[package.dependencies] +ipython-genutils = "*" +jupyter-contrib-core = ">=0.3.3" +jupyter-core = "*" +jupyter-highlight-selected-word = ">=0.1.1" +jupyter-latex-envs = ">=1.3.8" +jupyter-nbextensions-configurator = ">=0.4.0" +lxml = "*" +nbconvert = ">=4.2" +notebook = ">=4.0" +pyyaml = "*" +tornado = "*" +traitlets = ">=4.1" + +[package.extras] +test = ["nbformat", "nose", "pip", "requests", "mock"] + [[package]] category = "main" description = "Jupyter core package. A base package on which Jupyter projects rely." @@ -286,6 +329,48 @@ version = "4.6.1" pywin32 = ">=1.0" traitlets = "*" +[[package]] +category = "dev" +description = "Jupyter notebook extension that enables highlighting every instance of the current word in the notebook." +name = "jupyter-highlight-selected-word" +optional = false +python-versions = "*" +version = "0.2.0" + +[[package]] +category = "dev" +description = "Jupyter notebook extension which supports (some) LaTeX environments within markdown cells. Also provides support for labels and crossreferences, document wide numbering, bibliography, and more..." +name = "jupyter-latex-envs" +optional = false +python-versions = "*" +version = "1.4.6" + +[package.dependencies] +ipython = "*" +jupyter_core = "*" +nbconvert = "*" +notebook = ">=4.0" +traitlets = ">=4.1" + +[[package]] +category = "dev" +description = "jupyter serverextension providing configuration interfaces for nbextensions." +name = "jupyter-nbextensions-configurator" +optional = false +python-versions = "*" +version = "0.4.1" + +[package.dependencies] +jupyter_contrib_core = ">=0.3.3" +jupyter_core = "*" +notebook = ">=4.0" +pyyaml = "*" +tornado = "*" +traitlets = "*" + +[package.extras] +test = ["jupyter-contrib-core", "nose", "requests", "selenium", "mock"] + [[package]] category = "main" description = "The JupyterLab notebook server extension." @@ -321,6 +406,20 @@ notebook = ">=4.2.0" [package.extras] test = ["pytest", "requests"] +[[package]] +category = "dev" +description = "Powerful and Pythonic XML processing library combining libxml2/libxslt with the ElementTree API." +name = "lxml" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, != 3.4.*" +version = "4.5.0" + +[package.extras] +cssselect = ["cssselect (>=0.7)"] +html5 = ["html5lib"] +htmlsoup = ["beautifulsoup4"] +source = ["Cython (>=0.29.7)"] + [[package]] category = "main" description = "Safely add untrusted strings to HTML/XML markup." @@ -416,6 +515,22 @@ optional = false python-versions = ">=3.5" version = "1.18.1" +[[package]] +category = "main" +description = "Powerful data structures for data analysis, time series, and statistics" +name = "pandas" +optional = false +python-versions = ">=3.6.1" +version = "1.0.0" + +[package.dependencies] +numpy = ">=1.13.3" +python-dateutil = ">=2.6.1" +pytz = ">=2017.2" + +[package.extras] +test = ["pytest (>=4.0.2)", "pytest-xdist", "hypothesis (>=3.58)"] + [[package]] category = "main" description = "Utilities for writing pandoc filters in python" @@ -524,6 +639,14 @@ version = "2.8.1" [package.dependencies] six = ">=1.5" +[[package]] +category = "main" +description = "World timezone definitions, modern and historical" +name = "pytz" +optional = false +python-versions = "*" +version = "2019.3" + [[package]] category = "main" description = "Python for Window Extensions" @@ -542,6 +665,14 @@ optional = false python-versions = "*" version = "0.5.7" +[[package]] +category = "dev" +description = "YAML parser and emitter for Python" +name = "pyyaml" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +version = "5.3" + [[package]] category = "main" description = "Python bindings for 0MQ" @@ -679,7 +810,7 @@ docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] testing = ["jaraco.itertools"] [metadata] -content-hash = "c7cc19bb83c0f0869c6fbe7c1a65a57cf18f5d46d115e007080e497af615c1a3" +content-hash = "57a0723ba6d72fe21cc17ebfd12347a16a17d9cfefb90f7b3f5eb76da5d07d97" python-versions = "^3.7" [metadata.files] @@ -731,16 +862,16 @@ entrypoints = [ {file = "entrypoints-0.3.tar.gz", hash = "sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"}, ] importlib-metadata = [ - {file = "importlib_metadata-1.4.0-py2.py3-none-any.whl", hash = "sha256:bdd9b7c397c273bcc9a11d6629a38487cd07154fa255a467bf704cd2c258e359"}, - {file = "importlib_metadata-1.4.0.tar.gz", hash = "sha256:f17c015735e1a88296994c0697ecea7e11db24290941983b08c9feb30921e6d8"}, + {file = "importlib_metadata-1.5.0-py2.py3-none-any.whl", hash = "sha256:b97607a1a18a5100839aec1dc26a1ea17ee0d93b20b0f008d80a5a050afb200b"}, + {file = "importlib_metadata-1.5.0.tar.gz", hash = "sha256:06f5b3a99029c7134207dd882428a66992a9de2bef7c2b699b5641f9886c3302"}, ] ipykernel = [ {file = "ipykernel-5.1.4-py3-none-any.whl", hash = "sha256:ba8c9e5561f3223fb47ce06ad7925cb9444337ac367341c0c520ffb68ea6d120"}, {file = "ipykernel-5.1.4.tar.gz", hash = "sha256:7f1f01df22f1229c8879501057877ccaf92a3b01c1d00db708aad5003e5f9238"}, ] ipython = [ - {file = "ipython-7.11.1-py3-none-any.whl", hash = "sha256:387686dd7fc9caf29d2fddcf3116c4b07a11d9025701d220c589a430b0171d8a"}, - {file = "ipython-7.11.1.tar.gz", hash = "sha256:0f4bcf18293fb666df8511feec0403bdb7e061a5842ea6e88a3177b0ceb34ead"}, + {file = "ipython-7.12.0-py3-none-any.whl", hash = "sha256:f6689108b1734501d3b59c84427259fd5ac5141afe2e846cfa8598eb811886c9"}, + {file = "ipython-7.12.0.tar.gz", hash = "sha256:d9459e7237e2e5858738ff9c3e26504b79899b58a6d49e574d352493d80684c6"}, ] ipython-genutils = [ {file = "ipython_genutils-0.2.0-py2.py3-none-any.whl", hash = "sha256:72dd37233799e619666c9f639a9da83c34013a73e8bbc79a7a6348d93c61fab8"}, @@ -751,12 +882,12 @@ jedi = [ {file = "jedi-0.16.0.tar.gz", hash = "sha256:d5c871cb9360b414f981e7072c52c33258d598305280fef91c6cae34739d65d5"}, ] jinja2 = [ - {file = "Jinja2-2.11.0-py2.py3-none-any.whl", hash = "sha256:6e7a3c2934694d59ad334c93dd1b6c96699cf24c53fdb8ec848ac6b23e685734"}, - {file = "Jinja2-2.11.0.tar.gz", hash = "sha256:d6609ae5ec3d56212ca7d802eda654eaf2310000816ce815361041465b108be4"}, + {file = "Jinja2-2.11.1-py2.py3-none-any.whl", hash = "sha256:b0eaf100007721b5c16c1fc1eecb87409464edc10469ddc9a22a27a99123be49"}, + {file = "Jinja2-2.11.1.tar.gz", hash = "sha256:93187ffbc7808079673ef52771baa950426fd664d3aad1d0fa3e95644360e250"}, ] json5 = [ - {file = "json5-0.8.5-py2.py3-none-any.whl", hash = "sha256:32bd17e0553bf53927f6c29b6089f3a320c12897120a4bcfea76ea81c10b2d9c"}, - {file = "json5-0.8.5.tar.gz", hash = "sha256:124b0f0da1ed2ff3bfe3a3e9b8630abd3c650852465cb52c15ef60b8e82a73b0"}, + {file = "json5-0.9.0-py2.py3-none-any.whl", hash = "sha256:f2dd81b3de344143144532804171ff8e7da93cd57af6b56d4d4afa859f8c77ff"}, + {file = "json5-0.9.0.tar.gz", hash = "sha256:62a7a36f5f9806108d39bfc59d4458e2a083762a2fc15fd3c7828c72502fd702"}, ] jsonschema = [ {file = "jsonschema-3.2.0-py2.py3-none-any.whl", hash = "sha256:4e5b3cf8216f577bee9ce139cbe72eca3ea4f292ec60928ff24758ce626cd163"}, @@ -766,10 +897,28 @@ jupyter-client = [ {file = "jupyter_client-5.3.4-py2.py3-none-any.whl", hash = "sha256:d0c077c9aaa4432ad485e7733e4d91e48f87b4f4bab7d283d42bb24cbbba0a0f"}, {file = "jupyter_client-5.3.4.tar.gz", hash = "sha256:60e6faec1031d63df57f1cc671ed673dced0ed420f4377ea33db37b1c188b910"}, ] +jupyter-contrib-core = [ + {file = "jupyter_contrib_core-0.3.3-py2.py3-none-any.whl", hash = "sha256:1ec81e275a8f5858d56b0c4c6cd85335aa8e915001b8657fe51c620c3cdde50f"}, + {file = "jupyter_contrib_core-0.3.3.tar.gz", hash = "sha256:e65bc0e932ff31801003cef160a4665f2812efe26a53801925a634735e9a5794"}, +] +jupyter-contrib-nbextensions = [ + {file = "jupyter_contrib_nbextensions-0.5.1-py2.py3-none-any.whl", hash = "sha256:2c071f0aa208c569666f656bdc0f66906ca493cf9f06f46db6350db11030ff40"}, + {file = "jupyter_contrib_nbextensions-0.5.1.tar.gz", hash = "sha256:eecd28ecc2fc410226c0a3d4932ed2fac4860ccf8d9e9b1b29548835a35b22ab"}, +] jupyter-core = [ {file = "jupyter_core-4.6.1-py2.py3-none-any.whl", hash = "sha256:464769f7387d7a62a2403d067f1ddc616655b7f77f5d810c0dd62cb54bfd0fb9"}, {file = "jupyter_core-4.6.1.tar.gz", hash = "sha256:a183e0ec2e8f6adddf62b0a3fc6a2237e3e0056d381e536d3e7c7ecc3067e244"}, ] +jupyter-highlight-selected-word = [ + {file = "jupyter_highlight_selected_word-0.2.0-py2.py3-none-any.whl", hash = "sha256:9545dfa9cb057eebe3a5795604dcd3a5294ea18637e553f61a0b67c1b5903c58"}, + {file = "jupyter_highlight_selected_word-0.2.0.tar.gz", hash = "sha256:9fa740424859a807950ca08d2bfd28a35154cd32dd6d50ac4e0950022adc0e7b"}, +] +jupyter-latex-envs = [ + {file = "jupyter_latex_envs-1.4.6.tar.gz", hash = "sha256:070a31eb2dc488bba983915879a7c2939247bf5c3b669b398bdb36a9b5343872"}, +] +jupyter-nbextensions-configurator = [ + {file = "jupyter_nbextensions_configurator-0.4.1.tar.gz", hash = "sha256:e5e86b5d9d898e1ffb30ebb08e4ad8696999f798fef3ff3262d7b999076e4e83"}, +] jupyterlab = [ {file = "jupyterlab-1.2.6-py2.py3-none-any.whl", hash = "sha256:56c108e28934ac463754b7656441c0d92e76a81ad5dad446fe1071c6fd86245c"}, {file = "jupyterlab-1.2.6.tar.gz", hash = "sha256:42134b13fb0c410a9f55e8492a31ba5a1a346430a22690a512b8307764b68355"}, @@ -778,6 +927,35 @@ jupyterlab-server = [ {file = "jupyterlab_server-1.0.6-py3-none-any.whl", hash = "sha256:d9c3bcf097f7ad8d8fd2f8d0c1e8a1b833671c02808e5f807088975495364447"}, {file = "jupyterlab_server-1.0.6.tar.gz", hash = "sha256:d0977527bfce6f47c782cb6bf79d2c949ebe3f22ac695fa000b730c671445dad"}, ] +lxml = [ + {file = "lxml-4.5.0-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:0701f7965903a1c3f6f09328c1278ac0eee8f56f244e66af79cb224b7ef3801c"}, + {file = "lxml-4.5.0-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:06d4e0bbb1d62e38ae6118406d7cdb4693a3fa34ee3762238bcb96c9e36a93cd"}, + {file = "lxml-4.5.0-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5828c7f3e615f3975d48f40d4fe66e8a7b25f16b5e5705ffe1d22e43fb1f6261"}, + {file = "lxml-4.5.0-cp27-cp27m-win32.whl", hash = "sha256:afdb34b715daf814d1abea0317b6d672476b498472f1e5aacbadc34ebbc26e89"}, + {file = "lxml-4.5.0-cp27-cp27m-win_amd64.whl", hash = "sha256:585c0869f75577ac7a8ff38d08f7aac9033da2c41c11352ebf86a04652758b7a"}, + {file = "lxml-4.5.0-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:8a0ebda56ebca1a83eb2d1ac266649b80af8dd4b4a3502b2c1e09ac2f88fe128"}, + {file = "lxml-4.5.0-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:fe976a0f1ef09b3638778024ab9fb8cde3118f203364212c198f71341c0715ca"}, + {file = "lxml-4.5.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7bc1b221e7867f2e7ff1933165c0cec7153dce93d0cdba6554b42a8beb687bdb"}, + {file = "lxml-4.5.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:d068f55bda3c2c3fcaec24bd083d9e2eede32c583faf084d6e4b9daaea77dde8"}, + {file = "lxml-4.5.0-cp35-cp35m-win32.whl", hash = "sha256:e4aa948eb15018a657702fee0b9db47e908491c64d36b4a90f59a64741516e77"}, + {file = "lxml-4.5.0-cp35-cp35m-win_amd64.whl", hash = "sha256:1f2c4ec372bf1c4a2c7e4bb20845e8bcf8050365189d86806bad1e3ae473d081"}, + {file = "lxml-4.5.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:5d467ce9c5d35b3bcc7172c06320dddb275fea6ac2037f72f0a4d7472035cea9"}, + {file = "lxml-4.5.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:95e67224815ef86924fbc2b71a9dbd1f7262384bca4bc4793645794ac4200717"}, + {file = "lxml-4.5.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ebec08091a22c2be870890913bdadd86fcd8e9f0f22bcb398abd3af914690c15"}, + {file = "lxml-4.5.0-cp36-cp36m-win32.whl", hash = "sha256:deadf4df349d1dcd7b2853a2c8796593cc346600726eff680ed8ed11812382a7"}, + {file = "lxml-4.5.0-cp36-cp36m-win_amd64.whl", hash = "sha256:f2b74784ed7e0bc2d02bd53e48ad6ba523c9b36c194260b7a5045071abbb1012"}, + {file = "lxml-4.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fa071559f14bd1e92077b1b5f6c22cf09756c6de7139370249eb372854ce51e6"}, + {file = "lxml-4.5.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:edc15fcfd77395e24543be48871c251f38132bb834d9fdfdad756adb6ea37679"}, + {file = "lxml-4.5.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:fd52e796fee7171c4361d441796b64df1acfceb51f29e545e812f16d023c4bbc"}, + {file = "lxml-4.5.0-cp37-cp37m-win32.whl", hash = "sha256:90ed0e36455a81b25b7034038e40880189169c308a3df360861ad74da7b68c1a"}, + {file = "lxml-4.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:df533af6f88080419c5a604d0d63b2c33b1c0c4409aba7d0cb6de305147ea8c8"}, + {file = "lxml-4.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b4b2c63cc7963aedd08a5f5a454c9f67251b1ac9e22fd9d72836206c42dc2a72"}, + {file = "lxml-4.5.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e5d842c73e4ef6ed8c1bd77806bf84a7cb535f9c0cf9b2c74d02ebda310070e1"}, + {file = "lxml-4.5.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:63dbc21efd7e822c11d5ddbedbbb08cd11a41e0032e382a0fd59b0b08e405a3a"}, + {file = "lxml-4.5.0-cp38-cp38-win32.whl", hash = "sha256:4235bc124fdcf611d02047d7034164897ade13046bda967768836629bc62784f"}, + {file = "lxml-4.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:d5b3c4b7edd2e770375a01139be11307f04341ec709cf724e0f26ebb1eef12c3"}, + {file = "lxml-4.5.0.tar.gz", hash = "sha256:8620ce80f50d023d414183bf90cc2576c2837b88e00bea3f33ad2630133bbb60"}, +] markupsafe = [ {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, @@ -847,6 +1025,22 @@ numpy = [ {file = "numpy-1.18.1-cp38-cp38-win_amd64.whl", hash = "sha256:39d2c685af15d3ce682c99ce5925cc66efc824652e10990d2462dfe9b8918c6a"}, {file = "numpy-1.18.1.zip", hash = "sha256:b6ff59cee96b454516e47e7721098e6ceebef435e3e21ac2d6c3b8b02628eb77"}, ] +pandas = [ + {file = "pandas-1.0.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:b578df33338a09707bfe3e3939c9d46700948133bf829357c3c46795055c9376"}, + {file = "pandas-1.0.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:e8be4f6da608930c0d565240bfbe04fc6f5764d6a9214b02c6231cd5e223591d"}, + {file = "pandas-1.0.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d76a8ec22adf0323d362dac8c900b2c66e06eab984ecf04ef072866d8ab6c538"}, + {file = "pandas-1.0.0-cp36-cp36m-win32.whl", hash = "sha256:bad77cf498362590ef3a30bc9e769f4fe4399d853861a1ddbefeea8cbf39906c"}, + {file = "pandas-1.0.0-cp36-cp36m-win_amd64.whl", hash = "sha256:ae1ec10e34d22b0f699e38f346381630cae89d5050a2a61315a2be09e3435f99"}, + {file = "pandas-1.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:35d07389efaf3c478d93725a226941c7fc14714814ba77d6d43b2c9e63ef4af5"}, + {file = "pandas-1.0.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:46b0a146e4ba744e350847244767ef297950e9ce02424734b2dd0befd77d9aff"}, + {file = "pandas-1.0.0-cp37-cp37m-win32.whl", hash = "sha256:6d5c2d2a3e42100700bac7fe762c17ba0a04d0355feac04bce74a1aa6c8be164"}, + {file = "pandas-1.0.0-cp37-cp37m-win_amd64.whl", hash = "sha256:f66c63f357ac31c913f4917f55348ce99c639031567c3284f01dff605da58264"}, + {file = "pandas-1.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c36e4d44d34eaa503776a8fb57ba1305e680e178458c050c2fd8de67604fa209"}, + {file = "pandas-1.0.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:66c1a49b47c0953dbc6864a6d2578c4c24610f6bb8e4ab165d49b8371aa7745f"}, + {file = "pandas-1.0.0-cp38-cp38-win32.whl", hash = "sha256:18bbce2e69855d42397486ee0bb79cb0e4c94af6679fd9392e32ffdb7fcfade0"}, + {file = "pandas-1.0.0-cp38-cp38-win_amd64.whl", hash = "sha256:ab1aa2c50b7c6ba0eccebb146b4d80ed7f5804897b8d54ccddbe49f28c881a94"}, + {file = "pandas-1.0.0.tar.gz", hash = "sha256:3ea6cc86931f57f18b1240572216f09922d91b19ab8a01cf24734394a3db3bec"}, +] pandocfilters = [ {file = "pandocfilters-1.4.2.tar.gz", hash = "sha256:b3dd70e169bb5449e6bc6ff96aea89c5eea8c5f6ab5e207fc2f521a2cf4a0da9"}, ] @@ -888,6 +1082,10 @@ python-dateutil = [ {file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"}, {file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"}, ] +pytz = [ + {file = "pytz-2019.3-py2.py3-none-any.whl", hash = "sha256:1c557d7d0e871de1f5ccd5833f60fb2550652da6be2693c1e02300743d21500d"}, + {file = "pytz-2019.3.tar.gz", hash = "sha256:b02c06db6cf09c12dd25137e563b31700d3b80fcc4ad23abb7a315f2789819be"}, +] pywin32 = [ {file = "pywin32-227-cp27-cp27m-win32.whl", hash = "sha256:371fcc39416d736401f0274dd64c2302728c9e034808e37381b5e1b22be4a6b0"}, {file = "pywin32-227-cp27-cp27m-win_amd64.whl", hash = "sha256:4cdad3e84191194ea6d0dd1b1b9bdda574ff563177d2adf2b4efec2a244fa116"}, @@ -914,6 +1112,19 @@ pywinpty = [ {file = "pywinpty-0.5.7-cp38-cp38-win_amd64.whl", hash = "sha256:8fc5019ff3efb4f13708bd3b5ad327589c1a554cb516d792527361525a7cb78c"}, {file = "pywinpty-0.5.7.tar.gz", hash = "sha256:2d7e9c881638a72ffdca3f5417dd1563b60f603e1b43e5895674c2a1b01f95a0"}, ] +pyyaml = [ + {file = "PyYAML-5.3-cp27-cp27m-win32.whl", hash = "sha256:940532b111b1952befd7db542c370887a8611660d2b9becff75d39355303d82d"}, + {file = "PyYAML-5.3-cp27-cp27m-win_amd64.whl", hash = "sha256:059b2ee3194d718896c0ad077dd8c043e5e909d9180f387ce42012662a4946d6"}, + {file = "PyYAML-5.3-cp35-cp35m-win32.whl", hash = "sha256:4fee71aa5bc6ed9d5f116327c04273e25ae31a3020386916905767ec4fc5317e"}, + {file = "PyYAML-5.3-cp35-cp35m-win_amd64.whl", hash = "sha256:dbbb2379c19ed6042e8f11f2a2c66d39cceb8aeace421bfc29d085d93eda3689"}, + {file = "PyYAML-5.3-cp36-cp36m-win32.whl", hash = "sha256:e3a057b7a64f1222b56e47bcff5e4b94c4f61faac04c7c4ecb1985e18caa3994"}, + {file = "PyYAML-5.3-cp36-cp36m-win_amd64.whl", hash = "sha256:74782fbd4d4f87ff04159e986886931456a1894c61229be9eaf4de6f6e44b99e"}, + {file = "PyYAML-5.3-cp37-cp37m-win32.whl", hash = "sha256:24521fa2890642614558b492b473bee0ac1f8057a7263156b02e8b14c88ce6f5"}, + {file = "PyYAML-5.3-cp37-cp37m-win_amd64.whl", hash = "sha256:1cf708e2ac57f3aabc87405f04b86354f66799c8e62c28c5fc5f88b5521b2dbf"}, + {file = "PyYAML-5.3-cp38-cp38-win32.whl", hash = "sha256:70024e02197337533eef7b85b068212420f950319cc8c580261963aefc75f811"}, + {file = "PyYAML-5.3-cp38-cp38-win_amd64.whl", hash = "sha256:cb1f2f5e426dc9f07a7681419fe39cee823bb74f723f36f70399123f439e9b20"}, + {file = "PyYAML-5.3.tar.gz", hash = "sha256:e9f45bd5b92c7974e59bcd2dcc8631a6b6cc380a904725fce7bc08872e691615"}, +] pyzmq = [ {file = "pyzmq-18.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:0573b9790aa26faff33fba40f25763657271d26f64bffb55a957a3d4165d6098"}, {file = "pyzmq-18.1.1-cp27-cp27m-win32.whl", hash = "sha256:972d723a36ab6a60b7806faa5c18aa3c080b7d046c407e816a1d8673989e2485"}, diff --git a/pyproject.toml b/pyproject.toml index c30f700..106e21f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -9,10 +9,12 @@ license = "MIT" python = "^3.7" jupyterlab = "^1.2.6" numpy = "^1.18.1" +pandas = "^1.0.0" [tool.poetry.dev-dependencies] black = "^19.10b0" blackcellmagic = "^0.0.2" +jupyter_contrib_nbextensions = "^0.5.1" RISE = "^5.6.0" [build-system] diff --git a/requirements.txt b/requirements.txt index f9ab033..fe89b09 100644 --- a/requirements.txt +++ b/requirements.txt @@ -8,24 +8,31 @@ Click==7.0 decorator==4.4.1 defusedxml==0.6.0 entrypoints==0.3 -importlib-metadata==1.4.0 +importlib-metadata==1.5.0 ipykernel==5.1.4 -ipython==7.11.1 +ipython==7.12.0 ipython-genutils==0.2.0 jedi==0.16.0 -Jinja2==2.11.0 -json5==0.8.5 +Jinja2==2.11.1 +json5==0.9.0 jsonschema==3.2.0 jupyter-client==5.3.4 +jupyter-contrib-core==0.3.3 +jupyter-contrib-nbextensions==0.5.1 jupyter-core==4.6.1 +jupyter-highlight-selected-word==0.2.0 +jupyter-latex-envs==1.4.6 +jupyter-nbextensions-configurator==0.4.1 jupyterlab==1.2.6 jupyterlab-server==1.0.6 +lxml==4.5.0 MarkupSafe==1.1.1 mistune==0.8.4 nbconvert==5.6.1 nbformat==5.0.4 notebook==6.0.3 numpy==1.18.1 +pandas==1.0.0 pandocfilters==1.4.2 parso==0.6.0 pathspec==0.7.0 @@ -37,6 +44,8 @@ ptyprocess==0.6.0 Pygments==2.5.2 pyrsistent==0.15.7 python-dateutil==2.8.1 +pytz==2019.3 +PyYAML==5.3 pyzmq==18.1.1 regex==2020.1.8 rise==5.6.0 From 86e59b847afa92230f5be8fdf972a01dec891610 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 2 Feb 2020 16:31:31 +0100 Subject: [PATCH 2/8] Restructure *.ipynb files - rename *_content.ipynb into *_lecture.ipynb - adjust links in README.md --- ...content.ipynb => 00_intro_00_lecture.ipynb | 18 +++---- ...0_review.ipynb => 00_intro_01_review.ipynb | 2 +- ...cises.ipynb => 00_intro_02_exercises.ipynb | 2 +- ...tent.ipynb => 01_elements_00_lecture.ipynb | 12 ++--- ...eview.ipynb => 01_elements_01_review.ipynb | 2 +- ...es.ipynb => 01_elements_02_exercises.ipynb | 2 +- ...ent.ipynb => 02_functions_00_lecture.ipynb | 18 +++---- ...view.ipynb => 02_functions_01_review.ipynb | 2 +- ...s.ipynb => 02_functions_02_exercises.ipynb | 2 +- ....ipynb => 03_conditionals_00_lecture.ipynb | 8 +-- ...w.ipynb => 03_conditionals_01_review.ipynb | 2 +- ...pynb => 03_conditionals_02_exercises.ipynb | 4 +- ...ent.ipynb => 04_iteration_00_lecture.ipynb | 14 ++--- ...view.ipynb => 04_iteration_01_review.ipynb | 2 +- ...s.ipynb => 04_iteration_02_exercises.ipynb | 4 +- ...ntent.ipynb => 05_numbers_00_lecture.ipynb | 16 +++--- ...review.ipynb => 05_numbers_01_review.ipynb | 2 +- ...ses.ipynb => 05_numbers_02_exercises.ipynb | 8 +-- ..._content.ipynb => 06_text_00_lecture.ipynb | 24 ++++----- ...10_review.ipynb => 06_text_01_review.ipynb | 2 +- ...ent.ipynb => 07_sequences_00_lecture.ipynb | 36 ++++++------- ...view.ipynb => 07_sequences_01_review.ipynb | 4 +- ...s.ipynb => 07_sequences_02_exercises.ipynb | 16 +++--- ...tent.ipynb => 08_mappings_00_lecture.ipynb | 18 +++---- ...eview.ipynb => 08_mappings_01_review.ipynb | 4 +- ...es.ipynb => 08_mappings_02_exercises.ipynb | 2 +- README.md | 54 +++++++++---------- 27 files changed, 140 insertions(+), 140 deletions(-) rename 00_start_up_00_content.ipynb => 00_intro_00_lecture.ipynb (98%) rename 00_start_up_10_review.ipynb => 00_intro_01_review.ipynb (97%) rename 00_start_up_20_exercises.ipynb => 00_intro_02_exercises.ipynb (95%) rename 01_elements_00_content.ipynb => 01_elements_00_lecture.ipynb (99%) rename 01_elements_10_review.ipynb => 01_elements_01_review.ipynb (98%) rename 01_elements_20_exercises.ipynb => 01_elements_02_exercises.ipynb (97%) rename 02_functions_00_content.ipynb => 02_functions_00_lecture.ipynb (99%) rename 02_functions_10_review.ipynb => 02_functions_01_review.ipynb (98%) rename 02_functions_20_exercises.ipynb => 02_functions_02_exercises.ipynb (98%) rename 03_conditionals_00_content.ipynb => 03_conditionals_00_lecture.ipynb (99%) rename 03_conditionals_10_review.ipynb => 03_conditionals_01_review.ipynb (98%) rename 03_conditionals_20_exercises.ipynb => 03_conditionals_02_exercises.ipynb (98%) rename 04_iteration_00_content.ipynb => 04_iteration_00_lecture.ipynb (99%) rename 04_iteration_10_review.ipynb => 04_iteration_01_review.ipynb (98%) rename 04_iteration_20_exercises.ipynb => 04_iteration_02_exercises.ipynb (99%) rename 05_numbers_00_content.ipynb => 05_numbers_00_lecture.ipynb (99%) rename 05_numbers_10_review.ipynb => 05_numbers_01_review.ipynb (99%) rename 05_numbers_20_exercises.ipynb => 05_numbers_02_exercises.ipynb (97%) rename 06_text_00_content.ipynb => 06_text_00_lecture.ipynb (98%) rename 06_text_10_review.ipynb => 06_text_01_review.ipynb (98%) rename 07_sequences_00_content.ipynb => 07_sequences_00_lecture.ipynb (99%) rename 07_sequences_10_review.ipynb => 07_sequences_01_review.ipynb (98%) rename 07_sequences_20_exercises.ipynb => 07_sequences_02_exercises.ipynb (98%) rename 08_mappings_00_content.ipynb => 08_mappings_00_lecture.ipynb (99%) rename 08_mappings_10_review.ipynb => 08_mappings_01_review.ipynb (96%) rename 08_mappings_20_exercises.ipynb => 08_mappings_02_exercises.ipynb (99%) diff --git a/00_start_up_00_content.ipynb b/00_intro_00_lecture.ipynb similarity index 98% rename from 00_start_up_00_content.ipynb rename to 00_intro_00_lecture.ipynb index 3ca98d4..b812c61 100644 --- a/00_start_up_00_content.ipynb +++ b/00_intro_00_lecture.ipynb @@ -774,11 +774,11 @@ "**Part A: Expressing Logic**\n", "\n", "- What is a programming language? What kind of words exist?\n", - " - *Chapter 1*: [Elements of a Program](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb)\n", - " - *Chapter 2*: [Functions & Modularization](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb)\n", + " - *Chapter 1*: [Elements of a Program](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb)\n", + " - *Chapter 2*: [Functions & Modularization](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb)\n", "- What is the flow of execution? How can we form sentences from words?\n", - " - *Chapter 3*: [Conditionals & Exceptions](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb)\n", - " - *Chapter 4*: [Recursion & Looping](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb)" + " - *Chapter 3*: [Conditionals & Exceptions](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb)\n", + " - *Chapter 4*: [Recursion & Looping](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb)" ] }, { @@ -792,11 +792,11 @@ "**Part B: Managing Data and Memory**\n", "\n", "- How is data stored in memory?\n", - " - *Chapter 5*: [Bits & Numbers](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb)\n", - " - *Chapter 6*: [Bytes & Text](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb)\n", - " - *Chapter 7*: [Sequential Data](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb)\n", - " - *Chapter 8*: [Mappings & Sets](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb)\n", - " - *Chapter 9*: [Arrays & Dataframes](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_content.ipynb)\n", + " - *Chapter 5*: [Bits & Numbers](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb)\n", + " - *Chapter 6*: [Bytes & Text](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb)\n", + " - *Chapter 7*: [Sequential Data](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb)\n", + " - *Chapter 8*: [Mappings & Sets](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb)\n", + " - *Chapter 9*: Arrays & Dataframes\n", "- How can we create custom data types?\n", " - *Chapter 10*: Object-Orientation" ] diff --git a/00_start_up_10_review.ipynb b/00_intro_01_review.ipynb similarity index 97% rename from 00_start_up_10_review.ipynb rename to 00_intro_01_review.ipynb index e8cb215..f08c6ca 100644 --- a/00_start_up_10_review.ipynb +++ b/00_intro_01_review.ipynb @@ -18,7 +18,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { diff --git a/00_start_up_20_exercises.ipynb b/00_intro_02_exercises.ipynb similarity index 95% rename from 00_start_up_20_exercises.ipynb rename to 00_intro_02_exercises.ipynb index afd7f26..3b394db 100644 --- a/00_start_up_20_exercises.ipynb +++ b/00_intro_02_exercises.ipynb @@ -18,7 +18,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up_00_content.ipynb) of the book. Then, work through the exercises below." + "Read [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) of the book. Then, work through the exercises below." ] }, { diff --git a/01_elements_00_content.ipynb b/01_elements_00_lecture.ipynb similarity index 99% rename from 01_elements_00_content.ipynb rename to 01_elements_00_lecture.ipynb index 38b63b1..c627331 100644 --- a/01_elements_00_content.ipynb +++ b/01_elements_00_lecture.ipynb @@ -1082,7 +1082,7 @@ } }, "source": [ - "`a` and `d` indeed have the same value as is checked with the **equality operator** `==`. The resulting `True` (and the `False` further below) is yet another data type, a so-called **boolean**. We look into them closely in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb#Boolean-Expressions)." + "`a` and `d` indeed have the same value as is checked with the **equality operator** `==`. The resulting `True` (and the `False` further below) is yet another data type, a so-called **boolean**. We look into them closely in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#Boolean-Expressions)." ] }, { @@ -1875,7 +1875,7 @@ } }, "source": [ - "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) (= \"length\") [built-in functions](https://docs.python.org/3/library/functions.html) (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone." + "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) (= \"length\") [built-in functions](https://docs.python.org/3/library/functions.html) (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone." ] }, { @@ -2077,7 +2077,7 @@ "\n", "At the same time, for a beginner's course, it is often easier to code linearly.\n", "\n", - "In real data science projects, one would probably employ a mixed approach and put reusable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb#Local-Modules-and-Packages)) and then use Jupyter notebooks to build up a linear report or storyline for a business argument to be made." + "In real data science projects, one would probably employ a mixed approach and put reusable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Local-Modules-and-Packages)) and then use Jupyter notebooks to build up a linear report or storyline for a business argument to be made." ] }, { @@ -2818,7 +2818,7 @@ "source": [ "Let's change the first element of `x`.\n", "\n", - "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as just another operator, called the **indexing operator**. `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object. The indexing operator must be an operator as we merely read the first element and do not change anything in memory.\n", + "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as just another operator, called the **indexing operator**. `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object. The indexing operator must be an operator as we merely read the first element and do not change anything in memory.\n", "\n", "Note how Python **begins counting at 0**. This is not the case for many other languages, for example, [MATLAB](https://en.wikipedia.org/wiki/MATLAB), [R](https://en.wikipedia.org/wiki/R_%28programming_language%29), or [Stata](https://en.wikipedia.org/wiki/Stata). To understand why this makes sense, see this short [note](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) by one of the all-time greats in computer science, the late [Edsger Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)." ] @@ -3727,14 +3727,14 @@ " - ignored by Python\n", "\n", "\n", - "- functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb))\n", + "- functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb))\n", " - named sequences of instructions\n", " - the smaller parts in a larger program\n", " - make a program more modular and thus easier to understand\n", " - include [built-in functions](https://docs.python.org/3/library/functions.html) like [print()](https://docs.python.org/3/library/functions.html#print), [sum()](https://docs.python.org/3/library/functions.html#sum), or [len()](https://docs.python.org/3/library/functions.html#len)\n", "\n", "\n", - "- flow control (cf., [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb))\n", + "- flow control (cf., [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb))\n", " - expression of **business logic** or an **algorithm**\n", " - conditional execution of parts of a program (e.g., `if` statements)\n", " - repetitive execution of parts of a program (e.g., `for`-loops)" diff --git a/01_elements_10_review.ipynb b/01_elements_01_review.ipynb similarity index 98% rename from 01_elements_10_review.ipynb rename to 01_elements_01_review.ipynb index 1c2ee76..0ed455c 100644 --- a/01_elements_10_review.ipynb +++ b/01_elements_01_review.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { diff --git a/01_elements_20_exercises.ipynb b/01_elements_02_exercises.ipynb similarity index 97% rename from 01_elements_20_exercises.ipynb rename to 01_elements_02_exercises.ipynb index e34097c..c7fffb6 100644 --- a/01_elements_20_exercises.ipynb +++ b/01_elements_02_exercises.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb) of the book. Then, work through the exercises below." + "Read [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb) of the book. Then, work through the exercises below." ] }, { diff --git a/02_functions_00_content.ipynb b/02_functions_00_lecture.ipynb similarity index 99% rename from 02_functions_00_content.ipynb rename to 02_functions_00_lecture.ipynb index d0000d8..6dcccec 100644 --- a/02_functions_00_content.ipynb +++ b/02_functions_00_lecture.ipynb @@ -19,7 +19,7 @@ } }, "source": [ - "In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Example:-Averaging-Even-Numbers), we typed the code to calculate the average of the even numbers in a list into several code cells. Then, we executed them one after another. We had no way of **reusing** the code except for either executing cells multiple times or copying and pasting their contents into other cells. And, whenever we find ourselves doing repetitive manual work, we can be sure that there must be a way of automating what we are doing.\n", + "In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Example:-Averaging-Even-Numbers), we typed the code to calculate the average of the even numbers in a list into several code cells. Then, we executed them one after another. We had no way of **reusing** the code except for either executing cells multiple times or copying and pasting their contents into other cells. And, whenever we find ourselves doing repetitive manual work, we can be sure that there must be a way of automating what we are doing.\n", "\n", "At the same time, we executed built-in functions (e.g., [print()](https://docs.python.org/3/library/functions.html#print), [sum()](https://docs.python.org/3/library/functions.html#sum), [len()](https://docs.python.org/3/library/functions.html#len), [id()](https://docs.python.org/3/library/functions.html#id), or [type()](https://docs.python.org/3/library/functions.html#type)) that obviously must be reusing the same parts inside core Python every time we use them.\n", "\n", @@ -45,7 +45,7 @@ } }, "source": [ - "So-called **[user-defined functions](https://docs.python.org/3/reference/compound_stmts.html#function-definitions)** may be created with the `def` statement. To extend an already familiar example, we reuse the introductory example from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Best-Practices) in its final Pythonic version and transform it into the function `average_evens()` below. \n", + "So-called **[user-defined functions](https://docs.python.org/3/reference/compound_stmts.html#function-definitions)** may be created with the `def` statement. To extend an already familiar example, we reuse the introductory example from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Best-Practices) in its final Pythonic version and transform it into the function `average_evens()` below. \n", "\n", "A function's **name** must be chosen according to the same naming rules as ordinary variables as Python manages function names like variables. In this book, we further adopt the convention of ending function names with parentheses `()` in text cells for faster comprehension when reading (i.e., `average_evens()` vs. `average_evens`). These are *not* part of the name but must always be written out in the `def` statement for syntactic reasons.\n", "\n", @@ -57,7 +57,7 @@ "\n", "A function may come with an *explicit* **return value** (i.e., \"result\" or \"output\") specified with the `return` statement (cf., [reference](https://docs.python.org/3/reference/simple_stmts.html#the-return-statement)): Functions that have one are considered **fruitful**; otherwise, they are **void**. Functions of the latter kind are still useful because of their **side effects** as, for example, the built-in [print()](https://docs.python.org/3/library/functions.html#print) function. Strictly speaking, they also have an *implicit* return value of `None`.\n", "\n", - "A function should define a **docstring** that describes what it does in a short subject line, what parameters it expects (i.e., their types), and what it returns (if anything). A docstring is a syntactically valid multi-line string (i.e., type `str`) defined within **triple-double quotes** `\"\"\"`. Strings are covered in depth in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb#The-str-Type). Widely adopted standards as to how to format a docstring are [PEP 257](https://www.python.org/dev/peps/pep-0257/) and section 3.8 in [Google's Python Style Guide](https://github.com/google/styleguide/blob/gh-pages/pyguide.md)." + "A function should define a **docstring** that describes what it does in a short subject line, what parameters it expects (i.e., their types), and what it returns (if anything). A docstring is a syntactically valid multi-line string (i.e., type `str`) defined within **triple-double quotes** `\"\"\"`. Strings are covered in depth in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb#The-str-Type). Widely adopted standards as to how to format a docstring are [PEP 257](https://www.python.org/dev/peps/pep-0257/) and section 3.8 in [Google's Python Style Guide](https://github.com/google/styleguide/blob/gh-pages/pyguide.md)." ] }, { @@ -761,7 +761,7 @@ "source": [ "[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010,%2011,%2012%5D%0A%0Adef%20average_wrong%28numbers%29%3A%0A%20%20%20%20evens%20%3D%20%5Bn%20for%20n%20in%20nums%20if%20n%20%25%202%20%3D%3D%200%5D%0A%20%20%20%20average%20%3D%20sum%28evens%29%20/%20len%28evens%29%0A%20%20%20%20return%20average%0A%0Arv%20%3D%20average_wrong%28%5B123,%20456,%20789%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) is again helpful at visualizing the error interactively: Creating the `list` object `evens` eventually references takes *16* computational steps, namely two for managing the list comprehension, one for setting up an empty `list` object, *twelve* for filling it with elements derived from `nums` in the global scope (i.e., that is the error), and one to make `evens` reference it (cf., steps 6-21).\n", "\n", - "The frames logic shown by PythonTutor is the mechanism by which Python not only manages the names inside *one* function call but also for *many* potentially *simultaneous* calls, as revealed in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Trivial-Example:-Countdown). It is the reason why we may reuse the same names for the parameters and variables inside both `average_evens()` and `average_wrong()` without Python mixing them up. So, as we already read in the [Zen of Python](https://www.python.org/dev/peps/pep-0020/), \"namespaces are one honking great idea\" (cf., `import this`), and a frame is just a special kind of namespace." + "The frames logic shown by PythonTutor is the mechanism by which Python not only manages the names inside *one* function call but also for *many* potentially *simultaneous* calls, as revealed in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Trivial-Example:-Countdown). It is the reason why we may reuse the same names for the parameters and variables inside both `average_evens()` and `average_wrong()` without Python mixing them up. So, as we already read in the [Zen of Python](https://www.python.org/dev/peps/pep-0020/), \"namespaces are one honking great idea\" (cf., `import this`), and a frame is just a special kind of namespace." ] }, { @@ -1274,7 +1274,7 @@ } }, "source": [ - "So far, we have only specified one parameter in each of our user-defined functions. In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#%28Arithmetic%29-Operators), however, we saw the built-in function [divmod()](https://docs.python.org/3/library/functions.html#divmod) take two arguments. And, the order of the numbers passed in mattered! Whenever we call a function and list its arguments in a comma separated manner, we say that we pass in the arguments by position or refer to them as **positional arguments**." + "So far, we have only specified one parameter in each of our user-defined functions. In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Arithmetic%29-Operators), however, we saw the built-in function [divmod()](https://docs.python.org/3/library/functions.html#divmod) take two arguments. And, the order of the numbers passed in mattered! Whenever we call a function and list its arguments in a comma separated manner, we say that we pass in the arguments by position or refer to them as **positional arguments**." ] }, { @@ -2055,7 +2055,7 @@ "source": [ "The main point of having functions without a name is to use them in a situation where we know ahead of time that we use the function only *once*.\n", "\n", - "Popular applications of lambda expressions occur in combination with the **map-filter-reduce** paradigm or when we do \"number crunching\" with **arrays** and **data frames**. We look at both in detail in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb)." + "Popular applications of lambda expressions occur in combination with the **map-filter-reduce** paradigm or when we do \"number crunching\" with **arrays** and **data frames**. We look at both in detail in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb)." ] }, { @@ -2470,7 +2470,7 @@ "source": [ "Observe how the arguments passed to functions do not need to be just variables or simple literals. Instead, we may pass in any *expression* that evaluates to a *new* object of the type the function expects.\n", "\n", - "So just as a reminder from the expression vs. statement discussion in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Expressions): An expression is *any* syntactically correct combination of variables and literals with operators. And the call operator `()` is yet another operator. So both of the next two code cells are just expressions! They have no permanent side effects in memory. We may execute them as often as we want *without* changing the state of the program (i.e., this Jupyter notebook).\n", + "So just as a reminder from the expression vs. statement discussion in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Expressions): An expression is *any* syntactically correct combination of variables and literals with operators. And the call operator `()` is yet another operator. So both of the next two code cells are just expressions! They have no permanent side effects in memory. We may execute them as often as we want *without* changing the state of the program (i.e., this Jupyter notebook).\n", "\n", "So, regarding the very next cell in particular: Although the `2 ** 2` creates a *new* object `4` in memory that is then immediately passed into the [math.sqrt()](https://docs.python.org/3/library/math.html#math.sqrt) function, once that function call returns, \"all is lost\" and the newly created `4` object is forgotten again, as well as the return value of [math.sqrt()](https://docs.python.org/3/library/math.html#math.sqrt)." ] @@ -3041,9 +3041,9 @@ } }, "source": [ - "[numpy](http://www.numpy.org/) is the de-facto standard in the Python world for handling **array-like** data. That is a fancy word for data that can be put into a matrix or vector format. We look at it in depth in [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_content.ipynb).\n", + "[numpy](http://www.numpy.org/) is the de-facto standard in the Python world for handling **array-like** data. That is a fancy word for data that can be put into a matrix or vector format. We look at it in depth in [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_lecture.ipynb).\n", "\n", - "As [numpy](http://www.numpy.org/) is *not* in the [standard library](https://docs.python.org/3/library/index.html), it must be *manually* installed, for example, with the [pip](https://pip.pypa.io/en/stable/) tool. As mentioned in [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up_00_content.ipynb#Markdown-vs.-Code-Cells), to execute terminal commands from within a Jupyter notebook, we start a code cell with an exclamation mark.\n", + "As [numpy](http://www.numpy.org/) is *not* in the [standard library](https://docs.python.org/3/library/index.html), it must be *manually* installed, for example, with the [pip](https://pip.pypa.io/en/stable/) tool. As mentioned in [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb#Markdown-vs.-Code-Cells), to execute terminal commands from within a Jupyter notebook, we start a code cell with an exclamation mark.\n", "\n", "If you are running this notebook with an installation of the [Anaconda Distribution](https://www.anaconda.com/distribution/), then [numpy](http://www.numpy.org/) is probably already installed. Running the cell below confirms that." ] diff --git a/02_functions_10_review.ipynb b/02_functions_01_review.ipynb similarity index 98% rename from 02_functions_10_review.ipynb rename to 02_functions_01_review.ipynb index a320a3d..f0e4772 100644 --- a/02_functions_10_review.ipynb +++ b/02_functions_01_review.ipynb @@ -18,7 +18,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { diff --git a/02_functions_20_exercises.ipynb b/02_functions_02_exercises.ipynb similarity index 98% rename from 02_functions_20_exercises.ipynb rename to 02_functions_02_exercises.ipynb index 0f449e4..a17b45b 100644 --- a/02_functions_20_exercises.ipynb +++ b/02_functions_02_exercises.ipynb @@ -18,7 +18,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb) of the book. Then, work through the exercises below." + "Read [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) of the book. Then, work through the exercises below." ] }, { diff --git a/03_conditionals_00_content.ipynb b/03_conditionals_00_lecture.ipynb similarity index 99% rename from 03_conditionals_00_content.ipynb rename to 03_conditionals_00_lecture.ipynb index a9113a3..a6902df 100644 --- a/03_conditionals_00_content.ipynb +++ b/03_conditionals_00_lecture.ipynb @@ -19,7 +19,7 @@ } }, "source": [ - "We analyzed every aspect of the `average_evens()` function in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb) except for the `if`-related parts. While it seems to do what we expect it to, there is a whole lot more we learn from taking it apart. In particular, the `if` may occur within both a **statement** or an **expression**, analogous as to how a noun in a natural language is *either* the subject of *or* an object in a sentence. What is common to both usages is that it leads to code being executed for *parts* of the input only. It is our first way of **controlling** the **flow of execution** in a program.\n", + "We analyzed every aspect of the `average_evens()` function in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) except for the `if`-related parts. While it seems to do what we expect it to, there is a whole lot more we learn from taking it apart. In particular, the `if` may occur within both a **statement** or an **expression**, analogous as to how a noun in a natural language is *either* the subject of *or* an object in a sentence. What is common to both usages is that it leads to code being executed for *parts* of the input only. It is our first way of **controlling** the **flow of execution** in a program.\n", "\n", "After deconstructing `if` in the first part of this chapter, we take a close look at a similar concept, namely handling **exceptions**." ] @@ -139,7 +139,7 @@ } }, "source": [ - "There are, however, cases where even well-behaved Python does not make us happy. [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb#Imprecision) provides more insights into this \"bug.\"" + "There are, however, cases where even well-behaved Python does not make us happy. [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#Imprecision) provides more insights into this \"bug.\"" ] }, { @@ -281,7 +281,7 @@ } }, "source": [ - "Let's not confuse the boolean `False` with `None`, another built-in object! We saw the latter before in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb#Function-Definition) as the *implicit* return value of a function without a `return` statement.\n", + "Let's not confuse the boolean `False` with `None`, another built-in object! We saw the latter before in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Function-Definition) as the *implicit* return value of a function without a `return` statement.\n", "\n", "We might think of `None` in a boolean context indicating a \"maybe\" or even an \"unknown\" answer; however, for Python, there are no \"maybe\" or \"unknown\" objects, as we see further below!\n", "\n", @@ -357,7 +357,7 @@ } }, "source": [ - "`True`, `False`, and `None` have the property that they each exist in memory only *once*. Objects designed this way are so-called **singletons**. This **[design pattern](https://en.wikipedia.org/wiki/Design_Patterns)** was originally developed to keep a program's memory usage at a minimum. It may only be employed in situations where we know that an object does *not* mutate its value (i.e., to reuse the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Objects-vs.-Types-vs.-Values), no flipping of $0$s and $1$s in the bag is allowed). In languages \"closer\" to the memory like C, we would have to code this singleton logic ourselves, but Python has this built in for *some* types.\n", + "`True`, `False`, and `None` have the property that they each exist in memory only *once*. Objects designed this way are so-called **singletons**. This **[design pattern](https://en.wikipedia.org/wiki/Design_Patterns)** was originally developed to keep a program's memory usage at a minimum. It may only be employed in situations where we know that an object does *not* mutate its value (i.e., to reuse the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Objects-vs.-Types-vs.-Values), no flipping of $0$s and $1$s in the bag is allowed). In languages \"closer\" to the memory like C, we would have to code this singleton logic ourselves, but Python has this built in for *some* types.\n", "\n", "We verify this with either the `is` operator or by comparing memory addresses." ] diff --git a/03_conditionals_10_review.ipynb b/03_conditionals_01_review.ipynb similarity index 98% rename from 03_conditionals_10_review.ipynb rename to 03_conditionals_01_review.ipynb index de1a419..cd56223 100644 --- a/03_conditionals_10_review.ipynb +++ b/03_conditionals_01_review.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { diff --git a/03_conditionals_20_exercises.ipynb b/03_conditionals_02_exercises.ipynb similarity index 98% rename from 03_conditionals_20_exercises.ipynb rename to 03_conditionals_02_exercises.ipynb index 23692a3..650b063 100644 --- a/03_conditionals_20_exercises.ipynb +++ b/03_conditionals_02_exercises.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb) of the book. Then, work through the exercises below." + "Read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) of the book. Then, work through the exercises below." ] }, { @@ -184,7 +184,7 @@ "source": [ "**Q2.2**: Loop over the `numbers` list and replace numbers for which one of the two (or both) conditions apply with text strings `\"Fizz\"`, `\"Buzz\"`, or `\"FizzBuzz\"` using the indexing operator `[]` and the assignment statement `=`.\n", "\n", - "In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb), we saw that Python starts indexing with `0` as the first element. Keep that in mind.\n", + "In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb), we saw that Python starts indexing with `0` as the first element. Keep that in mind.\n", "\n", "So in each iteration of the `for`-loop, you have to determine an `index` variable as well as check the actual `number` for its divisors.\n", "\n", diff --git a/04_iteration_00_content.ipynb b/04_iteration_00_lecture.ipynb similarity index 99% rename from 04_iteration_00_content.ipynb rename to 04_iteration_00_lecture.ipynb index ba6467d..0c95c8a 100644 --- a/04_iteration_00_content.ipynb +++ b/04_iteration_00_lecture.ipynb @@ -841,7 +841,7 @@ "\n", "To understand this in detail, we have to study algorithms and data structures (e.g., with [this book](https://www.amazon.de/Introduction-Algorithms-Press-Thomas-Cormen/dp/0262033844/ref=sr_1_1?__mk_de_DE=%C3%85M%C3%85%C5%BD%C3%95%C3%91&crid=1JNE8U0VZGU0O&qid=1569837169&s=gateway&sprefix=algorithms+an%2Caps%2C180&sr=8-1)), a discipline within computer science, and dive into the analysis of **[time complexity of algorithms](https://en.wikipedia.org/wiki/Time_complexity)**.\n", "\n", - "Luckily, in the Fibonacci case, the inefficiency can be resolved with a **caching** (i.e., \"reuse\") strategy from the field of **[dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming)**, namely **[memoization](https://en.wikipedia.org/wiki/Memoization)**. We do so in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb#Memoization), after introducing the `dict` data type.\n", + "Luckily, in the Fibonacci case, the inefficiency can be resolved with a **caching** (i.e., \"reuse\") strategy from the field of **[dynamic programming](https://en.wikipedia.org/wiki/Dynamic_programming)**, namely **[memoization](https://en.wikipedia.org/wiki/Memoization)**. We do so in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb#Memoization), after introducing the `dict` data type.\n", "\n", "Let's measure the average run times for `fibonacci()` and varying `i` arguments with the `%%timeit` [cell magic](https://ipython.readthedocs.io/en/stable/interactive/magics.html#magic-timeit) that comes with Jupyter." ] @@ -4877,7 +4877,7 @@ } }, "source": [ - "For sequences of integers, the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in makes the `for` statement even more convenient: It creates a `list`-like object of type `range` that generates integers \"on the fly,\" and we look closely at the underlying effects in memory in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Mapping)." + "For sequences of integers, the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in makes the `for` statement even more convenient: It creates a `list`-like object of type `range` that generates integers \"on the fly,\" and we look closely at the underlying effects in memory in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Mapping)." ] }, { @@ -5008,11 +5008,11 @@ "\n", "Now, just as we classify objects by data type, we also classify these data types (e.g., `int`, `float`, `str`, or `list`) into **abstract concepts**.\n", "\n", - "We did this already in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Who-am-I?-And-how-many?) when we described a `list` object as \"some sort of container that holds [...] references to other objects\". So, abstractly speaking, **containers** are any objects that are \"composed\" of other objects and also \"manage\" how these objects are organized. `list` objects, for example, have the property that they model an order associated with their elements. There exist, however, other container types, many of which do *not* come with an order. So, containers primarily \"contain\" other objects and have *nothing* to do with looping.\n", + "We did this already in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Who-am-I?-And-how-many?) when we described a `list` object as \"some sort of container that holds [...] references to other objects\". So, abstractly speaking, **containers** are any objects that are \"composed\" of other objects and also \"manage\" how these objects are organized. `list` objects, for example, have the property that they model an order associated with their elements. There exist, however, other container types, many of which do *not* come with an order. So, containers primarily \"contain\" other objects and have *nothing* to do with looping.\n", "\n", "On the contrary, the abstract concept of **iterables** is all about looping: Any object that we can loop over is, by definition, an iterable. So, `range` objects, for example, are iterables, even though they hold no references to other objects. Moreover, looping does *not* have to occur in a *predictable* order, although this is the case for both `list` and `range` objects.\n", "\n", - "Typically, containers are iterables, and iterables are containers. Yet, only because these two concepts coincide often, we must not think of them as the same. In [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Collections-vs.-Sequences), we formalize these two concepts and introduce many more. Finally, Chapter 10 gives an explanation how abstract concepts are implemented and play together.\n", + "Typically, containers are iterables, and iterables are containers. Yet, only because these two concepts coincide often, we must not think of them as the same. In [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Collections-vs.-Sequences), we formalize these two concepts and introduce many more. Finally, Chapter 10 gives an explanation how abstract concepts are implemented and play together.\n", "\n", "Let's continue with `first_names` below as an example an illustrate what iterable containers are." ] @@ -5867,7 +5867,7 @@ } }, "source": [ - "Often, we process some iterable with numeric data, for example, a list of `numbers` as in this book's introductory example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Example:-Averaging-Even-Numbers) or, more realistically, data from a CSV file with many rows and columns.\n", + "Often, we process some iterable with numeric data, for example, a list of `numbers` as in this book's introductory example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Example:-Averaging-Even-Numbers) or, more realistically, data from a CSV file with many rows and columns.\n", "\n", "Processing numeric data usually comes down to operations that may be grouped into one of the following three categories:\n", "\n", @@ -5875,7 +5875,7 @@ "- **filtering**: throw away individual numbers (e.g., statistical outliers in a sample)\n", "- **reducing**: collect individual numbers into summary statistics\n", "\n", - "We study this **map-filter-reduce** paradigm extensively in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#The-Map-Filter-Reduce-Paradigm) after introducing more advanced data types that are needed to work with \"big\" data.\n", + "We study this **map-filter-reduce** paradigm extensively in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#The-Map-Filter-Reduce-Paradigm) after introducing more advanced data types that are needed to work with \"big\" data.\n", "\n", "Here, we focus on *filtering out* some numbers with a `for`-loop." ] @@ -6074,7 +6074,7 @@ } }, "source": [ - "With already three levels of indentation, less horizontal space is available for the actual code block. Of course, one could flatten the two `if` statements with the logical `and` operator, as shown in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb#The-if-Statement). Then, however, we trade off horizontal space against a more \"complex\" `if` logic, and this is *not* a real improvement.\n", + "With already three levels of indentation, less horizontal space is available for the actual code block. Of course, one could flatten the two `if` statements with the logical `and` operator, as shown in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#The-if-Statement). Then, however, we trade off horizontal space against a more \"complex\" `if` logic, and this is *not* a real improvement.\n", "\n", "A Pythonista would instead make use of the `continue` statement (cf., [reference](https://docs.python.org/3/reference/simple_stmts.html#the-continue-statement)) that causes a loop to jump into the next iteration skipping the rest of the code block.\n", "\n", diff --git a/04_iteration_10_review.ipynb b/04_iteration_01_review.ipynb similarity index 98% rename from 04_iteration_10_review.ipynb rename to 04_iteration_01_review.ipynb index 808e309..29c1f2f 100644 --- a/04_iteration_10_review.ipynb +++ b/04_iteration_01_review.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { diff --git a/04_iteration_20_exercises.ipynb b/04_iteration_02_exercises.ipynb similarity index 99% rename from 04_iteration_20_exercises.ipynb rename to 04_iteration_02_exercises.ipynb index 81f6928..5858e2d 100644 --- a/04_iteration_20_exercises.ipynb +++ b/04_iteration_02_exercises.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb) of the book. Then, work through the exercises below." + "Read [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) of the book. Then, work through the exercises below." ] }, { @@ -411,7 +411,7 @@ "\n", "In such cases, we could modify a recursive function to return a count value to be passed up the recursion tree.\n", "\n", - "This is similar to what we do in the recursive versions of `factorial()` and `fibonacci()` in [Chapter 4](https://github.com/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb), where we pass up an intermediate result.\n", + "This is similar to what we do in the recursive versions of `factorial()` and `fibonacci()` in [Chapter 4](https://github.com/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb), where we pass up an intermediate result.\n", "\n", "Let's create a `hanoi_moves()` function that follows the same internal logic as `hanoi()`, but, instead of printing out the moves, returns the number of steps done so far in the recursion.\n", "\n", diff --git a/05_numbers_00_content.ipynb b/05_numbers_00_lecture.ipynb similarity index 99% rename from 05_numbers_00_content.ipynb rename to 05_numbers_00_lecture.ipynb index 1f7ebc2..531de04 100644 --- a/05_numbers_00_content.ipynb +++ b/05_numbers_00_lecture.ipynb @@ -21,15 +21,15 @@ "source": [ "After learning about the basic building blocks of expressing and structuring the business logic in programs, we focus our attention on the **data types** Python offers us, both built-in and available via the [standard library](https://docs.python.org/3/library/index.html) or third-party packages.\n", "\n", - "We start with the \"simple\" ones: Numeric types in this chapter and textual data in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb). An important fact that holds for all objects of these types is that they are **immutable**. To reuse the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Objects-vs.-Types-vs.-Values), this means that the $0$s and $1$s making up an object's *value* cannot be changed once the bag is created in memory, implying that any operation with or method on the object creates a *new* object in a *different* memory location.\n", + "We start with the \"simple\" ones: Numeric types in this chapter and textual data in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb). An important fact that holds for all objects of these types is that they are **immutable**. To reuse the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Objects-vs.-Types-vs.-Values), this means that the $0$s and $1$s making up an object's *value* cannot be changed once the bag is created in memory, implying that any operation with or method on the object creates a *new* object in a *different* memory location.\n", "\n", - "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb), [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_content.ipynb) then cover the more \"complex\" data types, including, for example, the `list` type. Finally, Chapter 10 completes the picture by introducing language constructs to create custom types.\n", + "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb), [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_lecture.ipynb) then cover the more \"complex\" data types, including, for example, the `list` type. Finally, Chapter 10 completes the picture by introducing language constructs to create custom types.\n", "\n", "We have already seen many hints indicating that numbers are not as trivial to work with as it seems at first sight:\n", "\n", - "- [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#%28Data%29-Type-%2F-%22Behavior%22) reveals that numbers may come in *different* data types (i.e., `int` vs. `float` so far),\n", - "- [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb#Boolean-Expressions) raises questions regarding the **limited precision** of `float` numbers (e.g., `42 == 42.000000000000001` evaluates to `True`), and\n", - "- [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Infinite-Recursion) shows that sometimes a `float` \"walks\" and \"quacks\" like an `int`, whereas the reverse is true in other cases.\n", + "- [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Data%29-Type-%2F-%22Behavior%22) reveals that numbers may come in *different* data types (i.e., `int` vs. `float` so far),\n", + "- [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#Boolean-Expressions) raises questions regarding the **limited precision** of `float` numbers (e.g., `42 == 42.000000000000001` evaluates to `True`), and\n", + "- [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Infinite-Recursion) shows that sometimes a `float` \"walks\" and \"quacks\" like an `int`, whereas the reverse is true in other cases.\n", "\n", "This chapter introduces all the [built-in numeric types](https://docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex): `int`, `float`, and `complex`. To mitigate the limited precision of floating-point numbers, we also look at two replacements for the `float` type in the [standard library](https://docs.python.org/3/library/index.html), namely the `Decimal` type in the [decimals](https://docs.python.org/3/library/decimal.html#decimal.Decimal) and the `Fraction` type in the [fractions](https://docs.python.org/3/library/fractions.html#fractions.Fraction) module." ] @@ -53,7 +53,7 @@ } }, "source": [ - "The simplest numeric type is the `int` type: It behaves like an [integer in ordinary math](https://en.wikipedia.org/wiki/Integer) (i.e., the set $\\mathbb{Z}$) and supports operators in the way we saw in the section on arithmetic operators in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#%28Arithmetic%29-Operators)." + "The simplest numeric type is the `int` type: It behaves like an [integer in ordinary math](https://en.wikipedia.org/wiki/Integer) (i.e., the set $\\mathbb{Z}$) and supports operators in the way we saw in the section on arithmetic operators in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Arithmetic%29-Operators)." ] }, { @@ -3924,7 +3924,7 @@ } }, "source": [ - "As seen in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#%28Data%29-Type-%2F-%22Behavior%22), the [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) method tells us if a `float` can be casted as an `int` object without any loss in precision." + "As seen in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Data%29-Type-%2F-%22Behavior%22), the [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) method tells us if a `float` can be casted as an `int` object without any loss in precision." ] }, { @@ -6111,7 +6111,7 @@ } }, "source": [ - "Analogous to the discussion of *containers* and *iterables* in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Containers-vs.-Iterables), we contrast the *concrete* numeric data types in this chapter with the *abstract* ideas behind [numbers in mathematics](https://en.wikipedia.org/wiki/Number).\n", + "Analogous to the discussion of *containers* and *iterables* in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Containers-vs.-Iterables), we contrast the *concrete* numeric data types in this chapter with the *abstract* ideas behind [numbers in mathematics](https://en.wikipedia.org/wiki/Number).\n", "\n", "The figure below summarizes five *major* sets of [numbers in mathematics](https://en.wikipedia.org/wiki/Number) as we know them from high school:\n", "\n", diff --git a/05_numbers_10_review.ipynb b/05_numbers_01_review.ipynb similarity index 99% rename from 05_numbers_10_review.ipynb rename to 05_numbers_01_review.ipynb index 819d668..01d88fe 100644 --- a/05_numbers_10_review.ipynb +++ b/05_numbers_01_review.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { diff --git a/05_numbers_20_exercises.ipynb b/05_numbers_02_exercises.ipynb similarity index 97% rename from 05_numbers_20_exercises.ipynb rename to 05_numbers_02_exercises.ipynb index d00ef2e..ab2499d 100644 --- a/05_numbers_20_exercises.ipynb +++ b/05_numbers_02_exercises.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb) of the book. Then, work through the exercises below." + "Read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) of the book. Then, work through the exercises below." ] }, { @@ -33,13 +33,13 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1** in [Chapter 2's Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_20_exercises.ipynb#Volume-of-a-Sphere) section already revealed that we must consider the effects of the `float` type's imprecision.\n", + "**Q1** in [Chapter 2's Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_02_exercises.ipynb#Volume-of-a-Sphere) section already revealed that we must consider the effects of the `float` type's imprecision.\n", "\n", "This becomes even more important when we deal with numeric data modeling accounting or finance data (cf., [this comment](https://stackoverflow.com/a/24976426) on \"falsehoods programmers believe about money\").\n", "\n", "In addition to the *inherent imprecision* of numbers in general, the topic of **[rounding numbers](https://en.wikipedia.org/wiki/Rounding)** is also not as trivial as we might expect! [This article](https://realpython.com/python-rounding/) summarizes everything the data science practitioner needs to know.\n", "\n", - "In this exercise, we revisit **Q1** from [Chapter 3's Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_20_exercises.ipynb#Discounting-Customer-Orders) section, and make the `discounted_price()` function work *correctly* for real-life sales data." + "In this exercise, we revisit **Q1** from [Chapter 3's Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_02_exercises.ipynb#Discounting-Customer-Orders) section, and make the `discounted_price()` function work *correctly* for real-life sales data." ] }, { @@ -225,7 +225,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1.7**: Rewrite the function `discounted_price()` from [Chapter 3's Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_20_exercises.ipynb#Discounting-Customer-Orders) section!\n", + "**Q1.7**: Rewrite the function `discounted_price()` from [Chapter 3's Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_02_exercises.ipynb#Discounting-Customer-Orders) section!\n", "\n", "It takes the *positional* arguments `unit_price` and `quantity` and implements a discount scheme for a line item in a customer order as follows:\n", "\n", diff --git a/06_text_00_content.ipynb b/06_text_00_lecture.ipynb similarity index 98% rename from 06_text_00_content.ipynb rename to 06_text_00_lecture.ipynb index 912142e..d1bbc91 100644 --- a/06_text_00_content.ipynb +++ b/06_text_00_lecture.ipynb @@ -124,7 +124,7 @@ } }, "source": [ - "A `str` object evaluates to itself in a literal notation with enclosing **single quotes** `'` by default. In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Value), we already specified the double quotes `\"` convention we stick to in this book. Yet, single quotes `'` and double quotes `\"` are *perfect* substitutes for all `str` objects that do *not* contain any of the two symbols in it. We could use the reverse convention, as well.\n", + "A `str` object evaluates to itself in a literal notation with enclosing **single quotes** `'` by default. In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Value), we already specified the double quotes `\"` convention we stick to in this book. Yet, single quotes `'` and double quotes `\"` are *perfect* substitutes for all `str` objects that do *not* contain any of the two symbols in it. We could use the reverse convention, as well.\n", "\n", "As [this discussion](https://stackoverflow.com/questions/56011/single-quotes-vs-double-quotes-in-python) shows, many programmers have *strong* opinions about that and make up *new* conventions for their projects. Consequently, the discussion was \"closed as not constructive\" by the moderators." ] @@ -161,7 +161,7 @@ } }, "source": [ - "As the single quote `'` is often used in the English language as a shortener, we could make an argument in favor of using the double quotes `\"`: There are possibly fewer situations like in the two code cells below, in which we must revert to using a `\\` to **escape** a single quote `'` in a text (cf., the [Special Characters](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb#Special-Characters) section further below). However, double quotes `\"` are often used as well. So, this argument is somewhat not convincing.\n", + "As the single quote `'` is often used in the English language as a shortener, we could make an argument in favor of using the double quotes `\"`: There are possibly fewer situations like in the two code cells below, in which we must revert to using a `\\` to **escape** a single quote `'` in a text (cf., the [Special Characters](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb#Special-Characters) section further below). However, double quotes `\"` are often used as well. So, this argument is somewhat not convincing.\n", "\n", "Many proponents of the single quote `'` usage claim that double quotes `\"` make more **visual noise** on the screen. This argument is also not convincing. On the contrary, one could claim that *two* single quotes `''` look so similar to *one* double quote `\"` that it might not be apparent right away what we are looking at. By sticking to double quotes `\"`, we avoid such danger of confusion.\n", "\n", @@ -615,7 +615,7 @@ } }, "source": [ - "To use constructs familiar from [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb#The-try-Statement) to explain what `with open(...) as file:` does, below is a formulation with a `try` statement *equivalent* to the `with` statement above. The `finally`-branch is *always* executed, even if an exception is raised in the `for`-loop. So, `file` is sure to be closed too, with a somewhat less expressive formulation." + "To use constructs familiar from [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#The-try-Statement) to explain what `with open(...) as file:` does, below is a formulation with a `try` statement *equivalent* to the `with` statement above. The `finally`-branch is *always* executed, even if an exception is raised in the `for`-loop. So, `file` is sure to be closed too, with a somewhat less expressive formulation." ] }, { @@ -737,7 +737,7 @@ } }, "source": [ - "A **sequence** is yet another *abstract* concept (cf., the \"*Containers vs. Iterables*\" section in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Containers-vs.-Iterables)).\n", + "A **sequence** is yet another *abstract* concept (cf., the \"*Containers vs. Iterables*\" section in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Containers-vs.-Iterables)).\n", "\n", "It unifies *four* [orthogonal](https://en.wikipedia.org/wiki/Orthogonality) (i.e., \"independent\") behaviors into one idea: Any data type, such as `str`, is considered a sequence if it simultaneously\n", "\n", @@ -746,9 +746,9 @@ "3. comes with a *predictable* **order** of its\n", "4. **finite** number of \"things.\"\n", "\n", - "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Collections-vs.-Sequences) formalizes sequences in great detail. Here, we keep our focus on the `str` type that historically received its name as it models a \"**[string of characters](https://en.wikipedia.org/wiki/String_%28computer_science%29)**,\" and a \"string\" is more formally called a sequence in the computer science literature.\n", + "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Collections-vs.-Sequences) formalizes sequences in great detail. Here, we keep our focus on the `str` type that historically received its name as it models a \"**[string of characters](https://en.wikipedia.org/wiki/String_%28computer_science%29)**,\" and a \"string\" is more formally called a sequence in the computer science literature.\n", "\n", - "Behaving like a sequence, `str` objects may be treated like `list` objects in many cases. For example, the built-in [len()](https://docs.python.org/3/library/functions.html#len) function tells us how many elements (i.e., characters) make up `text`. [len()](https://docs.python.org/3/library/functions.html#len) would not work with an *infinite* object: As anything modeled in a program must fit into a computer's finite memory at runtime, there cannot exist objects containing a truly infinite number of elements; however, [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Iterators-vs.-Iterables) introduces iterable data types that can be used to model an *infinite* series of elements and that, consequently, have no concept of \"length.\"" + "Behaving like a sequence, `str` objects may be treated like `list` objects in many cases. For example, the built-in [len()](https://docs.python.org/3/library/functions.html#len) function tells us how many elements (i.e., characters) make up `text`. [len()](https://docs.python.org/3/library/functions.html#len) would not work with an *infinite* object: As anything modeled in a program must fit into a computer's finite memory at runtime, there cannot exist objects containing a truly infinite number of elements; however, [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Iterators-vs.-Iterables) introduces iterable data types that can be used to model an *infinite* series of elements and that, consequently, have no concept of \"length.\"" ] }, { @@ -912,7 +912,7 @@ } }, "source": [ - "As `str` objects have the additional property of being *ordered*, we may **index** into them to obtain individual characters with the **indexing operator** `[]`. This is analogous to how we obtained individual elements of a `list` object in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Who-am-I?-And-how-many?)." + "As `str` objects have the additional property of being *ordered*, we may **index** into them to obtain individual characters with the **indexing operator** `[]`. This is analogous to how we obtained individual elements of a `list` object in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Who-am-I?-And-how-many?)." ] }, { @@ -1518,9 +1518,9 @@ } }, "source": [ - "Whereas elements of a `list` object *may* be *re-assigned*, as shortly hinted at in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Who-am-I?-And-how-many?), this is *not* allowed for `str` objects. Once created, they *cannot* be *changed*. Formally, we say that they are **immutable**. In that regard, `str` objects and all the numeric types in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb) are alike.\n", + "Whereas elements of a `list` object *may* be *re-assigned*, as shortly hinted at in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Who-am-I?-And-how-many?), this is *not* allowed for `str` objects. Once created, they *cannot* be *changed*. Formally, we say that they are **immutable**. In that regard, `str` objects and all the numeric types in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) are alike.\n", "\n", - "On the contrary, objects that may be changed after creation, are called **mutable**. We already saw in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Who-am-I?-And-how-many?) how mutable objects are more difficult to reason about for a beginner, in particular, if more than *one* variable references it. Yet, mutability does have its place in a programmer's toolbox, and we revisit this idea in the next chapters.\n", + "On the contrary, objects that may be changed after creation, are called **mutable**. We already saw in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Who-am-I?-And-how-many?) how mutable objects are more difficult to reason about for a beginner, in particular, if more than *one* variable references it. Yet, mutability does have its place in a programmer's toolbox, and we revisit this idea in the next chapters.\n", "\n", "The `TypeError` indicates that `str` objects are *immutable*: Assignment to an index or a slice are *not* supported." ] @@ -2217,7 +2217,7 @@ } }, "source": [ - "As mentioned in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Operator-Overloading), the `+` and `*` operators are *overloaded* and used for **string concatenation**. They always create *new* `str` objects. That has nothing to do with the `str` type's immutability, but is the default behavior of operators." + "As mentioned in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Operator-Overloading), the `+` and `*` operators are *overloaded* and used for **string concatenation**. They always create *new* `str` objects. That has nothing to do with the `str` type's immutability, but is the default behavior of operators." ] }, { @@ -2775,7 +2775,7 @@ } }, "source": [ - "The `%` operator that we saw in the context of modulo division in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#%28Arithmetic%29-Operators) is overloaded with string interpolation when its first operand is a `str` object. The second operand consists of all expressions to be filled in. Format specifiers work with a `%` instead of curly braces and according to a different set of rules referred to as **[printf-style string formatting](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting)**. So, `{:.2f}` becomes `%.2f`.\n", + "The `%` operator that we saw in the context of modulo division in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#%28Arithmetic%29-Operators) is overloaded with string interpolation when its first operand is a `str` object. The second operand consists of all expressions to be filled in. Format specifiers work with a `%` instead of curly braces and according to a different set of rules referred to as **[printf-style string formatting](https://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting)**. So, `{:.2f}` becomes `%.2f`.\n", "\n", "This way of string interpolation is the oldest and originates from the [C language](https://en.wikipedia.org/wiki/C_%28programming_language%29). It is still widely spread, but we should use one of the other two ways instead. We show it here mainly for completeness sake." ] @@ -2812,7 +2812,7 @@ } }, "source": [ - "To insert more than one expression, we must list them in order and between parenthesis `(` and `)`. As [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#The-tuple-Type) reveals, this literal syntax creates an object of type `tuple`. Also, to format an expression as text, we use the format specifier `%s`." + "To insert more than one expression, we must list them in order and between parenthesis `(` and `)`. As [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#The-tuple-Type) reveals, this literal syntax creates an object of type `tuple`. Also, to format an expression as text, we use the format specifier `%s`." ] }, { diff --git a/06_text_10_review.ipynb b/06_text_01_review.ipynb similarity index 98% rename from 06_text_10_review.ipynb rename to 06_text_01_review.ipynb index fe9588e..d92bd12 100644 --- a/06_text_10_review.ipynb +++ b/06_text_01_review.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { diff --git a/07_sequences_00_content.ipynb b/07_sequences_00_lecture.ipynb similarity index 99% rename from 07_sequences_00_content.ipynb rename to 07_sequences_00_lecture.ipynb index 924467a..e3887a4 100644 --- a/07_sequences_00_content.ipynb +++ b/07_sequences_00_lecture.ipynb @@ -19,11 +19,11 @@ } }, "source": [ - "We studied numbers (cf., [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb)) and textual data (cf., [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb)) first, mainly because objects of the presented data types are \"simple,\" for two reasons: First, they are *immutable*, and, as we saw in the \"*Who am I? And how many?*\" section in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Who-am-I?-And-how-many?), mutable objects can quickly become hard to reason about. Second, they are \"flat\" in the sense that they are *not* composed of other objects.\n", + "We studied numbers (cf., [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb)) and textual data (cf., [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb)) first, mainly because objects of the presented data types are \"simple,\" for two reasons: First, they are *immutable*, and, as we saw in the \"*Who am I? And how many?*\" section in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Who-am-I?-And-how-many?), mutable objects can quickly become hard to reason about. Second, they are \"flat\" in the sense that they are *not* composed of other objects.\n", "\n", "The `str` type is a bit of a corner case in this regard. While one could argue that a longer `str` object, for example, `\"text\"`, is composed of individual characters, this is *not* the case in memory as the literal `\"text\"` only creates *one* object (i.e., one \"bag\" of $0$s and $1$s modeling all characters).\n", "\n", - "This chapter, [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_content.ipynb) introduce various \"complex\" data types. While some are mutable and others are not, they all share that they are primarily used to \"manage,\" or structure, the memory in a program. Unsurprisingly, computer scientists refer to the ideas and theories behind these data types as **[data structures](https://en.wikipedia.org/wiki/Data_structure)**.\n", + "This chapter, [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb), and [Chapter 9](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/09_arrays_00_lecture.ipynb) introduce various \"complex\" data types. While some are mutable and others are not, they all share that they are primarily used to \"manage,\" or structure, the memory in a program. Unsurprisingly, computer scientists refer to the ideas and theories behind these data types as **[data structures](https://en.wikipedia.org/wiki/Data_structure)**.\n", "\n", "In this chapter, we focus on data types that model all kinds of sequential data. Examples of such data are [spreadsheets](https://en.wikipedia.org/wiki/Spreadsheet) or [matrices](https://en.wikipedia.org/wiki/Matrix_%28mathematics%29)/[vectors](https://en.wikipedia.org/wiki/Vector_%28mathematics_and_physics%29). Such formats share the property that they are composed of smaller units that come in a sequence of, for example, rows/columns/cells or elements/entries." ] @@ -47,9 +47,9 @@ } }, "source": [ - "[Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb#A-\"String\"-of-Characters) already describes the *sequence* properties of `str` objects. Here, we take a step back and study these properties on their own before looking at bigger ideas.\n", + "[Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb#A-\"String\"-of-Characters) already describes the *sequence* properties of `str` objects. Here, we take a step back and study these properties on their own before looking at bigger ideas.\n", "\n", - "The [collections.abc](https://docs.python.org/3/library/collections.abc.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines a variety of **abstract base classes** (ABCs). We saw ABCs already in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb#The-Numerical-Tower), where we use the ones from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to classify Python's numeric data types according to mathematical ideas. Now, we take the ABCs from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module to classify the data types in this chapter and [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb) according to their behavior in various contexts.\n", + "The [collections.abc](https://docs.python.org/3/library/collections.abc.html) module in the [standard library](https://docs.python.org/3/library/index.html) defines a variety of **abstract base classes** (ABCs). We saw ABCs already in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#The-Numerical-Tower), where we use the ones from the [numbers](https://docs.python.org/3/library/numbers.html) module in the [standard library](https://docs.python.org/3/library/index.html) to classify Python's numeric data types according to mathematical ideas. Now, we take the ABCs from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module to classify the data types in this chapter and [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb) according to their behavior in various contexts.\n", "\n", "As an illustration, consider `numbers` and `text` below, two objects of *different* types." ] @@ -131,7 +131,7 @@ } }, "source": [ - "In [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Containers-vs.-Iterables), we referred to such types as *iterables*. That is *not* a proper [English](https://dictionary.cambridge.org/spellcheck/english-german/?q=iterable) word, even if it may sound like one at first sight. Yet, it is an official term in the Python world formalized with the `Iterable` ABC in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module.\n", + "In [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Containers-vs.-Iterables), we referred to such types as *iterables*. That is *not* a proper [English](https://dictionary.cambridge.org/spellcheck/english-german/?q=iterable) word, even if it may sound like one at first sight. Yet, it is an official term in the Python world formalized with the `Iterable` ABC in the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module.\n", "\n", "For the data science practitioner, it is worthwhile to know such terms as, for example, the documentation on the [built-ins](https://docs.python.org/3/library/functions.html) uses them extensively: In simple words, any built-in that takes an argument called \"*iterable*\" may be called with *any* object that supports being looped over. Already familiar [built-ins](https://docs.python.org/3/library/functions.html) include [enumerate()](https://docs.python.org/3/library/functions.html#enumerate), [sum()](https://docs.python.org/3/library/functions.html#sum), or [zip()](https://docs.python.org/3/library/functions.html#zip). So, they do *not* require the argument to be of a certain data type (e.g., `list`); instead, any *iterable* type works." ] @@ -181,7 +181,7 @@ } }, "source": [ - "As in the context of *goose typing* in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb#Goose-Typing), we can use ABCs with the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check if an object supports a behavior.\n", + "As in the context of *goose typing* in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#Goose-Typing), we can use ABCs with the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check if an object supports a behavior.\n", "\n", "So, let's \"ask\" Python if it can loop over `numbers` or `text`." ] @@ -1074,7 +1074,7 @@ "source": [ "Alternatively, we use the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in to create a `list` object out of an iterable we pass to it as the argument.\n", "\n", - "For example, we can wrap the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in with [list()](https://docs.python.org/3/library/functions.html#func-list): As described in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Containers-vs.-Iterables), `range` objects, like `range(1, 13)` below, are iterable and generate `int` objects \"on the fly\" (i.e., one by one). The [list()](https://docs.python.org/3/library/functions.html#func-list) around it acts like a `for`-loop and **materializes** twelve `int` objects in memory that then become the elements of the newly created `list` object. [PythonTutor](http://www.pythontutor.com/visualize.html#code=r%20%3D%20range%281,%2013%29%0Al%20%3D%20list%28range%281,%2013%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows this difference visually." + "For example, we can wrap the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in with [list()](https://docs.python.org/3/library/functions.html#func-list): As described in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Containers-vs.-Iterables), `range` objects, like `range(1, 13)` below, are iterable and generate `int` objects \"on the fly\" (i.e., one by one). The [list()](https://docs.python.org/3/library/functions.html#func-list) around it acts like a `for`-loop and **materializes** twelve `int` objects in memory that then become the elements of the newly created `list` object. [PythonTutor](http://www.pythontutor.com/visualize.html#code=r%20%3D%20range%281,%2013%29%0Al%20%3D%20list%28range%281,%2013%29%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows this difference visually." ] }, { @@ -2678,7 +2678,7 @@ "source": [ "The `list` type is an essential data structure in any real-world Python application, and many typical `list`-related algorithms from computer science theory are already built into it at the C level (cf., the [documentation](https://docs.python.org/3/library/stdtypes.html#mutable-sequence-types) or the [tutorial](https://docs.python.org/3/tutorial/datastructures.html#more-on-lists) for a full overview; unfortunately, not all methods have direct links). So, understanding and applying the built-in methods of the `list` type not only speeds up the development process but also makes programs significantly faster.\n", "\n", - "In contrast to the `str` type's methods in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb#String-Methods) (e.g., [upper()](https://docs.python.org/3/library/stdtypes.html#str.upper) or [lower()](https://docs.python.org/3/library/stdtypes.html#str.lower)), the `list` type's methods that mutate an object do so *in place*. That means they *never* create *new* `list` objects and return `None` to indicate that. So, we must *never* assign the return value of `list` methods to the variable holding the list!\n", + "In contrast to the `str` type's methods in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb#String-Methods) (e.g., [upper()](https://docs.python.org/3/library/stdtypes.html#str.upper) or [lower()](https://docs.python.org/3/library/stdtypes.html#str.lower)), the `list` type's methods that mutate an object do so *in place*. That means they *never* create *new* `list` objects and return `None` to indicate that. So, we must *never* assign the return value of `list` methods to the variable holding the list!\n", "\n", "Let's look at the following `names` example." ] @@ -3016,7 +3016,7 @@ "source": [ "The [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) method and the [sorted()](https://docs.python.org/3/library/functions.html#sorted) function sort the elements in `names` in alphabetical order, forward or backward. However, that does *not* hold in general.\n", "\n", - "We mention above that `list` objects may contain objects of *any* type and even of *mixed* types. Because of that, the sorting is **[delegated](https://en.wikipedia.org/wiki/Delegation_(object-oriented_programming))** to the elements in a `list` object. In a way, Python \"asks\" the elements in a `list` object to sort themselves. As `names` contains only `str` objects, they are sorted according the the comparison rules explained in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb#String-Comparison).\n", + "We mention above that `list` objects may contain objects of *any* type and even of *mixed* types. Because of that, the sorting is **[delegated](https://en.wikipedia.org/wiki/Delegation_(object-oriented_programming))** to the elements in a `list` object. In a way, Python \"asks\" the elements in a `list` object to sort themselves. As `names` contains only `str` objects, they are sorted according the the comparison rules explained in [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb#String-Comparison).\n", "\n", "To customize the sorting, we pass a keyword-only `key` argument to [sort()](https://docs.python.org/3/library/stdtypes.html#list.sort) or [sorted()](https://docs.python.org/3/library/functions.html#sorted), which must be a `function` object accepting *one* positional argument. Then, the elements in the `list` object are passed to that one by one, and the return values are used as the **sort keys**. The `key` argument is also a popular use case for `lambda` expressions.\n", "\n", @@ -6153,7 +6153,7 @@ } }, "source": [ - "Unpacking allows us to rewrite the iterative `fibonacci()` function from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#\"Hard-at-first-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29) in a concise way, now also supporting *goose typing* with the [numbers](https://docs.python.org/3/library/numbers.html) module from the [standard library](https://docs.python.org/3/library/index.html)." + "Unpacking allows us to rewrite the iterative `fibonacci()` function from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#\"Hard-at-first-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29) in a concise way, now also supporting *goose typing* with the [numbers](https://docs.python.org/3/library/numbers.html) module from the [standard library](https://docs.python.org/3/library/index.html)." ] }, { @@ -6576,7 +6576,7 @@ } }, "source": [ - "In the \"*Packing & Unpacking with Functions*\" [exercise](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_review_and_exercises_00_content.ipynb#Packing-&-Unpacking-with-Functions) at the end of this chapter, we look at `product()` in more detail.\n", + "In the \"*Packing & Unpacking with Functions*\" [exercise](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_02_exercises.ipynb#Packing-&-Unpacking-with-Functions) at the end of this chapter, we look at `product()` in more detail.\n", "\n", "While we needed to unpack `one_hundred` above to avoid the semantic error, unpacking an argument in a function call may also be a convenience in general.\n", "\n", @@ -7874,7 +7874,7 @@ } }, "source": [ - "Using the [map()](https://docs.python.org/3/library/functions.html#map) and [filter()](https://docs.python.org/3/library/functions.html#filter) built-ins, we can quickly switch the order: Filter first and then transform the remaining elements. This variant equals the \"*A simple Filter*\" example from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Example:-A-simple-Filter). On the contrary, code with `for`-loops and `if` statements is more tedious to adapt. Additionally, `map` and `filter` objects are optimized at the C level and, therefore, a lot faster as well." + "Using the [map()](https://docs.python.org/3/library/functions.html#map) and [filter()](https://docs.python.org/3/library/functions.html#filter) built-ins, we can quickly switch the order: Filter first and then transform the remaining elements. This variant equals the \"*A simple Filter*\" example from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Example:-A-simple-Filter). On the contrary, code with `for`-loops and `if` statements is more tedious to adapt. Additionally, `map` and `filter` objects are optimized at the C level and, therefore, a lot faster as well." ] }, { @@ -8208,7 +8208,7 @@ "\n", "Often, such functions are used *only once* in a program. However, the primary purpose of functions is to *reuse* them. In such cases, it makes more sense to define them \"anonymously\" right at the position where the first argument goes.\n", "\n", - "As mentioned in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb#Anonymous-Functions), Python provides `lambda` expressions to create `function` objects *without* a name referencing them.\n", + "As mentioned in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Anonymous-Functions), Python provides `lambda` expressions to create `function` objects *without* a name referencing them.\n", "\n", "So, the above `add()` function could be rewritten as a `lambda` expression like so ..." ] @@ -8422,7 +8422,7 @@ "source": [ "For [map()](https://docs.python.org/3/library/functions.html#map) and [filter()](https://docs.python.org/3/library/functions.html#filter), Python provides a nice syntax appealing to people who like mathematics.\n", "\n", - "Consider again the \"*A simple Filter*\" example from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Example:-A-simple-Filter), written with combined `for` and `if` statements. So, the mapping and filtering steps happen simultaneously." + "Consider again the \"*A simple Filter*\" example from [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Example:-A-simple-Filter), written with combined `for` and `if` statements. So, the mapping and filtering steps happen simultaneously." ] }, { @@ -10073,7 +10073,7 @@ } }, "source": [ - "[all()](https://docs.python.org/3/library/functions.html#all) can be viewed as syntactic sugar replacing a `for`-loop: Internally, [all()](https://docs.python.org/3/library/functions.html#all) implements the *short-circuiting* strategy from [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb#Short-Circuiting), and we mimic that by testing for the *opposite* condition in the `if` statement and leaving the `for`-loop early with the `break` statement. In the worst case, if `threshold` were, for example, `150`, we would loop over *all* elements in the *iterable*, which must be *finite* for the code to work. So, [all()](https://docs.python.org/3/library/functions.html#all) is a *linear search* in disguise." + "[all()](https://docs.python.org/3/library/functions.html#all) can be viewed as syntactic sugar replacing a `for`-loop: Internally, [all()](https://docs.python.org/3/library/functions.html#all) implements the *short-circuiting* strategy from [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#Short-Circuiting), and we mimic that by testing for the *opposite* condition in the `if` statement and leaving the `for`-loop early with the `break` statement. In the worst case, if `threshold` were, for example, `150`, we would loop over *all* elements in the *iterable*, which must be *finite* for the code to work. So, [all()](https://docs.python.org/3/library/functions.html#all) is a *linear search* in disguise." ] }, { @@ -10387,13 +10387,13 @@ } }, "source": [ - "With the new concepts in this chapter, let's rewrite the book's introductory \"*Averaging Even Numbers*\" example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Example:-Averaging-Even-Numbers) such that it efficiently handles a large sequence of numbers.\n", + "With the new concepts in this chapter, let's rewrite the book's introductory \"*Averaging Even Numbers*\" example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Example:-Averaging-Even-Numbers) such that it efficiently handles a large sequence of numbers.\n", "\n", "We assume the `average_evens()` function below is called with a *finite* and *iterable* object, which generates a \"stream\" of numeric objects that can be cast as `int` objects because the idea of even and odd numbers only makes sense in the context of whole numbers.\n", "\n", "The generator expression `(int(n) for n in numbers)` implements the type casting, and when it is evaluated, *nothing* happens except that a `generator` object is stored in `integers`. Then, with the [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) function from the [functools](https://docs.python.org/3/library/functools.html) module, we *simultaneously* add up *and* count the even numbers produced by the inner generator expression `((n, 1) for n in integers if n % 2 == 0)`. That results in a `generator` object producing `tuple` objects consisting of the next *even* number in line and `1`. Two such `tuple` objects are then iteratively passed to the `lambda` expression as the `x` and `y` arguments. `x` represents the total and the count of the even numbers processed so far, while `y`'s first element, `y[0]`, is the next even number to be added to the running total. The result of the [reduce()](https://docs.python.org/3/library/functools.html#functools.reduce) function is again a `tuple` object, namely the final `total` and `count`. Lastly, we calculate the simple average.\n", "\n", - "In summary, the implementation of `average_evens()` does *not* keep materialized `list` objects internally like its predecessors from [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb), but processes the elements of the `numbers` argument on a one-by-one basis." + "In summary, the implementation of `average_evens()` does *not* keep materialized `list` objects internally like its predecessors from [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb), but processes the elements of the `numbers` argument on a one-by-one basis." ] }, { @@ -11317,7 +11317,7 @@ } }, "source": [ - "In [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#The-for-Statement), we argue that the `for` statement is syntactic sugar, replacing the `while` statement in many scenarios. In particular, a `for`-loop saves us two tasks: Managing an index variable *and* obtaining the individual elements by indexing. In this sub-section, we look at a more realistic picture, using the new terminology as well.\n", + "In [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#The-for-Statement), we argue that the `for` statement is syntactic sugar, replacing the `while` statement in many scenarios. In particular, a `for`-loop saves us two tasks: Managing an index variable *and* obtaining the individual elements by indexing. In this sub-section, we look at a more realistic picture, using the new terminology as well.\n", "\n", "Let's print out the elements of a `list` object as the *iterable* to be looped over." ] diff --git a/07_sequences_10_review.ipynb b/07_sequences_01_review.ipynb similarity index 98% rename from 07_sequences_10_review.ipynb rename to 07_sequences_01_review.ipynb index a2d2f5c..d374b3c 100644 --- a/07_sequences_10_review.ipynb +++ b/07_sequences_01_review.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { @@ -40,7 +40,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1**: We have seen **containers** and **iterables** before in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Containers-vs.-Iterables). How do they relate to **sequences**? " + "**Q1**: We have seen **containers** and **iterables** before in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Containers-vs.-Iterables). How do they relate to **sequences**? " ] }, { diff --git a/07_sequences_20_exercises.ipynb b/07_sequences_02_exercises.ipynb similarity index 98% rename from 07_sequences_20_exercises.ipynb rename to 07_sequences_02_exercises.ipynb index b2a8169..daad5e0 100644 --- a/07_sequences_20_exercises.ipynb +++ b/07_sequences_02_exercises.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb) of the book. Then, work through the exercises below." + "Read [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) of the book. Then, work through the exercises below." ] }, { @@ -90,7 +90,7 @@ "source": [ "**Q1.3**: Generalize `nested_sum()` into a function `mixed_sum()` that can process a \"mixed\" `list` object, which contains numbers and other `list` objects with numbers! Use `mixed_numbers` below for testing!\n", "\n", - "Hints: Use the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check how an element is to be processed. Get extra credit for adhering to *goose typing*, as explained in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb#Goose-Typing)." + "Hints: Use the built-in [isinstance()](https://docs.python.org/3/library/functions.html#isinstance) function to check how an element is to be processed. Get extra credit for adhering to *goose typing*, as explained in [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb#Goose-Typing)." ] }, { @@ -196,7 +196,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the \"*Function Definitions & Calls*\" section in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Function-Definitions-&-Calls), we define the following function `product()`. In this exercise, you will improve it by making it more \"user-friendly.\"" + "In the \"*Function Definitions & Calls*\" section in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Function-Definitions-&-Calls), we define the following function `product()`. In this exercise, you will improve it by making it more \"user-friendly.\"" ] }, { @@ -290,7 +290,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Function-Definitions-&-Calls), we also pass a `list` object, like `one_hundred`, to `product()`, and *no* exception is raised." + "In [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Function-Definitions-&-Calls), we also pass a `list` object, like `one_hundred`, to `product()`, and *no* exception is raised." ] }, { @@ -315,7 +315,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q2.3**: What is wrong with that? What *kind* of error (cf., [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Formal-vs.-Natural-Languages)) is that conceptually? Describe precisely what happens to the passed in `one_hundred` in every line within `product()`!" + "**Q2.3**: What is wrong with that? What *kind* of error (cf., [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Formal-vs.-Natural-Languages)) is that conceptually? Describe precisely what happens to the passed in `one_hundred` in every line within `product()`!" ] }, { @@ -493,7 +493,7 @@ "source": [ "**Q2.7**: Rewrite `product()` so that it takes a *keyword-only* argument `start`, defaulting to the above *default* or *start* value, and use `start` internally instead of `result`!\n", "\n", - "Hint: Remember that a *keyword-only* argument is any parameter specified in a function's header line after the first (and only) `*` (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb#Keyword-only-Arguments))." + "Hint: Remember that a *keyword-only* argument is any parameter specified in a function's header line after the first (and only) `*` (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Keyword-only-Arguments))." ] }, { @@ -697,7 +697,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Side Note**: Above, we make `product()` work with a single *collection* type argument instead of a *sequence* type to keep it more generic: For example, we can pass in a `set` object, like `{2, 5, 10}` below, and `product()` continues to work correctly. The `set` type is introducted in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb#The-set-Type), and one essential difference to the `list` type is that objects of type `set` have *no* order regarding their elements. So, even though `[2, 5, 10]` and `{2, 5, 10}` look almost the same, the order implied in the literal notation gets lost in memory!" + "**Side Note**: Above, we make `product()` work with a single *collection* type argument instead of a *sequence* type to keep it more generic: For example, we can pass in a `set` object, like `{2, 5, 10}` below, and `product()` continues to work correctly. The `set` type is introducted in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb#The-set-Type), and one essential difference to the `list` type is that objects of type `set` have *no* order regarding their elements. So, even though `[2, 5, 10]` and `{2, 5, 10}` look almost the same, the order implied in the literal notation gets lost in memory!" ] }, { @@ -1627,7 +1627,7 @@ "source": [ "**Q3.10.2**: Just as in `standardized()`, write a *generator expression* that produces z-scores one by one! However, instead of just generating a z-score, the resulting `generator` object should produce `tuple` objects consisting of a \"raw\" number from `data` and its z-score.\n", "\n", - "Hint: Look at the revisited \"*Averaging Even Numbers*\" example in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Example:-Averaging-Even-Numbers-%28revisited%29) for some inspiration, which also contains a generator expression producing `tuple` objects." + "Hint: Look at the revisited \"*Averaging Even Numbers*\" example in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Example:-Averaging-Even-Numbers-%28revisited%29) for some inspiration, which also contains a generator expression producing `tuple` objects." ] }, { diff --git a/08_mappings_00_content.ipynb b/08_mappings_00_lecture.ipynb similarity index 99% rename from 08_mappings_00_content.ipynb rename to 08_mappings_00_lecture.ipynb index 2e19dbe..79483b5 100644 --- a/08_mappings_00_content.ipynb +++ b/08_mappings_00_lecture.ipynb @@ -19,9 +19,9 @@ } }, "source": [ - "While [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb) focuses on one special kind of *collection* types, namely *sequences*, this chapter introduces two more kinds: **Mappings** and **sets**. We present the data types belonging to these two groups in one chapter as they share the *same* underlying implementation at the C Level, known as **[hash tables](https://en.wikipedia.org/wiki/Hash_table)**.\n", + "While [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) focuses on one special kind of *collection* types, namely *sequences*, this chapter introduces two more kinds: **Mappings** and **sets**. We present the data types belonging to these two groups in one chapter as they share the *same* underlying implementation at the C Level, known as **[hash tables](https://en.wikipedia.org/wiki/Hash_table)**.\n", "\n", - "The most important mapping type in this chapter is the `dict` type that we have not yet seen before (cf, [documentation](https://docs.python.org/3/library/stdtypes.html#dict)). It is an essential part in a data science practitioner's toolbox for two reasons: First, Python employs `dict` objects basically \"everywhere\" internally. So, we must understand how they work to become better at Python in general. Second, after the many concepts related to *sequential* data, the ideas behind *mappings* enhance our general problem solving skills. As a concrete example, we look at the concept of **memoization** to complete our picture of *recursion*, as depicted in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#Recursion). We end this chapter with a discussion of *set* types." + "The most important mapping type in this chapter is the `dict` type that we have not yet seen before (cf, [documentation](https://docs.python.org/3/library/stdtypes.html#dict)). It is an essential part in a data science practitioner's toolbox for two reasons: First, Python employs `dict` objects basically \"everywhere\" internally. So, we must understand how they work to become better at Python in general. Second, after the many concepts related to *sequential* data, the ideas behind *mappings* enhance our general problem solving skills. As a concrete example, we look at the concept of **memoization** to complete our picture of *recursion*, as depicted in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#Recursion). We end this chapter with a discussion of *set* types." ] }, { @@ -45,7 +45,7 @@ "source": [ "A *mapping* is a one-to-one correspondence from a set of **keys** to a set of **values**. In other words, a *mapping* is a *collection* of **key-value pairs**, also called **items** for short.\n", "\n", - "In the context of mappings, the term *value* has a meaning different from the general *value* that *every* object has: In the \"bag\" analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Value), we descibe an object's value to be the concrete $0$s and $1$s it contains. Here, the terms *key* and *value* mean the *role* an object takes within a mapping. Both, *keys* and *values*, are real *objects* with a distinct *value*. So, the student should always remember the double meaning of the term *value* in this chapter!\n", + "In the context of mappings, the term *value* has a meaning different from the general *value* that *every* object has: In the \"bag\" analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Value), we descibe an object's value to be the concrete $0$s and $1$s it contains. Here, the terms *key* and *value* mean the *role* an object takes within a mapping. Both, *keys* and *values*, are real *objects* with a distinct *value*. So, the student should always remember the double meaning of the term *value* in this chapter!\n", "\n", "Let's continue with an example. To create a `dict` object, we commonly use the literal notation, `{..: .., ..: .., ...}`, and list all the items. `to_words` below maps the `int` objects `0`, `1`, and `2` to their English word equivalents, `\"zero\"`, `\"one\"`, and `\"two\"`, and `from_words` does the opposite. A stylistic side note: Pythonistas often expand `dict` or `list` definitions by writing each item or element on a line on their own. The commas `,` after the *last* items are *not* a mistake, as well, although they *may* be left out. Besides easier reading, such style has actual technical advantages (cf., [source](https://www.python.org/dev/peps/pep-0008/#when-to-use-trailing-commas)) that we do not go into detail about here." ] @@ -502,7 +502,7 @@ } }, "source": [ - "In [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up_00_content.ipynb#Isn't-C-a-lot-faster?), we argue that a major advantage of using Python is that it takes care of the memory managment for us. In line with that, we have never talked about the C level implementation thus far in the book. However, the `dict` type, among others, exhibits some behaviors that may seem \"weird\" for a beginner. To built a solid intuition that enables the student to better \"predict\" how `dict` objects behave, we describe the underlying implementation details on a conceptual level (i.e., without C code).\n", + "In [Chapter 0](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb#Isn't-C-a-lot-faster?), we argue that a major advantage of using Python is that it takes care of the memory managment for us. In line with that, we have never talked about the C level implementation thus far in the book. However, the `dict` type, among others, exhibits some behaviors that may seem \"weird\" for a beginner. To built a solid intuition that enables the student to better \"predict\" how `dict` objects behave, we describe the underlying implementation details on a conceptual level (i.e., without C code).\n", "\n", "The first unintuitive behavior is that we may *not* use a *mutable* object as a key. That results in a `TypeError`." ] @@ -707,7 +707,7 @@ } }, "source": [ - "The [glossary](https://docs.python.org/3/glossary.html#term-hashable) states a second requirement for hashability, namely that \"objects which *compare equal* must have the *same* hash value.\" The purpose of this is to ensure that if we put, for example, `1` as a key in a `dict` object, we can look it up later with `1.0`. In other words, we can look up keys by their object's value (i.e., in the meaning of [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb#Value)). The converse statement does *not* hold: Two objects *may* (accidentally) have the *same* hash value and *not* compare equal." + "The [glossary](https://docs.python.org/3/glossary.html#term-hashable) states a second requirement for hashability, namely that \"objects which *compare equal* must have the *same* hash value.\" The purpose of this is to ensure that if we put, for example, `1` as a key in a `dict` object, we can look it up later with `1.0`. In other words, we can look up keys by their object's value (i.e., in the meaning of [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb#Value)). The converse statement does *not* hold: Two objects *may* (accidentally) have the *same* hash value and *not* compare equal." ] }, { @@ -1081,7 +1081,7 @@ } }, "source": [ - "In [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Collections-vs.-Sequences), we show how *sequences* are a special kind of *collections*. The latter can be described as iterable containers with a finite number of elements.\n", + "In [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Collections-vs.-Sequences), we show how *sequences* are a special kind of *collections*. The latter can be described as iterable containers with a finite number of elements.\n", "\n", "The `dict` type is a special kind of a *collection*, as well, as revealed with the `Collection` ABC from the [collections.abc](https://docs.python.org/3/library/collections.abc.html) module in the [standard library](https://docs.python.org/3/library/index.html)." ] @@ -3769,7 +3769,7 @@ } }, "source": [ - "Just as a single `*` symbol is used for packing and unpacking iterables in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#Packing-&-Unpacking), a double `**` symbol implements packing and unpacking for mappings.\n", + "Just as a single `*` symbol is used for packing and unpacking iterables in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#Packing-&-Unpacking), a double `**` symbol implements packing and unpacking for mappings.\n", "\n", "Let's say we have `to_words` and `more_words` as below and want to merge the items together into a *new* `dict` object." ] @@ -4195,7 +4195,7 @@ } }, "source": [ - "Analogous to list comprehensions in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb#List-Comprehensions), **dictionary comprehensions**, or **dictcomps** for short, are a concise literal notation to derive new `dict` objects out of existing ones.\n", + "Analogous to list comprehensions in [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#List-Comprehensions), **dictionary comprehensions**, or **dictcomps** for short, are a concise literal notation to derive new `dict` objects out of existing ones.\n", "\n", "For example, let's derive `from_words` from `to_words` below by swapping the keys and values." ] @@ -4410,7 +4410,7 @@ } }, "source": [ - "The *recursive* implementation of the [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number) in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#\"Easy-at-first-Glance\"-Example:-Fibonacci-Numbers) takes long to compute for large Fibonacci numbers as the number of function calls grows exponentially.\n", + "The *recursive* implementation of the [Fibonacci numbers](https://en.wikipedia.org/wiki/Fibonacci_number) in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#\"Easy-at-first-Glance\"-Example:-Fibonacci-Numbers) takes long to compute for large Fibonacci numbers as the number of function calls grows exponentially.\n", "\n", "The graph below visualizes what the problem is and also suggests a solution: Instead of calculating the return value of the `fibonacci()` function for the *same* argument over and over again, it makes sense to **cache** the result and reuse it. This concept is called **[memoization](https://en.wikipedia.org/wiki/Memoization)** in the computer science literature." ] diff --git a/08_mappings_10_review.ipynb b/08_mappings_01_review.ipynb similarity index 96% rename from 08_mappings_10_review.ipynb rename to 08_mappings_01_review.ipynb index 471bd41..0ff62f9 100644 --- a/08_mappings_10_review.ipynb +++ b/08_mappings_01_review.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb) of the book. Then, work through the questions below." + "Read [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb) of the book. Then, work through the questions below." ] }, { @@ -113,7 +113,7 @@ "**Q6**: **Memoization** is an essential concept to know to solve problems in the real world. Together with the idea of **recursion**, it enables us to solve problems in a \"backwards\" fashion *effectively*.\n", "\n", "\n", - "Compare the **recursive** formulation of `fibonacci()` in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb#\"Easy-at-third-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29), the \"*Easy at third Glance*\" example, with the **iterative** version in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb#\"Hard-at-first-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29), the \"*Hard at first Glance*\" example!\n", + "Compare the **recursive** formulation of `fibonacci()` in [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb#\"Easy-at-third-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29), the \"*Easy at third Glance*\" example, with the **iterative** version in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb#\"Hard-at-first-Glance\"-Example:-Fibonacci-Numbers-%28revisited%29), the \"*Hard at first Glance*\" example!\n", "\n", "How are they similar and how do they differ?" ] diff --git a/08_mappings_20_exercises.ipynb b/08_mappings_02_exercises.ipynb similarity index 99% rename from 08_mappings_20_exercises.ipynb rename to 08_mappings_02_exercises.ipynb index 0f3f1a5..4db33ee 100644 --- a/08_mappings_20_exercises.ipynb +++ b/08_mappings_02_exercises.ipynb @@ -19,7 +19,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Read [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb) of the book. Then, work through the exercises below." + "Read [Chapter 8](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb) of the book. Then, work through the exercises below." ] }, { diff --git a/README.md b/README.md index 8c1cba2..c9b4933 100644 --- a/README.md +++ b/README.md @@ -17,48 +17,48 @@ They can be viewed in a plain web browser with the help of [nbviewer](https://nbviewer.jupyter.org/): - *Introduction*: Start up - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up_10_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up_20_exercises.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_02_exercises.ipynb)) - **Part A: Expressing Logic** - *Chapter 1*: Elements of a Program - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_10_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_20_exercises.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements_02_exercises.ipynb)) - *Chapter 2*: Functions & Modularization - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_10_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_20_exercises.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_02_exercises.ipynb)) - *Chapter 3*: Conditionals & Exceptions - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_10_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_20_exercises.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_02_exercises.ipynb)) - *Chapter 4*: Recursion & Looping - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_10_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_20_exercises.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration_02_exercises.ipynb)) - **Part B: Managing Data and Memory** - *Chapter 5*: Bits & Numbers - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_10_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_20_exercises.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers_02_exercises.ipynb)) - *Chapter 6*: Bytes & Text - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_10_review.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text_01_review.ipynb)) - *Chapter 7*: Sequential Data - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_10_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_20_exercises.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_02_exercises.ipynb)) - *Chapter 8*: Mappings & Sets - ([content](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_content.ipynb) - | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_10_review.ipynb) - | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_20_exercises.ipynb)) + ([lecture](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_00_lecture.ipynb) + | [review](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_01_review.ipynb) + | [exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/08_mappings_02_exercises.ipynb)) However, it is recommended that students **install Python and Jupyter locally** and run the code in the notebooks on their own. This way, the student can play with the code and learn more efficiently. Precise **installation instructions** are either in the [00th notebook]( -https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_start_up_00_content.ipynb) +https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/00_intro_00_lecture.ipynb) or further below. Feedback is encouraged and will be incorporated. From d372b4d58992ebb19a80911e49dc0636e8ac4a42 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 2 Feb 2020 17:23:36 +0100 Subject: [PATCH 3/8] Adjust update notification in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c9b4933..b6b1b9d 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -**Important**: The notebooks are being updated and amended throughout the +**Important**: The content is being updated and amended throughout the spring semester of 2020! # An Introduction to Python and Programming From 2f5ee9a8da6ac636ce8be79dbf0d044b58df2cb6 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 2 Feb 2020 17:24:06 +0100 Subject: [PATCH 4/8] Add notes for instructors - use jupyter notebook and not jupyter lab - do not use RISE with Collabsible Headings extension --- README.md | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index b6b1b9d..e64527c 100644 --- a/README.md +++ b/README.md @@ -181,13 +181,6 @@ if you have poetry installed, you may just type `poetry install` instead). - `python -m pip install -r requirements.txt` -The *requirements.txt* file also installs the [black](https://github.com/psf/black) -tool (incl. the [blackcellmagic](https://github.com/csurfer/blackcellmagic) -extension) and the [RISE](https://github.com/damianavila/RISE) extension. -With them, the instructor can easily re-format code in a class session and -execute code in presentation mode (currently RISE only works with the -older `jupyter notebook` command). - With everything installed, you can now do the equivalent of clicking the "JupyterLab" entry in the Anaconda Navigator. @@ -196,6 +189,33 @@ With everything installed, you can now do the equivalent of clicking the This opens a new tab in your web browser just as above. +#### Interactive Presentation Mode & Live Coding + +The *requirements.txt* file also installs the [nbextensions](https://github.com/ipython-contrib/jupyter_contrib_nbextensions) +for Jupyter notebooks, the [black](https://github.com/psf/black) code +formatting tool (incl. the [blackcellmagic](https://github.com/csurfer/blackcellmagic) +Jupyter extension) and the [RISE](https://github.com/damianavila/RISE) Jupyter +extension. +With them, the instructor can easily re-format code in a class session and +execute code in presentation mode. + +**Note**: Currently, the RISE extension *only* works with the older +notebook command. + +- `jupyter notebook` (so, `jupyter lab` may *not* be used). + +After installing the dependencies, the instructor must copy the extensions' +JavaScript and CSS files into Jupyter's search directory. + +- `jupyter contrib nbextension install --user` + +Now, the instructor can enable/disable the various Jupyter notebook +extensions. + +**Note**: The extension "Collapsible Headings" may interfere with the +RISE presentation if hotkeys are enabled. + + ## About the Author Alexander Hess is a PhD student at the Chair of Logistics Management at the From 40b6c9c5a60ba4208b229701e16c6c5a03f84a82 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 2 Feb 2020 17:25:17 +0100 Subject: [PATCH 5/8] Bump version number --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 106e21f..b77fd3a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "intro-to-python" -version = "0.6.1" +version = "0.6.2" description = "An introduction to Python and programming for wanna-be data scientists" authors = ["Alexander Hess "] license = "MIT" From 945debb25e527b7539fd9a6e8cb7d4f3d43b9ee9 Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 2 Feb 2020 18:47:08 +0100 Subject: [PATCH 6/8] Streamline text --- 00_intro_00_lecture.ipynb | 139 ++++++++++++++++++++++++-------------- README.md | 2 +- 2 files changed, 90 insertions(+), 51 deletions(-) diff --git a/00_intro_00_lecture.ipynb b/00_intro_00_lecture.ipynb index b812c61..a8d2237 100644 --- a/00_intro_00_lecture.ipynb +++ b/00_intro_00_lecture.ipynb @@ -128,9 +128,9 @@ } }, "source": [ - "The term **[data science](https://en.wikipedia.org/wiki/Data_science)** is rather vague and does *not* refer to an academic discipline. Instead, the term was popularized by the tech industry, who also coined non-meaningful job titles such as \"[rockstar](https://www.quora.com/Why-are-engineers-called-rockstars-and-ninjas)\" or \"[ninja developers](https://www.quora.com/Why-are-engineers-called-rockstars-and-ninjas).\" Most *serious* definitions describe the field as being **multi-disciplinary** *integrating* scientific methods, algorithms, and systems thinking to extract knowledge from (structured and unstructured) data *and* also emphasize the importance of **[domain knowledge](https://en.wikipedia.org/wiki/Domain_knowledge)**.\n", + "The term **[data science](https://en.wikipedia.org/wiki/Data_science)** is rather vague and does *not* refer to an academic discipline. Instead, the term was popularized by the tech industry, who also coined non-meaningful job titles such as \"[rockstar](https://www.quora.com/Why-are-engineers-called-rockstars-and-ninjas)\" or \"[ninja developers](https://www.quora.com/Why-are-engineers-called-rockstars-and-ninjas).\" Most *serious* definitions describe the field as being **multi-disciplinary** *integrating* scientific methods, algorithms, and systems thinking to extract knowledge from structured and unstructured data, *and* also emphasize the importance of **[domain knowledge](https://en.wikipedia.org/wiki/Domain_knowledge)**.\n", "\n", - "Recently, this integration aspect feeds back into the academic world. The [MIT](https://www.mit.edu/), for example, created the new [Stephen A. Schwarzman College of Computing](http://computing.mit.edu) for [artificial intelligence](https://en.wikipedia.org/wiki/Artificial_intelligence) (with a 1 billion dollar initial investment) where students undergo a \"bilingual\" curriculum with half the classes in quantitative and method-centric fields (like the ones mentioned above) and the other half in domains such as biology, business, chemistry, politics, (art) history, or linguistics (cf., the [official Q&As](http://computing.mit.edu/faq/) or this [NYT article](https://www.nytimes.com/2018/10/15/technology/mit-college-artificial-intelligence.html)). Their strategists see a future where programming skills are just as naturally embedded into every students' curricula as are nowadays subjects like calculus, statistics, or academic writing. Then, programming literacy is not just another \"nice to have\" skill but a prerequisite, or an enabler, to understanding more advanced topics in the actual domains studied. Top-notch researchers who use programming in their day-to-day lives could then teach students more efficiently in their \"language.\"" + "Recently, this integration aspect feeds back into the academic world. The [MIT](https://www.mit.edu/), for example, created the new [Stephen A. Schwarzman College of Computing](http://computing.mit.edu) for [artificial intelligence](https://en.wikipedia.org/wiki/Artificial_intelligence) with a 1 billion dollar initial investment where students undergo a \"bilingual\" curriculum with half the classes in quantitative and method-centric fields - like the ones mentioned above - and the other half in domains such as biology, business, chemistry, politics, (art) history, or linguistics (cf., the [official Q&As](http://computing.mit.edu/faq/) or this [NYT article](https://www.nytimes.com/2018/10/15/technology/mit-college-artificial-intelligence.html)). Their strategists see a future where programming skills are just as naturally embedded into students' curricula as are nowadays subjects like calculus, statistics, or academic writing. Then, programming literacy is not just another \"nice to have\" skill but a prerequisite, or an enabler, to understanding more advanced topics in the actual domains studied. Top-notch researchers who use programming in their day-to-day lives could then teach students more efficiently in their \"language.\"" ] }, { @@ -200,7 +200,7 @@ } }, "source": [ - "A new tab in your web browser opens with the website being \"localhost\" and some number (e.g., 8888). This is the [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) application that is used to display and run the Jupyter notebooks mentioned above. On the left, you see the files and folders in your local user folder. This file browser works like any other. In the center, you have several options to launch a new notebook file." + "A new tab in your web browser opens with the website being \"localhost\" and some number (e.g., 8888). This is the [JupyterLab](https://jupyterlab.readthedocs.io/en/stable/) application that is used to display and run Jupyter notebooks as described below. On the left, you see the files and folders in your local user folder. This file browser works like any other. In the center, you have several options to launch (i.e., \"create\") new files." ] }, { @@ -248,9 +248,29 @@ "\n", "\"Jupyter\" is an [acronym](https://en.wikipedia.org/wiki/Acronym) derived from the names of the three major programming languages **[Julia](https://julialang.org/)**, **[Python](https://www.python.org)**, and **[R](https://www.r-project.org/)**, all of which play significant roles in the world of data science. The Jupyter Project's idea is to serve as an integrating platform such that different programming languages and software packages can be used together within the same project easily.\n", "\n", - "Furthermore, Jupyter notebooks have become a de-facto standard for communicating and exchanging results in the data science community (both in academia and business) and often provide a more intuitive alternative to terminal-based ways of running Python (e.g., the default [Python interpreter](https://docs.python.org/3/tutorial/interpreter.html) as shown above or a more advanced interactive version like [IPython](https://ipython.org/)) or even a full-fledged [Integrated Development Environment](https://en.wikipedia.org/wiki/Integrated_development_environment) (e.g., the commercial [PyCharm](https://www.jetbrains.com/pycharm/) or the free [Spyder](https://github.com/spyder-ide/spyder)).\n", - "\n", - "In particular, they allow mixing plain English text with Python code cells. The plain text can be formatted using the [Markdown](https://guides.github.com/features/mastering-markdown/) language, and mathematical expressions can be typeset with [LaTeX](https://www.overleaf.com/learn/latex/Free_online_introduction_to_LaTeX_%28part_1%29). Lastly, we can include pictures, plots, and even videos. Because of these features, the notebooks developed for this book come in a self-contained \"tutorial\" style that enables students to learn and review the material on their own." + "Furthermore, Jupyter notebooks have become a de-facto standard for communicating and exchanging results in the data science community - both in academia and business - and provide an alternative to terminal-based ways of running Python (e.g., the default [Python interpreter](https://docs.python.org/3/tutorial/interpreter.html) as shown below or a more advanced interactive version like [IPython](https://ipython.org/)) or a full-fledged [Integrated Development Environment](https://en.wikipedia.org/wiki/Integrated_development_environment) (e.g., the commercial [PyCharm](https://www.jetbrains.com/pycharm/) or the free [Spyder](https://github.com/spyder-ide/spyder) that comes with the Anaconda Distribution)." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "slide" + } + }, + "source": [ + "" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "Jupyter notebooks allow mixing formatted English with Python code in the same document. Text is formatted with the [Markdown](https://guides.github.com/features/mastering-markdown/) language and mathematical formulas are typeset with [LaTeX](https://www.overleaf.com/learn/latex/Free_online_introduction_to_LaTeX_%28part_1%29). Moreover, we may include pictures, plots, and even videos. Because of these features, the notebooks developed for this book come in a self-contained \"tutorial\" style enabling students to learn and review the material on their own." ] }, { @@ -274,15 +294,15 @@ "source": [ "A Jupyter notebook consists of cells that have a type associated with them. So far, only cells of type \"Markdown\" have been used, which is the default way to present formatted text.\n", "\n", - "The next cell below is an example of a \"Code\" cell containing a line of actual Python code: it merely outputs the text \"Hello world\" when executed. To edit an existing code cell, enter into it with a mouse click. You know that you are \"in\" a code cell when you see the frame of the code cell turn green.\n", + "The cell below is an example of a \"Code\" cell containing a line of actual Python code: It merely outputs the text \"Hello world\" when executed. To edit an existing code cell, enter into it with a mouse click. You know that you are \"in\" a code cell when its frame is highlighted in blue.\n", "\n", - "Besides this **edit mode**, there is also a so-called **command mode** that you can reach by hitting the \"Escape\" key after entering a code cell, which turns the frame's color blue. Using the \"Enter\" and \"Escape\" keys, you can now switch between the two modes.\n", + "Besides this **edit mode**, there is also a so-called **command mode** that you reach by hitting the \"Escape\" key *after* entering a code cell, which un-highlights the frame. Using the \"Enter\" and \"Escape\" keys, you can now switch between the two modes.\n", "\n", - "To *execute*, or \"*run*,\" a code cell, hold the \"Control\" key and press \"Enter.\" Note how you do not go to the subsequent cell. Alternatively, you can hold the \"Shift\" key and press \"Enter,\" which executes the cell and places your focus on the next cell right after.\n", + "To *execute*, or \"*run*,\" a code cell, hold the \"Control\" key and press \"Enter.\" Note that you do *not* go to the subsequent cell. Alternatively, you can hold the \"Shift\" key and press \"Enter,\" which executes the cell *and* places your focus on the subsequent cell.\n", "\n", - "Similarly, a Markdown cell is also in either edit or command mode. For example, double-click on the text you are just reading, which takes you into edit mode. Now you could change the formatting (e.g., make a word printed in *italics* or **bold** with single or double asterisks) and then \"execute\" the cell to render the text as specified.\n", + "Similarly, a Markdown cell is also in either edit or command mode. For example, double-click on the text you are reading: This puts you into edit mode. Now, you could change the formatting (e.g., make a word printed in *italics* or **bold** with single or double asterisks) and \"execute\" the cell to render the text as specified.\n", "\n", - "To change a cell's type, choose either \"Code\" or \"Markdown\" in the navigation bar at the top." + "To change a cell's type, choose either \"Code\" or \"Markdown\" in the navigation bar at the top. Alternatively, you can hit either the \"Y\" or \"M\" key on your keyboard when in command mode to make the focused cell a code or markdown cell." ] }, { @@ -314,7 +334,7 @@ } }, "source": [ - "Sometimes a code cell starts with an exclamation mark `!`. Then, the Jupyter notebook behaves as if the following command were typed directly into a terminal. The cell below asks `python` to show its version number and is *not* Python code but a command in the [Shell](https://en.wikipedia.org/wiki/Shell_script) language. The `!` is useful to execute short commands without leaving a Jupyter notebook." + "Sometimes, a code cell starts with an exclamation mark `!`. Then, the Jupyter notebook behaves as if the following command were typed directly into a terminal. The cell below asks `python` to show its version number and is *not* Python code but a command in the [Shell](https://en.wikipedia.org/wiki/Shell_script) language. The `!` is useful to execute short commands without leaving a Jupyter notebook." ] }, { @@ -322,7 +342,7 @@ "execution_count": 2, "metadata": { "slideshow": { - "slide_type": "-" + "slide_type": "skip" } }, "outputs": [ @@ -342,7 +362,7 @@ "cell_type": "markdown", "metadata": { "slideshow": { - "slide_type": "skip" + "slide_type": "slide" } }, "source": [ @@ -357,15 +377,15 @@ } }, "source": [ - "In this book, *programming* is \"defined\" as:\n", + "In this book, **programming** is \"defined\" as\n", "\n", - "- a **structured** way of **problem-solving**\n", - "- by **expressing** the steps of a **computation/process**\n", - "- and thereby **documenting** the process in a formal way\n", + "- a *structured* way of *problem-solving*\n", + "- by *expressing* the steps of a *computation/process*\n", + "- and thereby *documenting* the process in a formal way.\n", "\n", - "Programming is always **concrete** and based on a **particular case**.\n", + "Programming is always *concrete* and based on a *particular case*.\n", "\n", - "It exhibits elements of a form of **art** or a **craft** as we hear programmers call code \"beautiful\" or \"ugly\" or talk about the \"expressive\" power of an application." + "It exhibits elements of a form of *art* or a *craft* as we hear programmers call code \"beautiful\" or \"ugly\" or talk about the \"expressive\" power of an application." ] }, { @@ -376,14 +396,14 @@ } }, "source": [ - "That is different from *computer science*, which is:\n", + "That is different from **computer science**, which is\n", "\n", - "- a field of study comparable to (applied) **mathematics** that\n", - "- asks **abstract** questions (\"Is something computable at all?\"),\n", - "- develops and analyses **algorithms** and **data structures**,\n", - "- and **proves** the **correctness** of a program\n", + "- a field of study comparable to (applied) *mathematics* that\n", + "- asks *abstract* questions (e.g., \"Is something computable at all?\"),\n", + "- develops and analyses *algorithms* and *data structures*,\n", + "- and *proves* the *correctness* of a program.\n", "\n", - "In a sense, a computer scientist does not need to know a programming language to work, and many computer scientists only know how to produce \"ugly\"-looking code in the eyes of professional programmers." + "In a sense, a computer scientist does not need to know a programming language to work, and many computer scientists only know how to produce \"ugly\" looking code in the eyes of professional programmers." ] }, { @@ -394,7 +414,7 @@ } }, "source": [ - "*IT* or *information technology* is a term that has many meanings to many people. Often, it has something to do with hardware or physical devices, both of which are out of scope for programmers and computer scientists. Many computer scientists and programmers are more than happy if their printer and internet connection work as they often do not know a lot more about that than non-technical people." + "**IT** or **information technology** is a term that has many meanings to different people. Often, it has something to do with hardware or physical devices, both of which are out of scope for programmers and computer scientists. Many computer scientists and programmers are more than happy if their printer and internet connection work as they often do not know a lot more about that than \"non-technical\" people." ] }, { @@ -430,10 +450,10 @@ "Here is a brief history of and some background on Python (cf., also this [TechRepublic article](https://www.techrepublic.com/article/python-is-eating-the-world-how-one-developers-side-project-became-the-hottest-programming-language-on-the-planet/) for a more elaborate story):\n", "\n", "- [Guido van Rossum](https://en.wikipedia.org/wiki/Guido_van_Rossum) (Python’s **[Benevolent Dictator for Life](https://en.wikipedia.org/wiki/Benevolent_dictator_for_life)**) was bored during a week around Christmas 1989 and started Python as a hobby project \"that would keep \\[him\\] occupied\" for some days\n", - "- the idea was to create a **general-purpose scripting** language that would allow fast **prototyping** and would **run on every operating system**\n", - "- Python grew through the 90s as van Rossum promoted it via his \"Computer Programming for Everybody\" initiative that had the **goal to encourage a basic level of coding literacy** as an equal knowledge alongside English literacy and math skills\n", - "- to become more independent from its creator the next major version **Python 2** (released in 2000; still in heavy use as of today) was **open-sourced** from the get-go which attracted a **large and global community of programmers** that **contributed** their expertise and best practices in their free time to make Python even better\n", - "- **Python 3** resulted from a significant overhaul of the language in 2008 taking into account the **learnings from almost two decades**, streamlining the language, and getting ready for the age of **big data**\n", + "- the idea was to create a **general-purpose** scripting **language** that would allow fast *prototyping* and would *run on every operating system*\n", + "- Python grew through the 90s as van Rossum promoted it via his \"Computer Programming for Everybody\" initiative that had the *goal to encourage a basic level of coding literacy* as an equal knowledge alongside English literacy and math skills\n", + "- to become more independent from its creator, the next major version **Python 2** - released in 2000 and still in heavy use as of today - was **open-source** from the get-go which attracted a *large and global community of programmers* that *contributed* their expertise and best practices in their free time to make Python even better\n", + "- **Python 3** resulted from a significant overhaul of the language in 2008 taking into account the *learnings from almost two decades*, streamlining the language, and getting ready for the age of **big data**\n", "- the language is named after the sketch comedy group [Monty Python](https://en.wikipedia.org/wiki/Monty_Python)" ] }, @@ -456,7 +476,7 @@ } }, "source": [ - "Python is a **general-purpose** programming language that allows for **fast development**, is **easy to read**, **open-source**, long-established, unifies the knowledge of **hundreds of thousands of experts** around the world, runs on basically every machine, and can handle the complexities of applications involving **big data**." + "Python is a **general-purpose** programming **language** that allows for *fast development*, is *easy to read*, **open-source**, long-established, unifies the knowledge of *hundreds of thousands of experts* around the world, runs on basically every machine, and can handle the complexities of applications involving **big data**." ] }, { @@ -478,9 +498,9 @@ } }, "source": [ - "Couldn't a company like Google, Facebook, or Microsoft come up with a better programming language? The following argument provides hints on why this cannot be the case.\n", + "Couldn't a company like Google, Facebook, or Microsoft come up with a better programming language? The following is an argument on why this can likely not be the case.\n", "\n", - "Wouldn't it be weird if professors and scholars of English literature and language studies dictated how we'd have to speak in day-to-day casual conversations or how authors of poesy and novels should use language constructs to achieve a particular type of mood? If you agree with that premise, it makes sense to assume that even programming languages should evolve in a \"natural\" way as users *use* the language over time and in new and unpredictable contexts creating new conventions." + "Wouldn't it be weird if professors and scholars of English literature and language studies dictated how we'd have to speak in day-to-day casual conversations or how authors of poesy and novels should use language constructs to achieve a particular type of mood? If you agree with that premise, it makes sense to assume that even programming languages should evolve in a \"natural\" way as users *use* the language over time and in *new* and *unpredictable* contexts creating new conventions." ] }, { @@ -491,7 +511,7 @@ } }, "source": [ - "Loose *communities* are the primary building block around which open-source software projects are built. Someone, like Guido, starts a project and makes it free to use for anybody (e.g., on a code-sharing platform like [GitHub](https://github.com/)). People find it useful enough to solve one of their daily problems and start using it. They see how a project could be improved and provide new use cases (via the popularized concept of a \"[pull request](https://help.github.com/articles/about-pull-requests/)\"). The project grows both in lines of code and people using it. After a while, people start local user groups to share their same interests and meet regularly (e.g., this is a big market for companies like [Meetup](https://www.meetup.com/) or non-profits like [PyData](https://pydata.org/)). Out of these local and usually monthly meetups grow yearly conferences on the country or even continental level (e.g., the original [PyCon](https://us.pycon.org/) in the US, [EuroPython](https://europython.eu/), or [PyCon.DE](https://de.pycon.org/)). The content presented at these conferences is made publicly available via GitHub and YouTube (e.g., [PyCon 2019](https://www.youtube.com/channel/UCxs2IIVXaEHHA4BtTiWZ2mQ) or [EuroPython](http://europython.tv/)) and serves as references on what people are working on and introductions to the endless number of specialized fields." + "Loose *communities* are the primary building block around which open-source software projects are built. Someone - like Guido - starts a project and makes it free to use for anybody (e.g., on a code-sharing platform like [GitHub](https://github.com/)). People find it useful enough to solve one of their daily problems and start using it. They see how a project could be improved and provide new use cases (e.g., via the popularized concept of a [pull request](https://help.github.com/articles/about-pull-requests/)). The project grows both in lines of code and people using it. After a while, people start local user groups to share their same interests and meet regularly (e.g., this is a big market for companies like [Meetup](https://www.meetup.com/) or non-profits like [PyData](https://pydata.org/)). Out of these local and usually monthly meetups grow yearly conferences on the country or even continental level (e.g., the original [PyCon](https://us.pycon.org/) in the US, [EuroPython](https://europython.eu/), or [PyCon.DE](https://de.pycon.org/)). The content presented at these conferences is made publicly available via GitHub and YouTube (e.g., [PyCon 2019](https://www.youtube.com/channel/UCxs2IIVXaEHHA4BtTiWZ2mQ) or [EuroPython](http://europython.tv/)) and serves as references on what people are working on and introductions to the endless number of specialized fields." ] }, { @@ -504,7 +524,7 @@ "source": [ "While these communities are somewhat loose and continuously changing, smaller in-groups, often democratically organized and elected (e.g., the [Python Software Foundation](https://www.python.org/psf/)), take care of, for example, the development of the \"core\" Python language itself.\n", "\n", - "Interestingly, Python is just a specification (i.e., a set of rules) as to what is allowed and what not. The current version of Python can always be looked up in the [Python Language Reference](https://docs.python.org/3/reference/index.html). To make changes to that, anyone can make a so-called **[Python Enhancement Proposal](https://www.python.org/dev/peps/)**, or **PEP** for short, where it needs to be specified what exact changes are to be made and argued why that is a good thing to do. These PEPs are reviewed by the [core developers](https://devguide.python.org/coredev/) and interested people and are then either accepted, modified, or rejected if, for example, the change introduces internal inconsistencies. This process is similar to the **double-blind peer review** established in academia. Many of the contributors held or hold positions in academia, one more indicator of the high quality standards in the Python community. To learn more about PEPs, check out [PEP 1](https://www.python.org/dev/peps/pep-0001/) that describes the entire process.\n", + "Python itself is just a specification (i.e., a set of rules) as to what is allowed and what not: It must first be implemented (c.f., next section below). The current version of Python can always be looked up in the [Python Language Reference](https://docs.python.org/3/reference/index.html). To make changes to that, anyone can make a so-called **[Python Enhancement Proposal](https://www.python.org/dev/peps/)**, or **PEP** for short, where it needs to be specified what exact changes are to be made and argued why that is a good thing to do. These PEPs are reviewed by the [core developers](https://devguide.python.org/coredev/) and interested people and are then either accepted, modified, or rejected if, for example, the change introduces internal inconsistencies. This process is similar to the **double-blind peer review** established in academia, just a lot more transparent. Many of the contributors even held or hold positions in academia, one more indicator of the high quality standards in the Python community. To learn more about PEPs, check out [PEP 1](https://www.python.org/dev/peps/pep-0001/) that describes the entire process.\n", "\n", "In total, no one single entity can control how the language evolves, and the users' needs and ideas always feed back to the language specification via a quality controlled and \"democratic\" process." ] @@ -517,7 +537,7 @@ } }, "source": [ - "Besides being free as in **\"free beer**,\" a major benefit of open-source is that one can always **look up how something works in detail**: That is the literal meaning of *open* source and different as compared to commercial languages (e.g., MATLAB) since a programmer can always continue to **study best practices** or find out how things are implemented. Along this way, many **errors are uncovered** as well. Furthermore, if one runs an open-source application, one can be reasonably sure that no bad people built in a \"backdoor.\" [Free software](https://en.wikipedia.org/wiki/Free_software) is consequently free of charge but brings many other freedoms with it, most notably the freedom to change the code." + "Besides being **free** as in \"free beer,\" a major benefit of open-source is that one can always *look up how something works in detail*: That is the literal meaning of *open* source and a difference to commercial languages (e.g., MATLAB) as a programmer can always continue to *study best practices* or find out how things are implemented. Along this way, many *errors are uncovered*, as well. Furthermore, if one runs an open-source application, one can be reasonably sure that no bad people built in a \"backdoor.\" [Free software](https://en.wikipedia.org/wiki/Free_software) is consequently free of charge but brings *many other freedoms* with it, most notably the freedom to change the code." ] }, { @@ -541,11 +561,31 @@ "source": [ "The \"weird\" thing is that the default Python implementation is written in the C language.\n", "\n", - "[C](https://en.wikipedia.org/wiki/C_%28programming_language%29) and [C++](https://en.wikipedia.org/wiki/C%2B%2B) (cf., this [introduction](https://www.learncpp.com/)) are wide-spread and long-established (i.e., since the 1970s) programming languages employed in many mission-critical software systems (e.g., operating systems themselves, low latency databases and web servers, nuclear reactor control systems, airplanes, ...). They are fast, mainly because the programmer not only needs to come up with the **business logic** but also manage the computer's memory \"manually\" (and the knowledge necessary to do that is not easy to learn).\n", + "[C](https://en.wikipedia.org/wiki/C_%28programming_language%29) and [C++](https://en.wikipedia.org/wiki/C%2B%2B) (cf., this [introduction](https://www.learncpp.com/)) are wide-spread and long-established (i.e., since the 1970s) programming languages employed in many mission-critical software systems (e.g., operating systems themselves, low latency databases and web servers, nuclear reactor control systems, airplanes, ...). They are fast, mainly because the programmer not only needs to come up with the **business logic** but also manage the computer's memory \"manually\" - and the knowledge necessary to do that is not easy to obtain.\n", "\n", - "In contrast, Python automatically manages the memory for the programmer. So, speed here is a trade-off between application run time and engineering/development time. Often, the program's run time is not that important: For example, what if C needs 0.001 seconds in a case where Python needs 0.1 seconds to train a linear regression model? When the requirements change and computing speed becomes an issue, the Python community offers many third-party libraries (usually also written in C) where specific problems can be solved in near-C time.\n", - "\n", - "**In a nutshell**: While it is, of course, true that C is a lot faster than Python when it comes to **pure computation time**, often, this does not matter as the **significantly shorter development cycles** are the more significant cost factor in a rapidly changing business world." + "In contrast, Python automatically manages the memory for the programmer. So, speed here is a trade-off between application run time and engineering/development time. Often, the program's run time is not that important: For example, what if C needs 0.001 seconds in a case where Python needs 0.1 seconds to do the same thing? When the requirements change and computing speed becomes an issue, the Python community offers many third-party libraries - usually also written in C - where specific problems can be solved in near-C time." + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "#### Summary" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "slideshow": { + "slide_type": "skip" + } + }, + "source": [ + "While it is true that a language like C is a lot faster than Python when it comes to *pure* **computation time**, this does not matter in many cases as the *significantly shorter* **development cycles** are the more significant cost factor in a rapidly changing world." ] }, { @@ -578,15 +618,14 @@ } }, "source": [ - "While it is usually not the best argument to quote authoritative figures like the pope, we briefly look at who uses Python here and leave it up to the reader to decide if this is convincing or not:\n", + "While ad-hominem arguments are usually not the best kind of reasoning, we briefly look at some examples of who uses Python and leave it up to the reader to decide if this is convincing or not:\n", "\n", "- **[Massachusetts Institute of Technology](https://www.mit.edu/)**\n", " - teaches Python in its [introductory course](https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-0001-introduction-to-computer-science-and-programming-in-python-fall-2016/) to computer science independent of the student's major\n", " - replaced the infamous course on the [Scheme](https://groups.csail.mit.edu/mac/projects/scheme/) language (cf., [source](https://news.ycombinator.com/item?id=602307))\n", "- **[Google](https://www.google.com/)**\n", - " - used the strategy **\"Python where we can, C++ where we must\"** from its early days on to stay flexible in a rapidly changing environment (cf., [source](https://stackoverflow.com/questions/2560310/heavy-usage-of-python-at-google))\n", - " - the very first web-crawler was written in **Java and so difficult to maintain** that it was **rewritten in Python** right away (cf., [source](https://www.amazon.com/Plex-Google-Thinks-Works-Shapes/dp/1416596585/ref=sr_1_1?ie=UTF8&qid=1539101827&sr=8-1&keywords=in+the+plex))\n", - " - Python and C++, Java, and Go are the only four server-side languages to be deployed to production\n", + " - used the strategy \"Python where we can, C++ where we must\" from its early days on to stay flexible in a rapidly changing environment (cf., [source](https://stackoverflow.com/questions/2560310/heavy-usage-of-python-at-google))\n", + " - the very first web-crawler was written in Java and so difficult to maintain that it was rewritten in Python right away (cf., [source](https://www.amazon.com/Plex-Google-Thinks-Works-Shapes/dp/1416596585/ref=sr_1_1?ie=UTF8&qid=1539101827&sr=8-1&keywords=in+the+plex))\n", " - Guido van Rossom was hired by Google from 2005 to 2012 to advance the language there\n", "- **[NASA](https://www.nasa.gov/)** open-sources many of its projects, often written in Python and regarding analyses with big data (cf., [source](https://code.nasa.gov/language/python/))\n", "- **[Facebook](https://facebook.com/)** uses Python besides C++ and its legacy PHP (a language for building websites; the \"cool kid\" from the early 2000s)\n", @@ -684,11 +723,11 @@ "source": [ "**A**lways **b**e **c**oding.\n", "\n", - "Programming is more than just writing code into a text file. It means reading through parts of the [documentation](https://docs.python.org/), blogs with best practices, and tutorials, or researching problems on Stack Overflow while trying to implement features in the application at hand. Also, it means using command-line tools to automate some part of the work or manage different versions of a program, for example, with **[git](https://git-scm.com/)**. In short, programming involves a lot of \"muscle memory,\" which can only be built and kept up through near-daily usage.\n", + "Programming is more than just writing code into a text file. It means reading through parts of the [documentation](https://docs.python.org/), blogs with best practices, and tutorials, or researching problems on [Stack Overflow](https://stackoverflow.com/) while trying to implement features in the application at hand. Also, it means using command-line tools to automate some part of the work or manage different versions of a program, for example, with **[git](https://git-scm.com/)**. In short, programming involves a lot of \"muscle memory,\" which can only be built and kept up through near-daily usage.\n", "\n", "Further, many aspects of software architecture and best practices can only be understood after having implemented some requirements for the very first time. Coding also means \"breaking\" things to find out what makes them work in the first place.\n", "\n", - "Coding is learned best by just doing it for some time on a daily or at least a regular basis and not right before some task is due, just like learning a \"real\" language." + "Therefore, coding is learned best by just doing it for some time on a daily or at least a regular basis and not right before some task is due, just like learning a \"real\" language." ] }, { @@ -712,12 +751,12 @@ "source": [ "[Y Combinator](https://www.ycombinator.com/)'s co-founder [Paul Graham](https://en.wikipedia.org/wiki/Paul_Graham_%28programmer%29) wrote a very popular and often cited [article](http://www.paulgraham.com/makersschedule.html) where he divides every person into belonging to one of two groups:\n", "\n", - "- **Managers**: People that need to organize things and command others (like a \"boss\"). Their schedule is usually organized by the hour or even 30-minute intervals.\n", - "- **Makers**: People that create things (like programmers, artists, or writers). Such people think in half days or full days.\n", + "- **Managers**: People that need to organize things and command others (e.g., a \"boss\" or manager). Their schedule is usually organized by the hour or even 30-minute intervals.\n", + "- **Makers**: People that create things (e.g., programmers, artists, or writers). Such people think in half days or full days.\n", "\n", "Have you ever wondered why so many tech people work during nights and sleep at \"weird\" times? The reason is that many programming-related tasks require a \"flow\" state in one's mind that is hard to achieve when one can get interrupted, even if it is only for one short question. Graham describes that only knowing that one has an appointment in three hours can cause a programmer to not get into a flow state.\n", "\n", - "As a result, do not set aside a certain amount of time for learning something but rather plan in an **entire evening** or a **rainy Sunday** where you can work on a problem in an **open end** setting. And do not be surprised anymore to hear \"I looked at it over the weekend\" from a programmer." + "As a result, do not set aside a certain amount of time for learning something but rather plan in an *entire evening* or a *rainy Sunday* where you can work on a problem in an *open end* setting. And do not be surprised anymore to hear \"I looked at it over the weekend\" from a programmer." ] }, { diff --git a/README.md b/README.md index e64527c..3df2247 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,7 @@ application that is used to display and run the Jupyter notebooks mentioned above. On the left, you see the files and folders in your local user folder. This file browser works like any other. -In the center, you have several options to launch a new notebook file. +In the center, you have several options to launch (i.e., "create") new files. From 18a0ee7c4c7eea0f5f75c1175b63937dca7e74eb Mon Sep 17 00:00:00 2001 From: Alexander Hess Date: Sun, 2 Feb 2020 20:00:22 +0100 Subject: [PATCH 7/8] Add pdf files for live presentations - warning that a class room session is recorded - template for memory diagrams --- static/in_class_memory_diagram.pdf | Bin 0 -> 163306 bytes .../in_class_recording_in_progress_warning.pdf | Bin 0 -> 14433 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 static/in_class_memory_diagram.pdf create mode 100644 static/in_class_recording_in_progress_warning.pdf diff --git a/static/in_class_memory_diagram.pdf b/static/in_class_memory_diagram.pdf new file mode 100644 index 0000000000000000000000000000000000000000..4de2a0f6cf759caca9c9d1dfcefd563b7e6b38be GIT binary patch literal 163306 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≥S(99*)D}(T9Eqnx{VpdHx1FLNR?rgc+ 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

Gj4DHgR5?|S zZdMgk1uCrWPIF+Ch@SXZ9R8-xq?xtJSJ?b7RrtVeu(rxNKbsxp6`_=ta zTs@#3(Amo5-;&6`rPQP9Q7Wxksa8}*wNve=tm>dTP&xIydY;OwWR*-6R5#U)Zdct^ zce+ERs1&+W^;W&9qUx*q(p_qR8bAqZkQzjl)DSg0b4|dY`JR57Y;ApPHy9>U=#}O{V+RR5g`qs_AMvJ)k~R zAJT(rmYPMi)JN(gs;xd&AJao>o|;E>)B?4D9#)^KPw5f$x%!+QRg2Ujs;jl? zTXmLwQf<>&_9?YpXW6IK4!veHQ@iw<@r>G|*NoVmpJt<)uTiCU}6 z>M}j6uBa>6_ww(rEJ{SKEw5wCv07QJG`oYEmy_iHOJCscvRWqul&cpvb(Wi6Z zzoYNp(HBHt9HOs+x!STihxYzE#{L~+|4lJwIbHPie2i5>B=RG6Gb&2esW#Q8Bx>d3Ij(wtE)yEV~4ZtxadLWLyq6gvFJNh*o`$WI4kG-_q5FAsYhvL{PdKiwqqle?z zCwinl_SSN#IHp9ufn%@eQ8@OFeiO$&(QoNvA1yZq$CT)|aqJcS4vxK}$Ku#0x<3hB zI#^?`=n)!wM~~Ln=U?#1yXbk(==TE8ydQXGeBhZ60?$kcJTo!y$fUp{lLL=T4LmX} z@W}MQBQpYzd>D9SR^XA@fk!?HJTfQn$j5<4<^>*^A9!Rz;E{!aM?MKWGEVouXY>?! zWF|Z^_h0nLXMsmP4?OZk;E_dvN4^X^vN-U_*Fmg&6L@Ax;F+a?XO;z?Ssr+1Mc|Qd z1CM+ccw|-Jk?#YKtPVV~Ch*AGz$5DdkE{Sc;sy0k#m7Z zE(9LA7LjX@+e-D#TG}pPDibwMuS~vC;2Z}b0~^^qag$lCEWxdi&$(3cyJ!(dTN~Q? z&<}^*2abMM3IvEd%fEoA9wg{HAKmr07o%askYC!O5+{eTr7@Flledc)@)VBfvC9`iXK8yCs9wAn>$ zz9zoQ6Zh`fPtU?j9>2Y=yf(KC`R_R{8yXjQb=v_ccg%WIG%wnEquaOCUtiNhSZn6@ z)>S?T(@b_IcivT>s7tGw+O1Mn9G{G9G|Cq_mY)f}z2>1{Icc7LOzn!(qCwTi&Zvf3V<7kXeW;Swps#8oX(v3*1imJadNTAw8!Q3Z+=nif4YOi_g3K ze2FugqfM71oW*<7I1ch)&B2%vegp6qO*^~31Y*plJfPDR*PP;J(In3?Ysu4`XlqGr zpHAHJRTZ-(id+4`uUhsvfLxQzuwb#tt9mGyq86BSeM@tlkzW(*aEV!!c|XBiQ-C}n z!k@!FhQcp0cFvTak>W18pT_2vIX>al&5d-HGA|fU6jDE-{*+!m;TS7CPZV2C6lvp* zqMH>Z3#SxSxh-^;=A}yyHy3r96>dbU61BRmbeC^Lwh`l*)pJI|AH2^`IH7G1!xXJQ zp>7Yy6mz@%n@ZstzG)P@Lh}@^Kj7;ih=&$BVCW!P{vg|J#t7Q7Sn>!47m0ca(S0*t!z4neh9jDU6RP|kW$Uk& z1GNvlmfh+P6vW*;-l))fjW2)7+ma7#zrM&9tFI7_dyK6yfjjoE@Rs}O&LFot`mISX zcZTbIeRl!EognX#?&)g7FWZW)&9Buh!|O)3)s9QPCq1v6&&aNAegncr#MRJC(kG?& zRG$rg!<($k69VXoUdTq3($cdjcg`n&(md178n8g2d1RLl04cq~QYx58>>@l7l}U;@L^Z2Ob_mdWk6}?VS{U32Arj z6Mt8kC62_E63NX+SMNxhSG;Zk9W$Q;p9`N8pBtY*-2>lK-}7qc z9w+s-?T(5~Hrw=$zR$kR16$XYR_#r~O`9u)E7xapx6qDpz5@b>*fz=yl`HJ$K(EoR z3$s@Bjf$(9E4F72j`^-DvoPd&uHIR(RkOu*&A~9=ab@bUsuz=jn-_+Tj2yFqOoF3&IwA@w*7DXqylndGBXp}j7WL_&p!s}h)nD7232wtcyHd3lw> zZYpnD_Kt4eZrGHtJFaZ%w)wSdo=(x^g3ADU_qb;?xzL^v8hH&3wm^Jo;VMWr!bA^o zRFUA)(hjwpYv<)Z8<*9~t;?G)9IILBZ!!4~kD`Xu#Wg>uUld|DHbbtj7GHwiBZuU! zK%%uboQjL7Em+Hi#S7Y3EdbTl7N4Kka*h1j1wfo->gSNZ-c;d2qjDUHXyQ`Hi353} zij4$K;C!x&fLAN2=kRyQFo^-uf&A=JiDnBjoOo0MTmqTAo4p&Ozq^sUky<(SM`48D zp-U^c>MP$p%gf(c=u4G(elD9IIXW!&<4^Sk7i9XgG;x|-giBUtV3lTa4`Zx2=O!#& z;^~XC`nWtFgQ|7k0vd?lzHA?YH9_BPpkEFyuYNXcAM2JS%Y(O`pI`gs8Z!DmsaA;J zWBodAtV`+yJrK+I%a5wVEN>CUFx6beXEZUg_)Q9@l0HiVhu2mmC!YK5r-SYs9 zLiNLo9{m(mLsiki&lI&|+$A%HcRxcHTMOul-0r04hB2ke#T83w^4p27%*C}c!4~cB z*)6wFu{skw^+#Dmk?9!#v6TE@5kx6PWHBKmXiy3`$tfXGF) zj07uvqNzXec34xve)bBt;zR{|?Rp>ylcD}H;ARR>MVJdu6a6_tW`=y<3rZ5H0iKK^ z6Lv@hS(A;4)CMl>mAPND3&jOvKqnDj0LAW@$W@%1XgpO18p>%j^}`-q;$xh1Prq+f z8_W&=nb%!>Ea6Tu=|j-he{)2w9=$w1XGB3U>mLPYc~kEmnM+{@Z3nTie|U43hg=ia zf|Gu`bk{6Mv&FteuoBr4>xPH0vv_;9tEdN70}^wnd%Wo{)T!MmjuqJ2r;ascC9xq$ zV#=@xdzIq&*D*xZ8@2mayy9xzK)8Z?A5?%6*)n({% z84@+xmwd2_(hUW=NKr4(0+}U>cg)^}^a^0_!tjM)a8+%Ef(X0->Q^6@5Dqe}4o#=T zM4~2{isXXp#&%%+EOX}`^G|W_^@f^p0w_<=EsiV0FwSVYw@z^MeZ6G457LVc z6+lVNiWL(GWxL=+nr98U zOaGGB-`WL^$*2Tpf!q0 zTk!5J!BCb7@L!Wm0_Cz~X@aLxgkMn2mDMe=1ywDNZ;x$#VC{p;jm#gmHs}@qX%I*v z!o+CofTux>XZOPhu+`#^FMK0z5X<<%e-dE-L2NJBwrIQ)R{QbmB>d)s>m-=53wt%J z>$?Jzsa+*SW!t$?>t4OynhBCnS=Mq)wc7;2JalZ7DK#W!;@9`Z2#& zk6D8OqB4aoo?&yQ>>Y9FyQ=!$qq5P`4_Cp(E+3gOo#)d&9!KS z#ICjQl8P7Gu#SqAJqT*X>(|50-|%8L9Xmgs{DW4&5DXDZ2M82{`F0qe{7I?md%zc| z+IxPoQ33rRny9kxd$|T2ehY!^v9<58?=cteARCc`-hkG@dfea)y0ayM5Rr*u&$<6t zfkSDnZGba?^4i9@!IVXB4|F==Nw58}eK_)Jh>R5Yp46vzygo?sZ+BDwA2TKYdjGb! z=rlO>P5L8LOUy>loL_j6*zTRm;1lz5(8G23@nnz2usbVD&|K+VAr9R~1$rN;mlK=` z!GRIMfe9fVE7Tn;w2%?umI*=17%!g@0s5aYAq8EC%;trGiruUy%f)*)vUu zo6`m2?y|SSUi~8wsdypIm9{rTKX1Uh{jYZ@!M}KgC8?0g0T_mYsrg$?p~aG3#tWDj z8b9+-hR2v@kjLw4DU*e2F_ZTV>}Z4XP?L#k5tH*~u*Vr$?=-Lx-VL!qAPunLH*2Fr zkduqi=5k&^)&7!n$0c>bdt=kmys{>%dTY}5+#S|h?~fa= zPN^G^8!?d3W|$}?R`YrPb3$wPRiF-T75v;9pHRW=f-kdq_{bBT+p7y01s7& zYb4-pZV)KGXn|(8ub7$j(<~^M2)7axx0k&Z5>MFS0#E>hw z&mJ?`(4HfC*B&t$*;`JH1iwimym4Wu{%=i?DY`!9c#St7?fT1`M)N(qMmXzLOc9Gt z&}9pTb~TiCHI}w5e)EQ>bp!m08Tm>CZr!1D-66Z-xQ*FmpZWk_HNZ;;`?(e7%0YEw zf73p;VwXUDn6Em(3lFrKw%5(YiBatb?_3`3J1YE>RQJ|Pwx_W{w9#!#8dYhOj~v8% z7`2z}6IHFYIZebP8HN{f_JNUpA6tj;&qE|(kWzpnPFQ?c?+b86t>EXo>8-)Y{Yy*;)cQx<_qoubOp-;`Gw65 z^$i8`B5Ql>{b!Oe=9pRKXl6*X;%$or=5j1tw1Ui*iQpZUAnl7KNRD>GjkMs9L-So> z#!dhO&WW?5I~_THGJ8h%DrFI-yT+WxxDEvaT7p_o!`#t3VR8qocAJQ{LLAX^fk)I~ z+Z)9Mps4J|Le>}X9AFo%kT2z~LM+%XHMjVKWd4RP6!f;;+kCw^vqJ%jSw zbfUXk;H?}*4g%CWzQ2b*E&SP9dehg9CqoS;!5Ag5x8h&pU*!Bs`Jig=+vx=>D!#vG zBfmEYdAuR@}1Fe}+4)(T?Q3gp%brq&AR)(WcD z)3z(wmLs;*f}iV)u#)ZLi}PW2zPNQ4sl&c7wK>8UCE!mgQ!UppQmgdas$!Les1V(; z&QW;oXa))tb(AuO3P)}xbvJAuKLq@Y!R`RedGaTy6nKctiExypqZW>!T=AK*=W}n) zZfjxed6O2fYY`ap&5eAQg3pCs^FAltjj(+Ft|h~BhR)#lV#D*{5AL2Md}-Oj(}gT2 zT+S4HIeMZDc`5U&&h%Ldm~#~;Y|hACF&vWPxb`L`B5!J<3 zr^XM^Z)85{{4zNu3^OSwG!Lq8+&)3Jg&C*n54dmmpSyl;N#EDmJx@G-?NryqDA!%9D$k#$5qhj*H`{90UJVl8vN3%?FOB!(}-kivD? zuR%UnbbbtSn`ZLWTHzt3=klft&hkSxIT;dI9*aC(ZdxfGiS>5fkiUa#yx<(t*xm3j zZuKLUZh{KzrM_Y}_4KkY*ix==#36xWzT!#UC~8L-^ysnAX5!fph1Z( zsF5TpX$SiVKt@!Yl~xIzL^NWq*L>ou?<7kjsRQ++ZILvYsuj6 z6xm4w(hGWGmBN>c1C|SV{n%kSduJe=nL>qOKJs|s59EuI>QAE~2ZFuCo1+F#T$?7W zmczAn5aM;7%$6nf3Q;7-aZZX}^d8`~cAVAXmpJ^wX8Zy5l7V(q_^`RonXE>hbGOVH zAc?CaLG^lRRm_W}x};8UO|hiKFn{OWJsJWm4L3FZa!urr``HIxc24N|LGrQk*=&2$4W3{6)d@cZncA z>&AI}ur}!-_o+SQNq(wka@czPVb3Zk`0bkOn{>HA5^ni}ba#mnWh$8j0R&puB#6Gw zGU(zxf&4-Dr@lQp>AXi%oaizewmyY9RSG3Z$XldX6mLf#rc!?prKlLCXfYW@*dbQ> z<}dQUcd&?&3bIhBR!le-1k!~E==kZGoWx8dVkLe?j><-k_R_3xA@l{4zEj9$UoX5w z-259r0dh`$so@qs0dW~IaqDSLX1)Qw3p{Ilu-Rgf6gdjxd$%+{8*m2g@5i%%2Zs;_sUSsoA{U zDDX3vOM|B@6%=q~3jr}nBJgoM{m}Lpg5M)mt4=hFe)H#51u?0YWqOP(Lr$3;-|3xN z0(6kyGn(&ud>*5Q2%R0M=qO&^@12u*(IGTh6ZiE;P|beMwr^B7MP}r`rO-?X@m|QF z!gca{3+6B{SKRE!i_raX4Rv|U@8dWoM;#-Xlah>swJEngyPhgr@47UNARymT)i>0Z zom%8mc`78tWM+Y$RW^s`-oJU_VBy$1SDlS}v$MOTIXqc$Q0t;Mf8|6*I+4)5CxLso zvub6v9@%||pmJp$uU9;|`n<(th-F|FGOU(gmf3&DM3TActS)3k^1_F1KEqIZa4C(Q z`ukjx9J(d>S~7rwB94;T;6gAuDgYK9%Qd^F<4 zj?E7ct9E*qC@Lg-Y^;Zoi)o1Zwxt}O8E~&CT(NMiQB`&{S{ay0gjUNkGpP!T4$GWF z`GjQ&9G2MsOIAd5fME8M>1w+L+sO9Xjxv?keqCKDL8a(+2ws(Z6e%=IA< zC4q2G4!u7#tSZ@D?xx~hQNH()w;`3!j(Z`aQg3MwKq>npax!{1G zD@&{0GsajuTXm-t|K`kwEStkY{kY5`Jz=CRH?5-soKJc(8uLQ!dqH9i>|$a>TKXzm zegMnRr9}d z;V$>rY&`TyDQ(QD28$8X&jy01APwuuT%&amGXeIr#Gb>qZl9^wgz0Z`9Mh?7J4KqN zLPnp6Im~_s{l6@e0$tiUDQV|wbzjbk$*KytGF7H!ImI?h$-P~F{;}{5@@;$qYBP6f z6|ZIpi`6NL9~5(^sqtqb#+T0<7ruFN&xllX))?sjBfq~O5u0mW;Od%co0=VJ?Q82= znxUL(Q6<2&wbxh00bk$&SI~xtKBF>!>8SZUPcEakoh?b??~jpQWB}5#>HbPcZLoL7 z2ZJL4n&0q7G_b{?5c~ebjIFTX2&PDyr=S7V-*@2KN;f%~B*Dn_nDj>aEmDj-i2Z4# zLYjyQn(sq5INRJlIW8i~HS8_EeA*s|Bj>Sa{pp|Q`H+9rW3p}ApNkBB%g1#F-6GGa zI+xf>ALWHraUk$hhMcK$o|ZgCGFbV*gEqh(S!Kpgl`$+}^;**_@jDpols=m^!!FTd z&lW6c8;5TFYHL^~bIiEZOFCVoV_HeA%bk_n7Xp~65sp9Y;?z^HMu4ccd8LF}Cwx>m7V0zm-6VifO_5v&?pGjgi>HPf0b=joHBMsaE&7=$_Tg zrM_nMe7q{t!u3n-n8uc$`FTP{>TxOW=cnp(`?OS+_V?|c<+1HDdIJH27OrU=_M+8& zxU*gVu=i$Pp1yjO;$8hJk9FqsqEHVPt!+!EDnVnO-^J*{{UM}r%0xs)O6Q^G=y6la z0uEjeAS>#+-;dKq?e$6I98s1phsRoEEo>eJOoaZd`(y6CRAa_yk+QN-Vvke*I08h* zCjuO{+$`$Fp2Sh_CYtS4;v6Ge9?$(b%+%HCH8e}sTP13^xTG!NjQUk#-Ls1!V)jCU)wo>Apq6Wgw#W5XT_EvW_xkjv z@*{hkk3-%AaOd(@RLqA{84U=RG{Nc_{rLEu1WQOy&kD@_`+~n`ZR%84MX+Pvp~~H!nw!kTOH4tTf6Wnd zhbE3q#yQJ^!i&H07nj+oGKJyRdi=zh0t?QatHA7J#;m8(L$dxZ;dRTf%c+(dqlE#W zGhS+-xDztP9Xn{rCsUVNKv7An-qrPfW`SL!^mIH2>;S9fC}RE17BW@~ymB)yX-$Fm zbz*EtuR#qB64i^%bgZYbasy)e)Z=HPADNYvGx+wc56xM;vUoG9gJejMC?@YWd56ia zwo3B2*cV4i{JxZ5B(!wgCRl3J2ZHsK#+V7Mw0dES)X*coS>khT$4TU=?wEl2K@j|4 z9&X^b>vQ6W+-kKBZ)vH?`wleemQ*-xKlXM^?oMAW=kJA{(rumNo~cM40eNwAlRP{~ zfImG*UzUUMPiJT-gl_~&v&WNdhlQSzP$m8G!^s-_No)hZ^V96h1iQ=(<^kAb?cyjx zbOtmVK6N&iQQz@#m~)Jw&&fSBwqmb1%D>K73Lbwku0u+d4vVx2EFu0&I7y zdJ}-;9HVX9>#)Xo-2D6wG8S`CN2!q?if*@pb$f2tWk1PhP&{r z%hQ22DYKzx#X+@ju#WhlA#QeR>=o8I^IED*(~p;wfK}?kB$>9cyw>g7U-dxLBgpCJ?av$I z`G>A&4r}SU^=lvN&hEfnG9kO3;C-;oHyVPqF0T@GlTEFZr-xtdr&funVU+YR#*1f5 zC#Or#ewI%UJ3P-UM=3R$C5Y^-E*wxW-s~5LL+cO~3Xigt6O7WkqdlpGUhYMOYg7jM z9#JZ4w}m@=(1ZEWp)GLUMR6}K-7Xu|%|pa4u#XDjzpIxrOOV7lH7~H*OuoT3L%rOx zVKx(R1of`WPdn(m%%#qjHpSXd7poa^DAP;LO}oN#6j?0|pZmoa%yZ^!+^Y|r>TiOF zvoNr-Q^`~HFm<1)cK>ZU##JZ9<72&WVx@OBxXiCv<;jJ`FobUljpgFVkIy(B=^Kj& zirp27$~Bj%<#DmZgbRNBav7yr@}Sciv2&F}*sUtE{m;d`;5Oa62ZE)}zqJNd!CEbz z0|e@=6z+$LD!uEP$L`ttn>Ys5NC{~#O_j`8_B6zD*w1A;xa1EzTxs1> z9UNTRU%jpk$DJ?Rm$@kblMe#5(ym?{pQ|O?_&XE23n&leTh}+h3y;v4lVWE?WwtH1 zp^=q5ukL-K_xt&=l$1XwDYh{dFiSCQRu^^LRQGz%OexNM?=Se9JR7V2_h-UuR24LD z&j~{#2o4#Y9q1c;jnQ%7o1FQL9m=0~iqpd}gY^oJdo&u&x;5Eab3+JfvEt7^qNm@-QGi z`b3dH--3Jvh8O*y#&lV-O(L@a?ti|w(WL(I!O{w03@7HR%mMg)(OE)|zwW5-GS6@A z*;NBTvYhT(arab~l(eWNPE2^1RQMFT88Jcxpf&00&`=?08Y zknu!V0|7*F0Lr8SA*$5C<`sPq@O|hb_lMzbx?W|8d-ZUQgN!!vS2xh&Qcb<~WR$WN ze|d(p>#72Zi_3 z+$rpacc>mJeU7Wrq{_aHT?&NnBTvuJ)-|c=pZdG_1kcgKuJnWk{A)gV9mEzZx*Qcx)tF)0QSucv=lve(9{@J^mxcN=6n|SzQ4VrOnRH!Un!qL7LYwv>xYX zuJ1B6Z_*tp(3|4~SB#d`J&(y-N(PxJ*J3=-TQ?0jjaF5v*InFZ4z>&Fd;~EI4&_HL zPxYZ4)!T|=czfKyKF`khwTU}7@v4?duQSo(Yn(Lnq&N+&c;)q!0~e}@e zRhjDj+YQA%{mmGqC5;*ceJgiMdEGYj+RNajeMNC6;$VSOO+biI%UHbKy>ubp z<{`{n(|N#X-CYv-RCPkrMU1{qi>-}T`WEFg-epw|pr~9Qf}H4 zO;+jA+HR$aknMIhMnNBg7qd_x@~UYcc76iCv$f8_$oqu31hyj7;~h_)uv$Hn+O8_& zsh&{v>ce9`4c@psl0_YXP+($x^D%6EG$}z`>GY~jzofFNIx04n>y$%?EaAvYjdu6S zglxkG93U$`<;P?H>B)UFye6qMq=ez!%~i)LL3`1D6Ii`BoGd8IqAQ?k^x)?mPa{5a z^r~oe{o~t3szf9TsK#5Vhve~I!Hl|eNF#j9NRd0jx{2k!8;}$gg4N-Q8W56z03`?( zjqe<9;m2qx7Vv8@cRg4!8M!zGB&C?#?5l|Nku;HgJMmu~J~l7I*(b0LS8lIJ zv?<+NSAMY@uWUQbW}oPxYIE39K*w}>ckvx>SaXK?w2xW(k{_1(N$YF~PFsTkX3u+{ zS9ka)0#%NT2AA^cxP>B`->lM~X|(-AV+zQ-LbXbGcYcqD?oW}2yJc(WX(&(IUnhri z@az^%ax86NCE*JHhBIYsS_1TcqT+I#9K|O(-IPPY*e5CuD-*C^tm}d7mcEU*6BCdT zNio_o``6T?sk$o@GzpKym}r`MHVxX6J*8Dqq`;|T{SCZ6BvhtYQqQk;jg{3qpIvLbD0@?;Nm|CVGvQF^?Agg% z$KTGZU^=ZC>MY&<{rhnJ++`E$HNbIaMAfKtxKH;rd%4E_amO^6rv%?atyiTki>th= z+<-wqtO96fD*QH5Rt!iqGiXTbBN+`a%>kUvb0o_)@Dg(tHi&sxlqtp}Ul11f3KaP| z0W^Cc(l2wniOlZo)ORZvN-_G??#bKfVGH=1q9$Lplqu;L(?>OJybr{pYb9*dH1GQ$ zf3__lfH@!1s%2w28;#2)(WQMns{b`2`y{*!&%kXHMWv^0PIGlk_H&z7Aa_F*ui>(@ zSw2E<>*RDP*}KnDb*NyL4Lpzq$JSR78P?0WdwT=>@r77uoLvGBV`^*SF|D}6u|IYibd%V01;(x52O&uA;tqq+`MNN(EOiUSMO>NDc zEr>X{SXkKp&ju3_6FV0xGb=woJk0;~w%ju>GNHYHFFw9Zd)XyV@F$qm%O$7Cs{Ne+ zR03R}Rz-;7q9`h{{|1OA$Y#ny7g0AiFXb~wl?v&U;@ar0D_b>bRsI%} z8?4fb`?omR%}luWaM|y>`RVy|BjvvPIos>Xb;`%hOcHD7M{g7dcH{3B_Ju4PJ0J8H z_|YG~I;_ge*JG~nS}}I&Nmx_0RhsPkoQ_+!AzKUa{r$?S+l!y7h6OPEpV5Cn`BhnI zZg`dkiM-Q526WsuwX2yY5l!>_^frVQyd00zz8uW4dK&m)&#+sXrTbakml~Ro403SM z|3!bMb&YxnZwmk8F$at)e+i-byyr5jyyHjlB3P->Qd`JRVvtHs{^Y*aYP0pTR||J><~|ry3vOd*}mH$W3sE}oJ(;2m621t1O|e8VY(Wa} zJl);els_jb%`c_FQs_DwB!*Kbp_D6qJD=`OYHt|MQ;9kEh`-nlD91w( zWQYN&HR8`Ac5b9RY^(Mn9J|sGSYJ@24>Vh_oqSHdElh|G;erAAHi=Mk5>}XH2PqwD zw_k1$RISfsmyji2k2uM%Gu!RAH;>^wv)2O0ncw89B9j6}LsIu9G(2JgQT3W*b?7-W z*WV#W&oweYj`gep*T?cCnq-D^3%BMbdfmBtccpt^@leQH`&#-Lgz7#1{n1n!pOx8R zRKy)~M^!Bm2M^7BdVDgH6*G=AP7}3sS==~yc2FRWl}*XX^wq<7ebwV*aHX|N9*|9J z_7qb|)vG>Q{~~c>Ab}3wqU{My22zuof{v?z6W0tABaBUL_S?Ei6>mS8?$7W?v!zw& z31Q0Jq_SQz9lEoIq{1+Uk({tX)5$USAdcVVTlQ@Fl;wq8ig;IVdv6szt-r1%yct{S z{jnCLn?suu*RTHLrHPF}k;EAIbIf{6oz1Ug@=LbGzb`qil;U`#n3pbT4_wC&bbjj$b!A zkChfT*N@{AbL^_U6H5PtmY5#5`XTf=s`{v$ALI4p^6k*){T{t-yKoLZr>EBRDN$So z@E9N3$&D(S0Jh{GoENY7zTF9n7qH8zS(Root!DKeC2U#2<;5%y4c(M|J*Lqb8va`; zzV$bd=VCo^n{CAvp|ghsO={{1+iPo|F_sgYI(bb?7u59yT@|R9v*R1Jg`0LQ2yez! zswVz0@q@W7O}dsSmPfI=JE2q6iZnf4#p#nWmDrb+#nAQLl`?D3f>Jj-)&Hh{?VuBd zAu~b+Y(ajKcbGMHc~uEi&Cf-@J5{aNNK)@W2DUfP?~V#B40!lEx5A<<&fwmzmsV((WH#-Mdm7SKSd$5?2f z4q($&w3E7)EO}s4sRta9P2Wk#osNe^jB?F#>T|Kxo1u=OT5T+8gQ*xUo#x!JFxg;Ze`q^ytlq!X`@wN zsT<*Hk~HY}%z9Hl~Xn@X!8X$CwtqQNTt?J|u8Gl=|6lYpk&W)%e{g^9l8FvB*KFom^rTbd9* zMSQ9OBqD#vjl6BGLhjIXpE^CkzPvC%#2hfBx(&T|T58)lu5xm7=oCIz*WOh1jc$rK zJ!bmkouf(B3&#zL+@ImPkj1%d+~W$yEyt(Dvk?n$`4s~ZWOI2stu@3m=TK24sJV2d zez?ENFl{N?!A+4>T77SK>R9LD-;mX$YR2a5veOLj7DfT@i~f`g^XQM!q>S5)U#EmQ z^b?G#X*&?&I~l=Gf*-fBt3_mON?c$;+uUfSOu>U4cVvqR$A&IBTh1G8K~o$1Hz$XM z4P`V$B&P->msHtcnww@_d4-Co-FR*VdJA_}ktOV(4R^A!`pv(kba~PS<0$p4+)etX z{Rp?AhivRml4A{t`1q_IWsPhm{>HeUIGIXMXzC$2xo)-P0h17Z&3nJoPNy|FWQGjN zT)?tvt>=^#q${7!>v444UsSx{Eh|}o(FH5mdC-ry;D3^=549dT;uhI4I{Vw1e59#q zYwIx~o0 zm3S+6E(f{>QaK+P66{xam;i+GMc6V_4a%3Kd$6ot@f;x(1G2Azd;AR#5Cmuk-9!A5 ze)CVw4d}!gZVo+-luhvw5%Ni{`4w23bAz@k1w;i5L&qZf%CAVcC%$`!8?x-;0apQXfM@_b z02$~BWbBi`B5{W{NB#+&EvSrbZL*%@)+PE1}3o=%uGiVopmN0x? zdab{rSgL|O(h>3z$`O(osu{8w3N;vXQW!P>MwlxvN>Q4M7!9=;HG&LEho~=voadJf zKv)=rIEOJhPGW@o0I42YGvGxtOg4}WX`05i1YxCFC;UAv;dC&h%Ki0S6L_y)dW1C7nKuKawiY~4Rin= z1B?L$fF4wSQg3Sb@lQD|c0#f|a`x;YlyfEzdm1O>E0`~%WnIdToM9{C3ol6sIkIg)y$d)f^oP-fxr z8k#}byr*Ca0m)b91>WV!%JTU?L;?N-RIzJMezl*}3xu4n!0s=c>rp`+^gU?H8&3EK ztjV|Ig;joF0YCx@5tZOST-HfC6+`D|2cS>=9jjICklQ z2*7D5x1SU4SB?VksmG*OL?2`Zw&EY026}*2J_Eg|7p2}#wA+6F)qvJ$+2(}NDicT8 zv<+Do0iyAYQfE@lEy31o936>Pb^}`>9g)cz3LUZ5zr_ze^__vV43s(;j0{57q~kKs zDM;dAb(dk+5Jo&mn2<*5M9n{q)Jf=J2G~jH;Rfg>yi?BTiN>$vMqgvHMo2@_8=oH^ z|3EfH&Jl>ba*gpPO0bm_K`6TBy(qcnZv;7VjOkMGDEfvtQjRGoT?xKIkHsq4O1vVE zAu8F5tj0LfjM1HCH{vSU3bqj(awl3TRSUJ@98xFJD0Rm=2A5M_Iwp=QHs|R?FzXNc zO%Vpq6GaPzTm-OQbqd0H;Z4JfHdGyw!a>MdTY3D4dII2&yqp;c&IJ3PhU|uFy(5eX zic+aUr9_FSWB(EyQG^|Od!J67g^`KV4M?z{fBqBMfi+MZ;-nK2QAGU>pbBKpHO^Dx zOeXz~V2-&X80(jN?t?dNdc_m6H5{P?1nKFz8QE?bk z`T8>t*$^w(!KAJvZ%aJ+eAu5a1aZ6b5yNgXEJ}xWT5B(g8(sr8BkalH7|Zfu#|EE*%F!!U@82QIE#V- zWe%zgfF{h`CoD-qhJs>|b_?JfmK)ip$|=AT;flC(gS#=O%E|wLKSWK8RpJMh`i9+s zjA>KZ<$pjNB8}lv`H6er7rfJsu}~=#e83#0Q1u9|#@?ZgB~U5k^2RWS-2D*$@J)PI zbS>D3bVQBh_sjI|OtVMG<1hfW2X(`mOyHtG!O>p2xJz9 z%*(Rp-enC;m=Ui1uWVzmRMQ2#p)p%Qj(KrOPr7}{t{~D>^=3G4)UKA$E!T-T&5XD9JgoDkEB!ZJmQ(@$nqWCzALNj-WD(WhQzL| zHmzPO9Nv#NAit^X2)Fn?25K2GHjcvxvY9Ge$8XU4y=j;387Ht)xqUPWY91H8vP5_~ z<AudFEQwsgfgJ-fOPc317j-AS#R!8DiFkucN1kEg+ZZ{&A~i>gUA&8 z(%>Q4!gr=|Z~!w6uNYGnQjVF?hT}G59KHp|6$daFvKaCVFBD{560lz8_xrn3Poq-5 z>iGmBC_4$FK*TOX&uXUV6wk#qi*da=qeQzBm44X)A*-r&DQ|qDEUQGfQnw1-cF_^R z##Qg~{VX@#t+Z~>M^$kUQWXy>bHt$+8(A1_$c)2Wz5<=#XoW%Gu-8FdP}_GtmASQX zlyI?rV_NrO+S1f*_^+w&;GnNPz4lgjR+DF~Rc68BQ@Orb5v}%GtQ4=4L z^>()M;_SgT@D3p~5wV^(S4!fmJa0FTSpQ3re@jsfK5vL4N&tnklQh()a)<-m;_o+l zxF#GEoQ$|ge?@2=Vx{0?T%lQ!>fcfI$A27we%oI^iM{U0zV8kd;F;==G3_4|)#-Ou z7x%YsAQ%4cJ3=p9A27bKgbtP`0N7n6cd)Gh#9b`@6zQo6awm`N4ZCSd`ncyH`4vc* zFi0o@c!KO!7I!Q{zfZJDRgH)g)0`Rbf}s79vwu;sGTi0!KnfO?Mg*eQNH^SXs03n@ zf(|Pu>`Xn%29XcxP_m4E7(Sh3*(a#KhmDy2V z`I*vpXb<5{SPiJyv26WW9elpy*$QF{$e4-c=%=%{Dve39>pRyfOJ4jy@&$DR>W&ch zUEUbCg84=q=HxwJ2YM+=;81Tzr(fFRTKWZQnGHJg+}`!mL-lsm;u?z|+W&!j>ifL; z;fN^i#J~%V*iVWz?1QyBOol%X7}vLvdj7ZS$Q>m+@bd=th5Rb2WEa~VBRlB$yDXiO zlCAOq^aIB?$m{aQ2ZA18yPt3e-5vf59CCNM^?d7H_*2H>mU*ocr`{94>I*b<))9|x zG{*XiYO$N{(f-Fe0YF3t%^P@Y4;PqfJlmlbF$1rRr}?1aY@6~iu~&yWPAlvtJ9K3G zaJz}6pl0-nEAmfj)5a|ivj6Mdv4#&b0^#+YxY4lNfNeU&yG{TNdTE+8!6qm93{<&e zn8J&1S4nI4y4d|VR>k`T(_Q5b&Lh@R!97+JPZ;;ebZL0B`;(=a{JNo8R-g&K!V7ym z^w!xOk#F*)8ZF#yw`%l5JMYcmg{BiRNAj8U1|*x3uy0u73)eEn;52egg)L|A5&Hu_ z#t2*>bYDe!SfPvy0Ts*G8?5g(^9L%WBW2^?5l*g>UKY9tm4CW#{rpMjs17!AS-EE8Q%XDy3rc7naWHKv}>xRZm9X0dXIm=A< zOx9Wd57OQOD2^ym!wn&U1P$(x;O?#g0t9y%+}#El91`5!H9&B88z8v54}-hA+hcd{ z-ralOzPk7At@`V$zyF@@>Y6!Sea`7K=hOyg8K(7N0m)p)cC6EhE~c84%EL=mX%&@& zw+!jWx|>NuRL9?1{X&f#T-na*cs4pyS?FmKwK4qe`d(fJCSKv=NaY6z@mnGnHsTVt zrUDmrbqOq5k`7W-(i`?~*$=j$?ta&d9@a6<{6-ZGL(Aj>aJ-$LTc4iC6%AN`K*z!- zv8J8(dA;%MRykkl;r8d*o>)4~61ik)raCPaf>mGy)6f7T6Aew~P*Q@a7TYEGHyuMo zGF?1o!MTXF23wMuiJa@!MUTkHnT)s5ed+9;1EUa~AOj_>)OYC_lZ4>Fd{Zko+gNSv zyic2ogX!nAC62#YHh7#x@0-esbjv-Bc8GxiaooweE9g1hLiYGyAutzc=Y;)o0HDx0KFWr-keE zmrK^SupaRH)-L8wVq#~Y7D!@rG<&bh$!L1{Ofk#F8{6jNdJH(oWlGEDpZ2tggjTbFN#w(QlWepknfF(*XrNO2<(45eb3Stx~8 zvxddiJ$Bz1PgscI;fYyHbavN)DQ6<@F=gG>bn1&q6^AJL83|J+7_r+#%a0bP^K6m z@1t{CS*d#~5dXt(h>Qtd_bdLcrCL1j#cM)(9TX^52bM5eV%GFO3WuKav>zcs&Rb!wESAc1Ojgzlg+Z!bbBPf?Gn zgtjER!h1qN+4Qc~ZOSl?E%r)s;mjh1W_CK6e@Bc?H*%C-GHZ>R$;2lB>JRjSTk$j7 z*z=L4F2|SN(j^um|B-RSJI%6JmpVuoCL@GA*RJJ9EWEWv zJ`oY(4##&{*!=f2n8iNzQAJeaDkRu_J@SGdML?W)j0t8Hlvtf?`~F}R7A{3)$EDD^ zMP3K#S?#7~iz#amy~$dYQ!Ti}(_N>Hhqt1c-NIe6DLI>^(1f*4cxtB6=}hbf6v6MH z_>>NS60AvVxLP$-l z7iC{-3>WNdGtt+1J|pIQ{VkKvlCDsjM~IA4P#iBK6E_LlY@Dh)&D74_{-Qq@XI2f_ zPLCq9ip5c`gh&r@v}ev3t2ggGNI?ZO(;I$Paw03spjOk)Xr7W*lXT*5`1tiZ!9@Ra zMr#oZ8<>Ty>TsOzbqUKdhV%)AMrPm_8>u}gik+;J^VUz`^>(1miNK3bM#d#A9T74@ z-kufa7njtbp*(ds_ZDNd!rB2bz{2ghWp$znRyp-tKBkE&R-U;m-d0LImWigtO@aB0 zq?^Tht*i5fDg)LLM^8R9`QaSc~QhQRvGNOH~I&l;}VAX6DaE}VwZ zv;LFzmj zM^MKZtX_Ccfvb1DutM>)<^{X9m*^?;%a`&t7?i2~n?Ih*AU#u{Y1J%iuR0&=SGpQt zy(ktwM}hZ{%Gw_jJi2ZK-9l#7&77dM{T zrF`3ECXEk8n^pCqdc`nTWJNd0wJm+B#XL4J_+@=Uu2Bbj8F0DKlm8(BYn#TPV<~@C zsPwR@w9eJdOEFyy`*jAxbE47n@apvWQl1g%)E#523J8SLrYiR{r4;1{DVuoOmg*wv zTn%>9F&(h+8PuB5IonP#@{3@Hwnnre2OWlT+@)lbWYL|WgZNLQ1^&Ji!~%=l5jZ~{ zhUHka5_YQOE6LgUS_?x5_n*12xtLtQh)OM21lDY-%h6=zqRVK1wBqKKm=yBjIP~7z zFF_sI@={jcRr=Tq(~QHiX*|V8Hqehg!jCgdBuMtE$9+1SB64iFmL8dq+cC=M|TR}LHvV}3WkABLa46N3@BQVG!&HqK(K8en8 z_RTPTGFgB994o{TfzlMIKS2LOGWM)UC;QQ@H*lSm#q1==I9dCi$aGwO3;s}Ms)S!c-^pul>j=P(# zZb0Ew2$q}M)*kP1!CJ%n&b(%g43VO+2_mg@F0wBD{^S_0vPsK7QPkG91Oc|sCU@Um zZB2Dy@W1b1-Rul7EI9Y_rZ3j?a5vyAKs%LF(zP|>$c&}E*)F0=hVdk^t?1imwGh5l z{mIGPRqoM@qsQB(X3R7iyqgLb>Lf{QlmKQrJbuW_O!lcBweI!1O?(Lt)9UIIFSpx4 zUwwIP9qCkOzDOr|LTKhj^jv6SMduz~Mx~p09mL9C?hlS%<_|9Vv6@KLH$$~!=w8Er zy>ZZf75fa2{IIM#wObS5aK$}& z{TBt+q?b@(Bi;D9v#pS3wFf%nFp2&qcZ<)po%9xM`Nj{wkA9Qw^W#$H(xgtbX>O7f z{g`Mx^Xt^3_*NLk*gJQCGZGbft+`zgVQ| zoBU(ZX_gJf&L6-IIOlzKUkFstMfH-}*yQTQrW^aX#iKxb@^Q;8x=3d2#5dr!FhoHY zPBVcvKFMgAaFC8Ui+GUEAhDP^KI(1FxvzrmdvR5H>WXbm%D&03ZI+_c74K{IC9=Vh zT7~$CTUQF@F;#X82}L5_`TTb&=bL7OaalC-|Kr9EpRm6nweOw+rPqcXlhaT2dq#cK z(jFqZ&bNCHKJa-hh#alS1aAmthl2#c-!wv-oyYxN$NdjPIOSfsgI#jB-dfKEaat+N zg<-eGW*`Q5HP|;8^Zm&CGL8J*dAbe9>~l`zcsY*8d~hDx@SQ!qDOM8#JCX)H4KtN0`_q;lbS=vv9;Ggi zKht&*)1G=)d#(L`Qa|y|Vvn-5aH;0W;K56(Y;QYs)5d`u_{Ggyb4@Yge)VXm&BD$R z!`YPb9u-ZqEo$d2DwEh>37Y#{J{>t1?6mNE=Wz4PI(zvjd4>9D(0Q^HzA7l9&_q|8 z&dv8|InD$5U;#s>M98ta9mN8<){#>RjU?7|H}3j6`jTGBN>LNmgAuBv;*rM!RnngO zZqv0~3`14!;aynfB84oVyc8=h$4^Bzsi8CJcxkesl(GOaco#%L0+K&&u`S9JSg7?q z)g_2mws*S$+1Urd~ts(1O}o}bJRRZjcxh{VbHu6r3~qHp#mTNkCF-pQNDEdX8l zo(`3>4D210z;nLwMy5d)iGj`R`=JZ6HD*g7@QmF~4>j_H7_F62JFEdGDFRvNY5nvw z0i1_+P-^zFtoiZ9s_$$KMN>CgQbSg+q3!WL&<$v4TVXSK#nxpMs+!q$JT=bIh+8$R zrieX>!}=t7eB-9GbnKmUBU6vfS%Cr64$>tt-e*K@*8eppV64RrO*p_G#AsPE%$VCa zySnxCV>`Nzi9yryY0N+#IckgW%XHSA(;pM}NU|$4`@@CFYI0Y{Ncb#cI=6-=zGICU z6a?kwmJ3!5dl7{;^>Ha~`Mk(X%GtKQfitHg^{svngQnQ5fQALw)cmCVM<+xfTBJis z%DnQcVmARPDedy7rBa-EF{h=l=7V|%hONo>_*(BdF=fM0ET&L|{e-sN#>g4op8>A# zHtw##%WQEeYy~SPJC3$ROjj`A$G1FJj7!o(Z_vV{Y6;U z;NpczSQ?Fv=`PDYy0D{Mn;bDLAIRR*7V?26Uw0-GEQ2UG2!}cgBJFjyMEQgfG|JjP__aJ43AYg8Ha*>xiqU zbuR}LS!+p^0J@(T)ra7T@+q5}F&?>^@327JB0-$z*J_qNo(6pRIGS~i6h}}IK9|YS zcM!K9An0Guk)1JTu@eP;!mD%9nUB2VDuXnIg5V}c?I9^5d^P4~ct`xAd=-(1OzPy|$~_Ftc>-^(8|3b|DS`hm~rPZE(B4xYLpLKPJ&#p}>=Am!?hZ%-K{ldC3v_mjz>k8gg=S%%iP>?}-7{G|&elNy!*%oaznh zv*p-rbdTQGslnyCUN~6OB&)^9*hIo`IGr`Om3;{ij8KoaSC9L>X6ifrc}9@42K2P~TFxgoISZ@;DTpMiMu)DvALGBSNRPi%wzs#Ly{O0RQ z24;(FHD4r75cN#FSG-QVO;0b=%d>>YQ&qn~3?XL<$xTxRpG&5r1nfghqYwS$hTLPZ zh80nRSoM5pc(GWbtKp1?m^2ibqPz{+yG2!_bg_OUJtZYY1d0;3X&%Xk-PrX38bi$! z`-Jx#9@q(&n|q|yZuj)_sznKu$88;(tGa7a=G!nBoA5?G`y#68BR0*N=cT`$6Y)Bq z`uSZGsgEbsapz9q6iPF_=Bj4y|7b*xD3!9EFnz)BK3X1?djY9%Z4CAlGhJXz+W z!$5!qIj#jcx#UNir;Nu8d{zS15{D88XJwZ%NS&otXTATsp!n!r7Y>DDZ3%4;9X_2F z?M3apXC)XgsUm^ z(nm(y7!q7fEbff*7cL?lk0mTObrUWEE(j%m{K_d z@veeG0v)%mG!w;C8dzFbhwBVe$1sc5A+ z_m-c-zCFFLns~m*+-1x;@joML3GS%ky>Ev0 z-ky+IXfKK_CeCj7i`HTkRmq=`+XsBdP?sCiilzeh0^@*COTrgJ!WUaYp{y=b?L*GU zhlmY>joUonB|+a0pvt9euK9FStTo|OxDm;QYY-4T$32?KXLd|zQ3TYsAXF#l!-?2{ z+qkUVZ) zc8#YsM@5K2RJARqj%GIjSrtvYZgX`w-p5zvl_{ED#~F+JP4vGP1)EPVbSOtb_fF0I zq*>(4ZtsfjQ>(jK)j2<>nBq15&lxvJr z86R&bteM@=YcR~xo?{y6fe98Ku`~mgyva_Kd*MZz--l|PY&Jzhw3q>R;q20 z2?9yf9lzxm^62t}OqeMasjZk8Lp)-2r6H51vZdh3V%G@tCKU^UInXz0zy!!y+9Eg+ zM8v2#N#m7%pqYR?VaVT9$o;bV2+ljSeWB>Fi+4<-J(}brciM#j#Y*{Sic8rBcarF_ zh{#4LdQxI%l>&PQgQXMcbD;!$dK#fd60OT}xrDYf6Ae*$?7y#NM&y>F@5^-=Z3Uc% z@}z37rrYyoyF=aEcH1d93?Iu4GfKpr52lm?od{-?D0>E<;(cvz^cFKFUz*G3Oq^P> zjOGrWC!bE*=Z)fH?#t##ay?guriUO_h$b#s z-tpO9z0gWZH9>IIYJP26&Cjsu>&}DysTn4A8CL~nq#m>@Xa-f3v%}1qv~v#*aRfKB&Y89 zxO}dq<>dok4v3`6)Hqg=RXma_ly{Jw_H{+~7+Q5ed`fPQxtr7V?&$N<+G<#aCvmH^oNcW^NE@r+9D&47xh(Iy5nOa$ z^gMQ4=vee)1!>F1mN z=rLF7i*y9Ne-5xfL}dzZd}uanMqH|B6w-{ZH}A|rMKr?_RJ~PPdlqT$JKo#G+Xieb z)Z9XPy0FJI!LDbaJ$6jX&9|#vqd`Fe;O8||5>rvVcqR56>K1cp#iiIxX@o>;z`7p9 z&Eh4mCP}brx?#A3t|4md`a?&FpNLSw7-U#(KpVj+Zzf)2Z#-PHYyQ7a1e5 zBTi(zxnBF`;}k!99WBl%>Ci(K)BR)RW8?(|FWYX71%ch*Xyie13@U25;WN9b(Z=xb zBIq645#;wAq*M|*#qUwCli}KEBibN&-x8t~H=CIymP^YbkIHGfZeAuQS;0|Ku)<+# z(t2$0)TAhs|M|#PmcKXs8Q+eOQ*%+&$%>nVbMVf2{UB^MsH05H|H7)%${i{MfCuAL zzz#nFtK59VF2e0ke5OZy26TR4kMysbg;07esk z-4}4zQs6}7v-Xy^nk90U&m=)IENVllEE7v#eWtPxZ&t7AQHHos=;$xe)Ezl5xt&qw zRvkf9>49bnuS5UqogBIppy|v$u0a{^+?Suu)b;1=71T$(wL&i5S0UFDUS3lN4MGKT zt4CvebcT4L}sY zhQU~6TK+JQ3P97L0gz>kG@bIJM|1@n_w*XU+)FVR2Rl%;CoOHxQG0pW8#8Wot z`%&YqGtQC&4&`j=KI$&TGrPxe&3QUOiFMcZr8Dd1KI2{?*A>$YbIz^x9`U=yAR8AW z3QN^XRfgsqJgfB=BbM0-wXFh<@R>T*kg{rqtpYpTk^>*r@T;3@=^@%Dwk^ZF%gJic ziwuj}#SmjJ$_DFD&pz%$?CU}Icn=9`Vkdiw1ureR$UMm=0`8Xii*2@f~%knC0F9L?%Nb}&Tw8J6&G2H^DHoa0Ve{1GTgJ zEZQv=6nwIsR#!Ry`eG(&mr~%hJ9LU$9%oOfewTg(Eu)AhGF5q`Ni!wde1`x{V##

Gpmbx64qX8xdBqjAMo>*(`@ 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 F{a=UxHXHx| literal 0 HcmV?d00001 diff --git a/static/in_class_recording_in_progress_warning.pdf b/static/in_class_recording_in_progress_warning.pdf new file mode 100644 index 0000000000000000000000000000000000000000..abb7d012ab94dcf6de5d697cc1a0f5728b8e6b34 GIT binary patch literal 14433 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 Date: Sun, 2 Feb 2020 22:27:49 +0100 Subject: [PATCH 8/8] Streamline text --- 01_elements_00_lecture.ipynb | 146 ++++++++++++++++----------------- 01_elements_02_exercises.ipynb | 8 +- 2 files changed, 77 insertions(+), 77 deletions(-) diff --git a/01_elements_00_lecture.ipynb b/01_elements_00_lecture.ipynb index c627331..b37b958 100644 --- a/01_elements_00_lecture.ipynb +++ b/01_elements_00_lecture.ipynb @@ -20,9 +20,9 @@ } }, "source": [ - "Do you remember how you first learned to speak in your mother tongue? Probably not. No one's memory goes back that far. Your earliest memory as a child should probably be around the age of three or four years old when you could already say simple things and interact with your environment. Although you did not know any grammar rules yet, other people just understood what you said. Well, most of the time.\n", + "Do you remember how you first learned to speak in your mother tongue? Probably not. No one's memory goes back that far. Your earliest memory as a child should probably be around the age of three or four years old when you could already say simple things and interact with your environment. Although you did not know any grammar rules yet, other people just understood what you said. At least most of the time.\n", "\n", - "It is intuitively best to take the very mindset of a small child when learning a foreign language. This first chapter introduces simplistic examples, and we accept them as they are *without* knowing any of the \"grammar\" rules yet. Then, we analyze them in parts and slowly build up our understanding.\n", + "It is intuitively best to take the very mindset of a small child when learning a new language. And a programming language is no different from that. This first chapter introduces simplistic examples and we accept them as they are *without* knowing any of the \"grammar\" rules yet. Then, we analyze them in parts and slowly build up our understanding.\n", "\n", "Consequently, if parts of this chapter do not make sense right away, let's not worry too much. Besides introducing the basic elements, it also serves as an outlook for what is to come. So, many terms and concepts used here are deconstructed in great detail in the following chapters." ] @@ -46,7 +46,7 @@ } }, "source": [ - "As our introductory example, we want to calculate the *average* of all *evens* in a **list** of numbers: `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]`.\n", + "As our introductory example, we want to calculate the *average* of all *evens* in a **list** of whole numbers: `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]`.\n", "\n", "While we are used to finding an [analytical solution](https://math.stackexchange.com/questions/935405/what-s-the-difference-between-analytical-and-numerical-approaches-to-problems/935446#935446) in math (i.e., derive some equation with \"pen and paper\"), we solve this task *programmatically* instead.\n", "\n", @@ -110,17 +110,17 @@ } }, "source": [ - "So far, so good. Let's see how the desired **computation** could be expressed as a **sequence of instructions** in Python.\n", + "So far, so good. Let's see how the desired **computation** could be expressed as a **sequence of instructions** in the next code cell.\n", "\n", "Intuitively, the line `for number in numbers` describes a \"loop\" over all the numbers in the `numbers` list, one at a time.\n", "\n", "The `if number % 2 == 0` may look confusing at first sight. Both `%` and `==` must have an unintuitive meaning here. Luckily, the **comment** in the same line after the `#` symbol has the answer: The program does something only for an even `number`.\n", "\n", - "In particular, it increases `count` by `1` and adds the current `number` onto the [running](https://en.wikipedia.org/wiki/Running_total) `total`. Both `count` and `number` are initially set to `0` and the single `=` symbol reads as \"... is *set* equal to ...\". It could not indicate a mathematical equation as, for example, `count` is generally not equal to `count + 1`.\n", + "In particular, it increases `count` by `1` and adds the current `number` onto the [running](https://en.wikipedia.org/wiki/Running_total) `total`. Both `count` and `number` are **initialized** to `0` and the single `=` symbol reads as \"... is *set* equal to ...\". It cannot indicate a mathematical equation as, for example, `count` is generally *not* equal to `count + 1`.\n", "\n", "Lastly, the `average` is calculated as the ratio of the final **values** of `total` and `count`. Overall, we divide the sum of all even numbers by their count: This is nothing but the definition of an average.\n", "\n", - "The lines of code \"within\" the `for` and `if` **statements** are **indented** and **aligned** with multiples of **four spaces**: This shows immediately how the lines relate to each other." + "The lines of code \"within\" the `for` and `if` **statements** are **indented** and aligned with multiples of *four spaces*: This shows immediately how the lines relate to each other." ] }, { @@ -187,7 +187,7 @@ } }, "source": [ - "## Generating Cell Output in a Jupyter Notebook" + "## Output in a Jupyter Notebook" ] }, { @@ -198,9 +198,9 @@ } }, "source": [ - "Note how only two of the previous four code cells generate an **output** while two remained \"silent\" (i.e., there is no \"**Out[...]**\" after running the cell).\n", + "Only two of the previous four code cells generate an **output** while two remained \"silent\" (i.e., nothing appears below the cell after running it).\n", "\n", - "By default, Jupyter notebooks show the value of the **expression** in the last line of a code cell only. This output can be suppressed by ending the last line with a semicolon `;`." + "By default, Jupyter notebooks only show the value of the **expression** in the last line of a code cell. And, this output may also be suppressed by ending the last line with a semicolon `;`." ] }, { @@ -249,7 +249,7 @@ } }, "source": [ - "To visualize something before the end of the cell, we use the built-in [print()](https://docs.python.org/3/library/functions.html#print) **function**. Here, the parentheses `()` indicate that we execute code written somewhere else." + "To see any output other than that, we use the built-in [print()](https://docs.python.org/3/library/functions.html#print) **function**. Here, the parentheses `()` indicate that we **call** (i.e., \"execute\") code written somewhere else." ] }, { @@ -329,9 +329,9 @@ "source": [ "Python comes with many built-in **[operators](https://docs.python.org/3/reference/lexical_analysis.html#operators)**: They are **tokens** (i.e., \"symbols\") that have a special meaning to the Python interpreter.\n", "\n", - "The arithmetic operators either \"operate\" with the number immediately following them (= **unary** operators; e.g., negation) or \"process\" the two numbers \"around\" them (= **binary** operators; e.g., addition).\n", + "The arithmetic operators either \"operate\" with the number immediately following them, so-called **unary** operators (e.g., negation), or \"process\" the two numbers \"around\" them, so-called **binary** operators (e.g., addition).\n", "\n", - "By definition, operators have **no** permanent **side effects** in the computer's memory. Although the code cells in this section do indeed create *new* numbers in memory (e.g., `77 + 13` creates `90`), they are immediately \"forgotten\" as they are not stored in a **variable** like `numbers` or `average` above. We develop this thought further at the end of this chapter when we compare **expressions** with **statements**.\n", + "By definition, operators on their own have *no* permanent **side effects** in the computer's memory. Although the code cells in this section do indeed create *new* numbers in memory (e.g., `77 + 13` creates `90`), they are immediately \"forgotten\" as they are not stored in a **variable** like `numbers` or `average` above. We develop this thought further at the end of this chapter when we compare **expressions** with **statements**.\n", "\n", "Let's see some examples of operators. We start with the binary `+` and the `-` operators for addition and subtraction. Binary operators mimic what mathematicians call [infix notation](https://en.wikipedia.org/wiki/Infix_notation) and have the expected meaning." ] @@ -392,7 +392,7 @@ } }, "source": [ - "The `-` operator may be used as a unary operator as well. Then it just flips the sign of a number." + "The `-` operator may be used as a unary operator as well. Then, it unsurprisingly flips the sign of a number." ] }, { @@ -545,7 +545,7 @@ } }, "source": [ - "Even though it appears that the `//` operator **truncates** (i.e., \"cuts off\") the decimals so as to effectively \"rounding\" down (i.e., the `42.5` became `42` in the previous code cell), this is *not* the case: The result is always \"rounded\" towards minus infinity!" + "Even though it appears that the `//` operator **truncates** (i.e., \"cuts off\") the decimals so as to effectively \"round down\" (i.e., the `42.5` became `42` in the previous code cell), this is *not* the case: The result is always \"rounded\" towards minus infinity!" ] }, { @@ -617,7 +617,7 @@ "source": [ "The remainder is `0` *only if* a number is *divisible* by another.\n", "\n", - "A popular convention in both, computer science and mathematics, is to abbreviate \"only if\" as **iff**, which is short for \"**[if and only if](https://en.wikipedia.org/wiki/If_and_only_if)**.\" The iff means that a remainder of `0` implies that a number is divisible by another but also that a number divisible by another implies a remainder of `0`. The implication goes in *both* directions!\n", + "A popular convention in both computer science and mathematics is to abbreviate \"only if\" as \"iff\", which is short for \"**[if and only if](https://en.wikipedia.org/wiki/If_and_only_if)**.\" The iff means that a remainder of `0` implies that a number is divisible by another but also that a number's being divisible by another implies a remainder of `0`. The implication goes in *both* directions!\n", "\n", "So, `49` is divisible by `7`." ] @@ -713,7 +713,7 @@ } }, "source": [ - "The built-in [divmod()](https://docs.python.org/3/library/functions.html#divmod) function combines the integer and modulo divisions into one operation. However, this is not an operator but a function. Also, [divmod()](https://docs.python.org/3/library/functions.html#divmod) returns a \"pair\" of integers and not just one." + "The built-in [divmod()](https://docs.python.org/3/library/functions.html#divmod) function combines the integer and modulo divisions into one operation. However, grammatically this is *not* an operator but a function. Also, [divmod()](https://docs.python.org/3/library/functions.html#divmod) returns a \"pair\" of integers and not just one." ] }, { @@ -877,7 +877,7 @@ } }, "source": [ - "Some programmers also use \"style\" conventions. For example, we might play with the **whitespace**, which is an umbrella term that refers to any non-printable sign like spaces, tabs, or the like. However, parentheses convey a much clearer picture." + "Some programmers also use \"style\" conventions. For example, we might play with the **whitespace**, which is an umbrella term that refers to any non-printable sign like spaces, tabs, or the like. However, this is *not* a good practice and parentheses convey a much clearer picture." ] }, { @@ -912,7 +912,7 @@ } }, "source": [ - "There exist many non-mathematical operators that are introduced throughout this book, together with the concepts they implement. They often come in a form different from the unary and binary mentioned above." + "There exist many non-mathematical operators that are introduced throughout this book, together with the concepts they implement. They often come in a form different from the unary and binary ones mentioned above." ] }, { @@ -936,7 +936,7 @@ "source": [ "Python is a so-called **object-oriented** language, which is a paradigm of organizing a program's memory.\n", "\n", - "An **object** may be viewed as a \"bag\" of $0$s and $1$s in a given memory location. The $0$s and $1$s in a bag make up the object's **value**. There exist different **types** of bags: Each type comes with distinct rules how the $0$s and $1$s are interpreted and may be worked with.\n", + "An **object** may be viewed as a \"bag\" of $0$s and $1$s in a given memory location. The $0$s and $1$s in a bag make up the object's **value**. There exist different **types** of bags, and each type comes with its own rules how the $0$s and $1$s are interpreted and may be worked with.\n", "\n", "So, an object *always* has *three* main characteristics. Let's look at the following examples and work them out." ] @@ -975,7 +975,7 @@ } }, "source": [ - "The [id()](https://docs.python.org/3/library/functions.html#id) built-in function shows an object's \"address\" in memory." + "The built-in [id()](https://docs.python.org/3/library/functions.html#id) function shows an object's \"address\" in memory." ] }, { @@ -990,7 +990,7 @@ { "data": { "text/plain": [ - "140173037405648" + "139627575613392" ] }, "execution_count": 28, @@ -1014,7 +1014,7 @@ { "data": { "text/plain": [ - "140173037405584" + "139627575613200" ] }, "execution_count": 29, @@ -1038,7 +1038,7 @@ { "data": { "text/plain": [ - "140173037234160" + "139627575358192" ] }, "execution_count": 30, @@ -1058,7 +1058,7 @@ } }, "source": [ - "These addresses are *not* meaningful for anything other than checking if two variables reference the *same* object. Let's create a second variable `d` and also set it to `789`." + "These addresses are *not* meaningful for anything other than checking if two variables reference the *same* object. Let's create a new variable `d` and also set it to `789`." ] }, { @@ -1082,7 +1082,7 @@ } }, "source": [ - "`a` and `d` indeed have the same value as is checked with the **equality operator** `==`. The resulting `True` (and the `False` further below) is yet another data type, a so-called **boolean**. We look into them closely in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#Boolean-Expressions)." + "`a` and `d` indeed have the *same value* as is checked with the **equality operator** `==`: We say `a` and `d` \"evaluate equal.\" The resulting `True` - and the `False` further below - is yet another data type, a so-called **boolean**. We look into them in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_00_lecture.ipynb#Boolean-Expressions)." ] }, { @@ -1117,7 +1117,7 @@ } }, "source": [ - "On the contrary, `a` and `d` are different objects as the **identity operator** `is` shows: they are stored at separate addresses in the memory." + "On the contrary, `a` and `d` are *different objects* as the **identity operator** `is` shows: They are stored at *different* addresses in the memory." ] }, { @@ -1152,7 +1152,7 @@ } }, "source": [ - "If we want to check the opposite case, we use the negated version of the `is` operator." + "If we want to check the opposite case, we use the negated version of the `is` operator, namely `is not`." ] }, { @@ -1198,7 +1198,7 @@ } }, "source": [ - "The [type()](https://docs.python.org/3/library/functions.html#type) built-in function shows an object's type. For example, `a` is an integer (i.e., `int`) while `b` is a so-called [floating-point number](https://en.wikipedia.org/wiki/Floating-point_arithmetic) (i.e., `float`)." + "The [type()](https://docs.python.org/3/library/functions.html#type) built-in shows an object's type. For example, `a` is an integer (i.e., `int`) while `b` is a so-called [floating-point number](https://en.wikipedia.org/wiki/Floating-point_arithmetic) (i.e., `float`)." ] }, { @@ -1257,9 +1257,9 @@ } }, "source": [ - "Different types imply different behaviors for the objects. The `b` object, for example, can be \"asked\" if it could also be interpreted as an `int` with the [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) \"functionality\" that comes with every `float` object.\n", + "Different types imply different behaviors for the objects. The `b` object, for example, may be \"asked\" if it is a whole number with the [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) \"functionality\" that comes with every `float` object.\n", "\n", - "Formally, we call such type-specific functionalities **methods** (to differentiate them from functions) and we formally introduce them in Chapter 10. For now, it suffices to know that we access them using the **dot operator** `.`. Of course, `b` could be converted into an `int`, which the boolean value `True` tells us." + "Formally, we call such type-specific functionalities **methods** (i.e., as opposed to functions) and we formally introduce them in Chapter 10. For now, it suffices to know that we access them with the **dot operator** `.` on the object. Of course, `b` is a whole number, which the boolean object `True` tells us." ] }, { @@ -1330,7 +1330,7 @@ } }, "source": [ - "The `c` object is a so-called **string** type (i.e., `str`), which is Python's way of representing \"text.\" Strings also come with peculiar behaviors, for example, to convert a text to lower or upper case." + "The `c` object is a so-called **string** type (i.e., `str`), which is Python's way of representing \"text.\" Strings also come with peculiar behaviors, for example, to convert a text to lower, upper, or title case." ] }, { @@ -1448,9 +1448,9 @@ } }, "source": [ - "Almost trivially, every object also has a value to which it \"evaluates\" when referenced. We think of the value as the **conceptual idea** of what the $0$s and $1$s in the bag mean to *humans* as machines cannot see beyond $0$s and $1$s.\n", + "Almost trivially, every object also has a value to which it **evaluates** when referenced. We think of the value as the **conceptual idea** of what the $0$s and $1$s in the bag mean to *humans*.\n", "\n", - "For built-in data types, Python prints out the object's value as a so-called **[literal](https://docs.python.org/3/reference/lexical_analysis.html#literals)**: This means that we can copy and paste the output back into a code cell to create a *new* object with the *same* value." + "For built-in data types, Python prints out an object's value as a so-called **[literal](https://docs.python.org/3/reference/lexical_analysis.html#literals)**: This means that we may copy and paste the value back into a code cell and create a *new* object with the *same* value." ] }, { @@ -1509,7 +1509,7 @@ } }, "source": [ - "In this book, we follow the convention of creating strings with **double quotes** `\"` instead of the **single quotes** `'` to which Python defaults in its *literal* notation for `str` objects. Both types of quotes may be used interchangeably." + "In this book, we follow the convention of creating strings with **double quotes** `\"` instead of the **single quotes** `'` to which Python defaults in its *literal* notation for `str` objects. Both types of quotes may be used interchangeably. So, the `\"Python rocks\"` from above and `'Python rocks'` create two objects that evaluate equal (i.e., `\"Python rocks\" == 'Python rocks'`)." ] }, { @@ -1533,7 +1533,7 @@ } ], "source": [ - "c # we defined c = \"Python rocks\" with double quotes \" above" + "c" ] }, { @@ -1581,7 +1581,7 @@ "source": [ "If we do not follow the rules, the code cannot be **parsed** correctly, i.e., the program does not even start to run but **raises** a **syntax error** indicated as `SyntaxError` in the output. Computers are very dumb in the sense that the slightest syntax error leads to the machine not understanding our code.\n", "\n", - "For example, if we wanted to write an accounting program that adds up currencies, we would have to model dollar prices as `float` objects as the dollar symbol cannot be understood by Python." + "If we were to write an accounting program that adds up currencies, we would, for example, have to model dollar prices as `float` objects as the dollar symbol cannot be understood by Python." ] }, { @@ -1693,9 +1693,9 @@ } }, "source": [ - "Syntax errors are easy to find as the code does not even run in the first place.\n", + "Syntax errors are easy to find as the code does *not* even run in the first place.\n", "\n", - "However, there are also so-called **runtime errors**, often called **exceptions**, that occur whenever otherwise (i.e., syntactically) correct code does not run because of invalid input.\n", + "However, there are also so-called **runtime errors** that occur whenever otherwise (i.e., syntactically) correct code does not run because of invalid input. Runtime errors are also often referred to as **exceptions**.\n", "\n", "This example does not work because just like in the \"real\" world, Python does not know how to divide by `0`. The syntactically correct code leads to a `ZeroDivisionError`." ] @@ -1825,7 +1825,7 @@ } }, "source": [ - "Thus, adhering to just syntax rules is *never* enough. Over time, **best practices** and **style guides** were created to make it less likely for a developer to mess up a program and also to allow \"onboarding\" him as a contributor to an established code base, often called **legacy code**, faster. These rules are not enforced by Python itself: Badly styled code still runs. At the very least, Python programs should be styled according to [PEP 8](https://www.python.org/dev/peps/pep-0008/) and documented \"inline\" (i.e., in the code itself) according to [PEP 257](https://www.python.org/dev/peps/pep-0257/).\n", + "Thus, adhering to just syntax rules is *never* enough. Over time, **best practices** and **style guides** were created to make it less likely for a developer to mess up a program and also to allow \"onboarding\" him as a contributor to an established code base, often called **legacy code**, faster. These rules are *not* enforced by Python itself: Badly styled code still runs. At the very least, Python programs should be styled according to [PEP 8](https://www.python.org/dev/peps/pep-0008/) and documented \"inline\" (i.e., in the code itself) according to [PEP 257](https://www.python.org/dev/peps/pep-0257/).\n", "\n", "An easier to read version of PEP 8 is [here](https://pep8.org/). The video below features a well known **[Pythonista](https://en.wiktionary.org/wiki/Pythonista)** talking about the importance of code style." ] @@ -1854,7 +1854,7 @@ " " ], "text/plain": [ - "" + "" ] }, "execution_count": 52, @@ -1875,7 +1875,7 @@ } }, "source": [ - "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) (= \"length\") [built-in functions](https://docs.python.org/3/library/functions.html) (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone." + "For example, while the above code to calculate the average of the even numbers in `[7, 11, 8, 5, 3, 12, 2, 6, 9, 10, 1, 4]` is correct, a Pythonista would rewrite it in a more \"Pythonic\" way and use the built-in [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Built-in-Functions)) as well as a so-called **list comprehension** (cf., [Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#List-Comprehensions)). Pythonic code runs faster in many cases and is less error-prone." ] }, { @@ -1973,7 +1973,7 @@ } }, "source": [ - "To get a rough overview of the mindsets of a typical Python programmer, see these rules by an early Python core developer deemed so important that they are included in every Python installation." + "To get a rough overview of the mindset of a typical Python programmer, look at these rules, also known as the **Zen of Python**, that are deemed so important that they are included in every Python installation." ] }, { @@ -2025,7 +2025,7 @@ } }, "source": [ - "### Jupyter Notebook Aspects to keep in Mind" + "### Jupyter Notebook Aspects" ] }, { @@ -2047,11 +2047,11 @@ } }, "source": [ - "Observe that you can run the code cells in a Jupyter notebook in any arbitrary order.\n", + "We can run the code cells in a Jupyter notebook in *any* arbitrary order.\n", "\n", "That means, for example, that a variable defined towards the bottom could accidentally be referenced at the top of the notebook. This happens quickly when we iteratively built a program and go back and forth between cells.\n", "\n", - "As a good practice, it is recommended to click on \"Kernel\" > \"Restart & Run All\" in the navigation bar once a notebook is finished. That restarts the Python process forgetting any **state** (i.e., all variables) and ensures that the notebook runs top to bottom without any errors the next time it is opened." + "As a good practice, it is recommended to click on \"Kernel\" > \"Restart Kernel and Run All Cells\" in the navigation bar once a notebook is finished. That restarts the Python process forgetting all **state** (i.e., all variables) and ensures that the notebook runs top to bottom without any errors the next time it is opened." ] }, { @@ -2073,11 +2073,11 @@ } }, "source": [ - "While this book is built with Jupyter notebooks, it is crucial to understand that \"real\" programs are almost always just \"linear\" (= top to bottom) sequences of instructions but instead may take many different **flows of execution**.\n", + "While this book is built with Jupyter notebooks, it is crucial to understand that \"real\" programs are almost never \"linear\" (i.e., top to bottom) sequences of instructions but instead may take many different **flows of execution**.\n", "\n", "At the same time, for a beginner's course, it is often easier to code linearly.\n", "\n", - "In real data science projects, one would probably employ a mixed approach and put reusable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Local-Modules-and-Packages)) and then use Jupyter notebooks to build up a linear report or storyline for a business argument to be made." + "In real data science projects, one would probably employ a mixed approach and put reusable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_00_lecture.ipynb#Local-Modules-and-Packages)) and then use Jupyter notebooks to build up a linear report or storyline for an analysis." ] }, { @@ -2088,7 +2088,7 @@ } }, "source": [ - "## Variables vs. Names vs. Identifiers" + "## Variables vs. Names vs. Identifiers vs. References" ] }, { @@ -2099,7 +2099,7 @@ } }, "source": [ - "**Variables** are created with the **[assignment statement](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements)** `=`, which is *not* an operator, mainly because of its side effect of making a **[name](https://docs.python.org/3/reference/lexical_analysis.html#identifiers)** reference an object in memory.\n", + "**Variables** are created with the **[assignment statement](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements)** `=`, which is *not* an operator because of its *side effect* of making a **[name](https://docs.python.org/3/reference/lexical_analysis.html#identifiers)** reference an object in memory.\n", "\n", "We read the terms **variable**, **name**, and **identifier** used interchangebly in many Python-related texts. In this book, we adopt the following convention: First, we treat *name* and *identifier* as perfect synonyms but only use the term *name* in the text for clarity. Second, whereas *name* only refers to a string of letters, numbers, and some other symbols, a *variable* means the combination of a *name* and a *reference* to an object in memory." ] @@ -2161,7 +2161,7 @@ } }, "source": [ - "A variable may be **re-assigned** as often as we wish. Thereby, we could also assign an object of a *different* type. Because this is allowed, Python is said to be a **dynamically typed** language. On the contrary, a **statically typed** language like C also allows re-assignment but only with objects of the *same* type. This subtle distinction is one reason why Python is slower at execution than C: As it runs a program, it needs to figure out an object's type each time it is referenced. But as mentioned before, this is mitigated with third-party libraries." + "A variable may be **re-assigned** as often as we wish. Thereby, we could also assign an object of a *different* type. Because this is allowed, Python is said to be a **dynamically typed** language. On the contrary, a **statically typed** language like C also allows re-assignment but only with objects of the *same* type. This subtle distinction is one reason why Python is slower at execution than C: As it runs a program, it needs to figure out an object's type each time it is referenced." ] }, { @@ -2209,7 +2209,7 @@ } }, "source": [ - "If we want to re-assign a variable while referencing its \"old\" (i.e., current) object, we may also **update** it using a so-called **[augmented assignment statement](https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements)** (*not* operator), introduced with [PEP 203](https://www.python.org/dev/peps/pep-0203/): The currently mapped object is implicitly inserted as the first operand on the right-hand side." + "If we want to re-assign a variable while referencing its \"old\" (i.e., current) object, we may also **update** it using a so-called **[augmented assignment statement](https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements)** (i.e., *not* operator), as introduced with [PEP 203](https://www.python.org/dev/peps/pep-0203/): The currently mapped object is implicitly inserted as the first operand on the right-hand side." ] }, { @@ -2235,7 +2235,7 @@ }, "outputs": [], "source": [ - "a //= 2 # same as a = a // 2, \"//\" to retain the integer type" + "a //= 2 # same as a = a // 2; \"//\" to retain the integer type" ] }, { @@ -2283,7 +2283,7 @@ } }, "source": [ - "Variables are **[dereferenced](https://docs.python.org/3/reference/simple_stmts.html#the-del-statement)** (i.e., \"deleted\") with the `del` statement. It does *not* delete the object a variable references but merely removes the variable's name from the \"global list of all names.\"" + "Variables are **[dereferenced](https://docs.python.org/3/reference/simple_stmts.html#the-del-statement)** (i.e., \"deleted\") with the `del` statement. This does *not* delete the object a variable references but merely removes the variable's name from the \"global list of all names.\"" ] }, { @@ -2331,7 +2331,7 @@ } }, "source": [ - "If we refer to an unknown name, a *runtime* error occurs, namely a `NameError`. The `Name` in `NameError` gives a hint as to why we prefer the term *name* over *identifier*: Python uses it more often in its error messages." + "If we refer to an unknown name, a *runtime* error occurs, namely a `NameError`. The `Name` in `NameError` gives a hint why we choose the term *name* over *identifier* above: Python uses it more often in its error messages." ] }, { @@ -2367,7 +2367,7 @@ } }, "source": [ - "Some variables magically exist when we start a Python process or are added by Jupyter. We may safely ignore the former until Chapter 10 and the latter for good." + "Some variables magically exist when a Python process is started or are added by Jupyter. We may safely ignore the former until Chapter 10 and the latter for good." ] }, { @@ -2598,7 +2598,7 @@ "source": [ "It is *crucial* to understand that *several* variables may reference the *same* object in memory. Not having this in mind may lead to many hard to track down bugs.\n", "\n", - "Make `b` reference whatever object `a` is referencing." + "Let's make `b` reference whatever object `a` is referencing." ] }, { @@ -2755,7 +2755,7 @@ } }, "source": [ - "However, if a variable references an object of a more \"complex\" type (e.g., `list`), \"weird\" things happen." + "However, if a variable references an object of a more \"complex\" type (e.g., `list`), predicting the outcome of a code snippet may be unintuitive for a beginner." ] }, { @@ -2818,9 +2818,9 @@ "source": [ "Let's change the first element of `x`.\n", "\n", - "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as just another operator, called the **indexing operator**. `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object. The indexing operator must be an operator as we merely read the first element and do not change anything in memory.\n", + "[Chapter 7](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/07_sequences_00_lecture.ipynb#The-list-Type) discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of references to other objects and treat the brackets `[]` attached to it as yet another operator, namely the **indexing operator**. So, `x[0]` instructs Python to first follow the reference from the global list of all names to the `x` object. Then, it follows the first reference it finds there to the `1` object we put in the list. The indexing operator must be an operator as we merely *read* the first element and do not change anything in memory permanently.\n", "\n", - "Note how Python **begins counting at 0**. This is not the case for many other languages, for example, [MATLAB](https://en.wikipedia.org/wiki/MATLAB), [R](https://en.wikipedia.org/wiki/R_%28programming_language%29), or [Stata](https://en.wikipedia.org/wiki/Stata). To understand why this makes sense, see this short [note](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) by one of the all-time greats in computer science, the late [Edsger Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)." + "Python **begins counting at 0**. This is not the case for many other languages, for example, [MATLAB](https://en.wikipedia.org/wiki/MATLAB), [R](https://en.wikipedia.org/wiki/R_%28programming_language%29), or [Stata](https://en.wikipedia.org/wiki/Stata). To understand why this makes sense, see this short [note](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) by one of the all-time greats in computer science, the late [Edsger Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)." ] }, { @@ -2855,7 +2855,7 @@ } }, "source": [ - "To change the first entry in the list, we use the assignment statement `=` again. Here, this does *not* create a *new* variable, or overwrite an existing one, but only changes the object which the first element in `x` referenced. As we only change parts of the `x` object, we say that we **mutate** (i.e., \"change\") its **state**. To use the bag analogy from above, we keep the same bag but \"flip\" some of the $0$s into $1$s and some of the $1$s into $0$s." + "To change the first entry in the list, we use the assignment statement `=` again. Here, this does *not* create a *new* variable, nor overwrite an existing one, but only changes the object referenced as the first element in `x`. As we only change parts of the `x` object, we say that we **mutate** its **state**. To use the bag analogy from above, we keep the same bag but \"flip\" some of the $0$s into $1$s and some of the $1$s into $0$s." ] }, { @@ -2938,15 +2938,15 @@ } }, "source": [ - "The illustrated difference in behavior has to do with the fact that integers and floats are **immutable** types while lists are **mutable**.\n", + "The difference in behavior illustrated in this sub-section has to do with the fact that `int` and `float` objects are **immutable** types while `list` objects are **mutable**.\n", "\n", - "In the first case, an object cannot be changed \"in place\" once it is created in memory. When we assigned `123` to the already existing `a`, we did not change the $0$s and $1$s in the object `a` referenced before the assignment but created a new integer object and made `a` reference it while the `b` variable is *not* affected.\n", + "In the first case, an object cannot be changed \"in place\" once it is created in memory. When we assigned `123` to the already existing `a`, we did *not* change the $0$s and $1$s in the object `a` referenced before the assignment but created a new `int` object and made `a` reference it while the `b` variable is *not* affected.\n", "\n", - "In the second case, `x[0] = 99` creates a *new* integer object `99` and merely changes the first reference in the `x` list.\n", + "In the second case, `x[0] = 99` creates a *new* `int` object `99` and merely changes the first reference in the `x` list.\n", "\n", - "In general, the assignment statement creates a new name and makes it reference whatever object is on the right-hand side *iff* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it *mutates* an already existing object. And, we always must expect that the latter might have more than one variable referencing it.\n", + "In general, the assignment statement creates a new name and makes it reference whatever object is on the right-hand side *iff* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it *mutates* an already existing object. And, we must always expect that the latter may have more than one variable referencing it.\n", "\n", - "Visualizing what is going on in the memory with a tool like [PythonTutor](http://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20x%0Ax%5B0%5D%20%3D%2099%0Aprint%28y%5B0%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) might be helpful for a beginner." + "Visualizing what is going on in memory with a tool like [PythonTutor](http://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20x%0Ax%5B0%5D%20%3D%2099%0Aprint%28y%5B0%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) may be helpful for a beginner." ] }, { @@ -3155,7 +3155,7 @@ } }, "source": [ - "Variables with leading and trailing double underscores, referred to as **dunder** in Python jargon, are used for built-in functionalities. Do *not* use this style for custom variables unless you exactly know what you are doing!" + "Variables with leading and trailing double underscores, referred to as **dunder** in Python jargon, are used for built-in functionalities and to implement object-oriented features as we see in Chapter 10. We must *not* use this style for variables!" ] }, { @@ -3205,7 +3205,7 @@ "\n", "In simple words, anything that may be used on the right-hand side of an assignment statement without creating a `SyntaxError` is an expression.\n", "\n", - "What we said about individual operators above, namely that they have *no* side effects, should have been put here, to begin with. The code cells in the section on operators above are all expressions!\n", + "What we say about *individual* operators above, namely that they have *no* permanent side effects in memory, should be put here, to begin with: The absence of any permanent side effects is the characteristic property of expressions, and all the code cells in the \"*(Arithmetic) Operators*\" section above contain only expressions!\n", "\n", "The simplest possible expressions contain only one variable or literal." ] @@ -3293,7 +3293,7 @@ } }, "source": [ - "The definition of an expression is **recursive**. So, the sub-expression `a + b` is combined with the literal `3` by the operator `**` to form the full expression." + "The definition of an expression is **recursive**. So, the sub-expression `a + b` is combined with the literal `3` by the operator `**` to form the full expression `(a + b) ** 3`." ] }, { @@ -3363,7 +3363,7 @@ } }, "source": [ - "When not used as a delimiter, parentheses also constitute an operator, namely the **call operator** `()`. We saw this syntax above when we \"called\" (i.e., executed) built-in functions and methods." + "When not used as a delimiter, parentheses also constitute an operator, namely the **call operator** `()`. We saw this syntax above when we called built-in functions and methods." ] }, { @@ -3504,7 +3504,7 @@ } }, "source": [ - "A **[statement](https://docs.python.org/3/reference/simple_stmts.html)** is anything that *changes* the *state of a program* or has another *side effect*. Statements, unlike expressions, do not just evaluate to a value; instead, they create or change values.\n", + "A **[statement](https://docs.python.org/3/reference/simple_stmts.html)** is anything that *changes* the *state of a program* or has another permanent *side effect*. Statements, unlike expressions, do not evaluate to a value; instead, they create or change values.\n", "\n", "Most notably, of course, are the `=` and `del` statements." ] @@ -3543,7 +3543,7 @@ } }, "source": [ - "The built-in [print()](https://docs.python.org/3/library/functions.html#print) function is regarded as a \"statement\" as well. It used to be an actual statement in Python 2 and has all the necessary properties. It is a bit of a corner case as expressions are also \"printed\" in a Jupyter notebook when evaluated last in a code cell." + "The built-in [print()](https://docs.python.org/3/library/functions.html#print) function is sometimes regarded as a \"statement\" as well. It used to be an actual statement in Python 2 and has all the necessary properties. It is a bit of a corner case but we can think of it as changing the state of the screen." ] }, { @@ -3588,7 +3588,7 @@ "source": [ "We use the `#` symbol to write comments in plain English right into the code.\n", "\n", - "As a good practice, comments should *not* describe *what* happens (this should be evident by reading the code; otherwise, it is most likely badly written code) but *why* something happens.\n", + "As a good practice, comments should *not* describe *what* happens. This should be evident by reading the code. Otherwise, it is most likely badly written code. Rather, comments should describe *why* something happens.\n", "\n", "Comments may be added either at the end of a line of code, by convention separated with two spaces, or on a line on their own." ] @@ -3786,7 +3786,7 @@ " " ], "text/plain": [ - "" + "" ] }, "execution_count": 110, diff --git a/01_elements_02_exercises.ipynb b/01_elements_02_exercises.ipynb index c7fffb6..56bf985 100644 --- a/01_elements_02_exercises.ipynb +++ b/01_elements_02_exercises.ipynb @@ -33,9 +33,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1.1**: Read about the [print()](https://docs.python.org/3/library/functions.html#print) built-in. How can you use it to print both `greeting` and `audience` *without* concatenating the two strings with the `+` operator?\n", + "**Q1**: Read the documentation on the built-in [print()](https://docs.python.org/3/library/functions.html#print) function! How can you use it to print both `greeting` and `audience` *without* concatenating the two strings with the `+` operator?\n", "\n", - "Hint: The `*objects` in the documentation implies that we can insert several comma-seperated variables." + "Hint: The `*objects` in the documentation implies that we can insert several *comma-seperated* variables." ] }, { @@ -61,7 +61,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1.2**: What does the `sep=\" \"` mean in the documentation? Use it to print out the three names in `first`, `second`, and `third` on one line seperated by commas with one [print()](https://docs.python.org/3/library/functions.html#print) statement." + "**Q2**: What does the `sep=\" \"` mean in the documentation? Use it and print out the three names in `first`, `second`, and `third` on one line seperated by *commas* with only *one* call of the [print()](https://docs.python.org/3/library/functions.html#print) function!" ] }, { @@ -88,7 +88,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "**Q1.3**: Lastly, what does the `end=\"\\n\"` mean in the documentation? Use it in the `for`-loop to print the numbers 1 through 10 in just one line." + "**Q3**: Lastly, what does the `end=\"\\n\"` mean in the documentation? Use it in the `for`-loop and print the numbers 1 through 10 in just *one* line!" ] }, {