Release 0.4.0

This commit is contained in:
Alexander Hess 2019-10-15 20:15:33 +02:00
commit 21e3345441
19 changed files with 12001 additions and 828 deletions

View file

@ -19,11 +19,9 @@
}
},
"source": [
"This book is set up to be a *thorough* introduction to programming in [Python](https://www.python.org/).\n",
"This book is a *thorough* introduction to programming in [Python](https://www.python.org/).\n",
"\n",
"It teaches the concepts behind and the syntax of the core Python language as defined by the [Python Software Foundation](https://www.python.org/psf/) in the official [language reference](https://docs.python.org/3/reference/index.html) and introduces additions to the language as distributed with the [standard library](https://docs.python.org/3/library/index.html) that come with every installation.\n",
"\n",
"Furthermore, some very popular third-party libraries like [numpy](https://www.numpy.org/), [pandas](https://pandas.pydata.org/), [matplotlib](https://matplotlib.org/), and others are portrayed."
"It teaches the concepts behind and the syntax of the core Python language as defined by the [Python Software Foundation](https://www.python.org/psf/) in the official [language reference](https://docs.python.org/3/reference/index.html). Furthermore, it introduces commonly used functionalities from the [standard library](https://docs.python.org/3/library/index.html) and popular third-party libraries like [numpy](https://www.numpy.org/), [pandas](https://pandas.pydata.org/), [matplotlib](https://matplotlib.org/), and others."
]
},
{
@ -56,7 +54,7 @@
}
},
"source": [
"To be suitable for *total beginners*, there are *no* formal prerequisites. It is only expected that the student has:\n",
"This book is suitable for *total beginners*, and there are *no* formal prerequisites. The student only needs to have:\n",
"\n",
"- a *solid* understanding of the **English language**,\n",
"- knowledge of **basic mathematics** from high school,\n",
@ -94,7 +92,7 @@
}
},
"source": [
"This includes but is not limited to topics such as:\n",
"These include but are not limited to topics such as:\n",
"- linear algebra\n",
"- statistics & econometrics\n",
"- data cleaning & wrangling\n",
@ -108,7 +106,7 @@
"- quantitative marketing (e.g., customer segmentation)\n",
"- quantitative supply chain management (e.g., forecasting)\n",
"- management science & decision models\n",
"- backend / API / web development (to serve data products to clients)"
"- backend/API/web development (to serve data products to clients)"
]
},
{
@ -130,9 +128,9 @@
}
},
"source": [
"The term **[data science](https://en.wikipedia.org/wiki/Data_science)** is rather vague and does actually *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 [artifical 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' studies 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. This could make teaching easier for top-notch researchers who use a lot of programming in their day-to-day lifes answering big questions: The student and the teacher are then more likely to \"speak\" the same 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 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.\""
]
},
{
@ -154,11 +152,11 @@
}
},
"source": [
"To follow this book, a working installation of **Python 3.6** or higher is needed.\n",
"To \"read\" this book in the most meaningful way, a working installation of **Python 3.6** or higher is needed.\n",
"\n",
"A popular and beginner friendly way is to install the [Anaconda Distribution](https://www.anaconda.com/distribution/) that not only ships Python and the standard library but comes pre-packaged with a lot of third-party libraries from the so-called \"scientific stack\". Just go to the [download](https://www.anaconda.com/download/) page and install the latest version (i.e., *2019-07* with Python 3.7 at the time of this writing) for your operating system.\n",
"A popular and beginner-friendly way is to install the [Anaconda Distribution](https://www.anaconda.com/distribution/) that not only ships Python and the standard library but comes pre-packaged with a lot of third-party libraries from the so-called \"scientific stack.\" Just go to the [download](https://www.anaconda.com/download/) page and install the latest version (i.e., *2019-07* with Python 3.7 at the time of this writing) for your operating system.\n",
"\n",
"Then, among others, you will find an entry \"Jupyter Notebook\" in your start menu like below. Click on it and a new tab in your web browser will open where you can switch between folders as you could in your computer's default file browser."
"Then, among others, you find an entry \"Jupyter Notebook\" in your start menu like below. Click on it to open a new tab in your web browser where you can switch between folders as you could in your computer's default file browser."
]
},
{
@ -180,7 +178,7 @@
}
},
"source": [
"To download the materials accompanying this book as a ZIP file, open this [GitHub repository](https://github.com/webartifex/intro-to-python) in a web browser and click on the green \"Clone or download\" button on the right. Then, unpack the ZIP file into a folder of your choosing (ideally somewhere within your personal user folder so that the files show up right away)."
"To download the materials accompanying this book as a ZIP file, open this [GitHub repository](https://github.com/webartifex/intro-to-python) in a web browser and click on the green \"Clone or download\" button on the right. Then, unpack the ZIP file into a folder of your choosing (ideally somewhere within your user folder so that the files show up right away)."
]
},
{
@ -202,7 +200,7 @@
}
},
"source": [
"Python can also be installed in a \"pure\" way as obtained from its core development team. However, this is somewhat too \"advanced\" for a beginner who would then also be responsible for setting up all the third-party libraries needed to actually view this document. Plus, many of the involveld steps must be done in a [terminal](https://en.wikipedia.org/wiki/Terminal_emulator) window, which tends to be a bit intimidating for most beginners."
"Python can also be installed in a \"pure\" way as obtained from its core development team. However, this is somewhat too \"advanced\" for a beginner who would then also be responsible for setting up all the third-party libraries needed to view this document. Plus, many of the involved steps are typed in a [terminal](https://en.wikipedia.org/wiki/Terminal_emulator) window, which tends to be a bit intimidating for most beginners."
]
},
{
@ -224,7 +222,7 @@
}
},
"source": [
"For more \"couragous\" beginners wanting to learn how to accomplish this, here is a rough sketch of the aspects to know. First, all Python realeases are available for free on the official [download](https://www.python.org/downloads/) page for any supported operating system. Choose the one you want, then download and install it (cf., the [instruction notes](https://wiki.python.org/moin/BeginnersGuide/Download)). As this only includes core Python and the standard library, the beginner then needs to learn about the [pip](https://pip.pypa.io/en/stable/) module, which is to be used inside a terminal. With the command `python -m pip install jupyter`, all necessary third-party libraries can be installed (cf., more background [here](https://jupyter.readthedocs.io/en/latest/install.html)). However, this would be done in a *system-wide* fashion and is not recommended. Instead, the best practice is to create a so-called **virtual environment** with the [venv](https://docs.python.org/3/library/venv.html) module with which the installed third-party packages can be *isolated* on a per-project basis (the command `python -m venv env-name` creates a virtual enviroment called \"env-name\"). This tactic is employed to avoid a situation known as **[dependency hell](https://en.wikipedia.org/wiki/Dependency_hell)** Once created, the virtual environment must then be activated each time before resuming work in each terminal (with the command `source env-name/bin/activate`). While there exist convenience tools that automate parts of this (e.g., [poetry](https://poetry.eustace.io/docs/) or [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/)), it only distracts a beginner from actually studying the Python language. Yet, it is still worthwhile to have heard about these terms and concepts as many online resources often implicitly assume the user to know about them."
"For more \"courageous\" beginners wanting to learn how to accomplish this, here is a rough sketch of the aspects to know. First, all Python releases are available for free on the official [download](https://www.python.org/downloads/) page for any supported operating system. Choose the latest one applicable, then download and install it (cf., the [instruction notes](https://wiki.python.org/moin/BeginnersGuide/Download)). As this only includes core Python and the standard library, the beginner then needs to learn about the [pip](https://pip.pypa.io/en/stable/) module. With the command `python -m pip install jupyter`, all necessary third-party libraries are installed (cf., more background [here](https://jupyter.readthedocs.io/en/latest/install.html)). However, this would be done in a *system-wide* fashion and is not recommended. Instead, the best practice is to create a so-called **virtual environment** with the [venv](https://docs.python.org/3/library/venv.html) module with which the installed third-party packages are *isolated* on a per-project basis (the command `python -m venv env-name` creates a virtual environment called \"env-name\"). This tactic is employed to avoid a situation known as **[dependency hell](https://en.wikipedia.org/wiki/Dependency_hell)**. Once created, the virtual environment must then be activated each time before resuming work in each terminal (with the command `source env-name/bin/activate`). While there exist convenience tools that automate parts of this (e.g., [poetry](https://poetry.eustace.io/docs/) or [virtualenvwrapper](https://virtualenvwrapper.readthedocs.io/en/latest/)), it only distracts a beginner from studying the Python language. Yet, it is still worthwhile to have heard about these terms and concepts as many online resources often implicitly assume the user to know about them."
]
},
{
@ -250,9 +248,9 @@
"\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",
"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 to mix 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."
"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."
]
},
{
@ -274,15 +272,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",
"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 simply outputs the text \"Hello world\" when executed. To edit an existing code cell, just 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 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",
"\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 into 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 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",
"\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 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",
"\n",
"Similarly, a Markdown cell is also in either the edit or command mode. For example, simply 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 actually 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 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",
"\n",
"To change a cell's type, choose either \"Code\" or \"Markdown\" in the navigation bar at the top."
]
@ -316,7 +314,7 @@
}
},
"source": [
"Sometimes a code cell starts with an exclamation mark `!`. Then, the Jupyter notebook behaves as if you just typed the following command right into a terminal. The cell below asks `python` to show its version number. This is actually *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."
]
},
{
@ -359,15 +357,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",
"- 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",
"\n",
"Programming definitely exhibits elements of an **art** or a **craft** as we will 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."
]
},
{
@ -385,7 +383,7 @@
"- 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. In fact, many computer scientists only know how to produce \"ugly\" 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."
]
},
{
@ -396,7 +394,7 @@
}
},
"source": [
"*IT* or *information technology* is a term that has many meanings to many people. Often, it has something to do with hardware and devices both of which are out of scope for programmers and computer scientists. In fact, many people from the two aforementioned fields are more than happy if their printer and internet just work as they do not know a lot more about that than non-technical people."
"*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."
]
},
{
@ -434,8 +432,8 @@
"- [Guido van Rossum](https://en.wikipedia.org/wiki/Guido_van_Rossum) (Pythons **[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 individual knowledge and best practices in their free time to make Python even better\n",
"- **Python 3** resulted from a major 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",
"- 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 language is named after the sketch comedy group [Monty Python](https://en.wikipedia.org/wiki/Monty_Python)"
]
},
@ -458,7 +456,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**."
]
},
{
@ -480,9 +478,9 @@
}
},
"source": [
"Couldn't a company like Google, Facebook, or Microsoft come up with a better programming language? The following argument provides hints why this cannot really be the case.\n",
"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",
"\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 certain 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 just *use* the language over time and in new and unpredictable contexts making up their own 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."
]
},
{
@ -493,7 +491,7 @@
}
},
"source": [
"Loose *communities* are the main building block around which open-source software is built. Someone starts a project (like Guido) 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 number of people using it. After a while, people start local user groups to share their same interests and meet on a regular basis (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 (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,11 +502,11 @@
}
},
"source": [
"While these communities are rather loose and constantly changing, smaller in-groups, often democratically organized and elected (e.g., the Python Software Foundation), take care of, for example, the development of the \"core\" Python language itself.\n",
"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 lookep up in the [Python Language Reference](https://docs.python.org/3/reference/index.html). In order 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 anyone interested and are then either accepted, modified, or rejected if, for example, the change introduces internal inconsistencies. This is very similar to the **double blind peer review** established in academia. In fact, 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",
"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",
"\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."
"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."
]
},
{
@ -519,7 +517,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). This is a huge benefit compared to commercial languages (e.g., MATLAB) since a programmer can always continue to **study best practices** or how things are done. 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 notable 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 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."
]
},
{
@ -541,13 +539,13 @@
}
},
"source": [
"The \"weird\" thing is that the default Python implementation is actually written in the C language.\n",
"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) (check this [introduction](https://www.learncpp.com/)) are wide-spread and long established (i.e., since the 1970s) programming languages that are employed in many mission critical softwares (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 learn).\n",
"\n",
"In contrast, Python automatically manages the memory for the programmer. This speeds up the development process a lot. So speed here is really a trade-off of application run time vs. engineering / development time and in many applications the program's run time is not that important (e.g., 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",
"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**, in many cases this does not really matter as the **significantly shorter development cycles** are the more important cost factor in a rapidly changing business world."
"**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."
]
},
{
@ -580,25 +578,23 @@
}
},
"source": [
"While it is usually not the best argument to quote authorative figures like the pope, we will do this in this section anyways:\n",
"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",
"\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 ([source](https://news.ycombinator.com/item?id=602307))\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 ([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 **re-written in Python** right away ([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",
" - 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 **re-written 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",
" - Guido van Rossom was hired by Google from 2005 to 2012 to advance the language there\n",
"- **[NASA](https://www.nasa.gov/)** open-sources a lot of its projects, many of which are written in Python and regard working with really big data ([source](https://code.nasa.gov/language/python/))\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",
"- **[Instagram](https://instagram.com/)** operates the largest installation of the popular **web framework [Django](https://www.djangoproject.com/)** ([source](https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366))\n",
"- **[Spotify](https://spotify.com/)** bases its data science on Python ([source](https://labs.spotify.com/2013/03/20/how-we-use-python-at-spotify/))\n",
"- **[Netflix](https://netflix.com/)** also runs its predictive models on Python ([source](https://medium.com/netflix-techblog/python-at-netflix-86b6028b3b3e))\n",
"- **[Dropbox](https://dropbox.com/)** \"stole\" Guido van Rossom from Google to help scale the platform ([source](https://medium.com/dropbox-makers/guido-van-rossum-on-finding-his-way-e018e8b5f6b1))\n",
"- **[JPMorgan Chase](https://www.jpmorganchase.com/)** requires new employees to learn Python as part of the onboarding process starting with the 2018 intake ([source](https://www.ft.com/content/4c17d6ce-c8b2-11e8-ba8f-ee390057b8c9?segmentId=a7371401-027d-d8bf-8a7f-2a746e767d56))\n",
"- ...\n",
"- ... this list is intentionally shortened as Python is simply very popular ..."
"- **[Instagram](https://instagram.com/)** operates the largest installation of the popular **web framework [Django](https://www.djangoproject.com/)** (cf., [source](https://instagram-engineering.com/web-service-efficiency-at-instagram-with-python-4976d078e366))\n",
"- **[Spotify](https://spotify.com/)** bases its data science on Python (cf., [source](https://labs.spotify.com/2013/03/20/how-we-use-python-at-spotify/))\n",
"- **[Netflix](https://netflix.com/)** also runs its predictive models on Python (cf., [source](https://medium.com/netflix-techblog/python-at-netflix-86b6028b3b3e))\n",
"- **[Dropbox](https://dropbox.com/)** \"stole\" Guido van Rossom from Google to help scale the platform (cf., [source](https://medium.com/dropbox-makers/guido-van-rossum-on-finding-his-way-e018e8b5f6b1))\n",
"- **[JPMorgan Chase](https://www.jpmorganchase.com/)** requires new employees to learn Python as part of the onboarding process starting with the 2018 intake (cf., [source](https://www.ft.com/content/4c17d6ce-c8b2-11e8-ba8f-ee390057b8c9?segmentId=a7371401-027d-d8bf-8a7f-2a746e767d56))"
]
},
{
@ -631,7 +627,7 @@
}
},
"source": [
"As the graph below shows, neither Google's very own language **[Go](https://golang.org/)** nor **[R](https://www.r-project.org/)**, a very popular language in the niche of statistics and data science, can compete with Python's year-to-year growth."
"As the graph below shows, neither Google's very own language **[Go](https://golang.org/)** nor **[R](https://www.r-project.org/)**, a domain-specific language in the niche of statistics, can compete with Python's year-to-year growth."
]
},
{
@ -686,13 +682,13 @@
}
},
"source": [
"Simply put, **always be coding**.\n",
"**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 documentation, blogs with best practices, and tutorials, or researching some problem on Stack Overflow while trying to implement some feature 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 software simultaneously using software like **[git](https://git-scm.com/)**. In short, programming involves a lot of \"muscle memory\". This 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 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 requirement for the very first time. Coding also means \"breaking\" things to find out what makes them actually work to begin with.\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 regular basis and not right before some task is due, just like learning a \"real\" language."
"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."
]
},
{
@ -716,12 +712,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 by 30 minute intervals.\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",
"\n",
"Have you ever wondered why so many tech nerds work all the nights and sleep during \"weird\" hours? This is mainly because many programming related tasks require a certain \"flow\" state of one's mind. This is hard to achieve when one can get interupted, 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",
"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 any more to hear a \"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."
]
},
{
@ -743,17 +739,17 @@
}
},
"source": [
"When being asked the above question, most programmers will answer something that can be classified into one of two broader groups.\n",
"When being asked the above question, most programmers answer something that can be classified into one of two broader groups.\n",
"\n",
"**1) Toy Problem / Case Study / Prototype**: Pick some problem that you want to write a programatic solution for, break it down into smaller packages, and solve them \"backwards\".\n",
"**1) Toy Problem, Case Study, or Prototype**: Pick some problem, break it down into smaller sub-problems, and solve them with an end in mind.\n",
"\n",
"**2) Books / Video Tutorials / Courses**: Research the best book / blog post / video tutorial for something and work it through from start to end.\n",
"**2) Books, Video Tutorials, and Courses**: Research the best book, blog, video, or tutorial for something and work it through from start to end.\n",
"\n",
"The truth is that you need to iterate between these two phases.\n",
"\n",
"Building a prototype will always reveal issues no book or tutorial can think of before. Data is never clean as it comes. Some algorithm from a text book must be adapted to a very specific but important aspect of a case study. It is important to learn to \"ship a product\", i.e., to finish some project to the very end because only then you will have looked at all the aspects.\n",
"Building a prototype always reveals issues no book or tutorial can think of before. Data is never as clean as it should be. An algorithm from a textbook must be adapted to a peculiar aspect of a case study. It is essential to learn to \"ship a product\" because only then will one have looked at all the aspects.\n",
"\n",
"The major downside of this approach is that you likely learn bad \"patterns\" as whatever you learn is overfitted to the case and you do not get the big picture or mental concepts behind a solution. This is a gap well written books can fill in (e.g., check the Python / Programming books by [Packt](https://www.packtpub.com/packt/offers/free-learning/) or [OReilly](https://www.oreilly.com/))."
"The major downside of this approach is that one likely learns bad \"patterns\" overfitted to the case at hand, and one does not get the big picture or mental concepts behind a solution. This gap can be filled in by well-written books: For example, check the Python/programming books offered by [Packt](https://www.packtpub.com/packt/offers/free-learning/) or [OReilly](https://www.oreilly.com/)."
]
},
{
@ -778,11 +774,11 @@
"**Part 1: Expressing Logic**\n",
"\n",
"- What is a programming language? What kind of words exist?\n",
" 1. Elements of a Program\n",
" 2. Functions & Modularization\n",
" 1. [Elements of a Program](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb)\n",
" 2. [Functions & Modularization](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb)\n",
"- What is the flow of execution? How can we form sentences from words?\n",
" 3. Conditionals & Exceptions\n",
" 4. Recursion & Looping"
" 3. [Conditionals & Exceptions](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb)\n",
" 4. [Recursion & Looping](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb)"
]
},
{
@ -796,12 +792,12 @@
"**Part 2: Managing Data and Memory**\n",
"\n",
"- How is data stored in memory?\n",
" 5. Numbers\n",
" 5. [Numbers](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb)\n",
" 6. Text\n",
" 7. Sequences\n",
" 8. Mappings & Sets\n",
" 9. Arrays\n",
"- How can we create our own data types?\n",
"- How can we create custom data types?\n",
" 10. Object-Orientation"
]
},

View file

@ -53,7 +53,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q2**: Explain what is a *pull request* and elaborate how this concept fits to a *distributed* organization of work!"
"**Q2**: Explain what is a *pull request* and elaborate on how this concept fits a *distributed* organization of work!"
]
},
{
@ -81,7 +81,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q4**: What is a major advantage of a \"slow\" programming language like Python over a faster one like C?"
"**Q4**: What is a significant advantage of a \"slow\" programming language like Python over a faster one like C?"
]
},
{
@ -109,7 +109,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q5**: Python has been the fastest growing *major* programming language in recent years."
"**Q5**: Python has been the fastest-growing *major* programming language in recent years."
]
},
{
@ -137,7 +137,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q7**: Python was originally designed for highly intensive numerical computing, in particular for use cases from physics and astronomy."
"**Q7**: Python was initially designed for highly intensive numerical computing, in particular for use cases from physics and astronomy."
]
},
{
@ -151,7 +151,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q8**: JavaScript is a special subset of the Java language."
"**Q8**: JavaScript is a subset of the Java language."
]
},
{
@ -165,7 +165,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q9**: Python is *free software*. That means it will never cost anything."
"**Q9**: Python is *free software*. That means it does not cost anything."
]
},
{
@ -179,7 +179,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q10**: The main purpose of PEPs is to regulate how code should be documented and/or styled."
"**Q10**: The primary purpose of PEPs is to regulate how code should be documented and styled."
]
},
{
@ -228,7 +228,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q12**: The quote \"Education is what remains after one has forgotten what one has learned in school\" is attributed to Albert Einstein. Use a special Markdown syntax to display the author and his quote appropriately!"
"**Q12**: The quote \"Education is what remains after one has forgotten what one has learned in school\" is attributed to Albert Einstein. Display the author and his quote appropriately!"
]
},
{

File diff suppressed because it is too large Load diff

View file

@ -40,7 +40,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q1**: Elaborate on how **modulo division** might be a very useful operation to know!"
"**Q1**: Elaborate on how **modulo division** might be a handy operation to know!"
]
},
{

View file

@ -19,11 +19,11 @@
}
},
"source": [
"In [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) we typed the **business logic** of our little program to calculate the mean of a subset of a list of numbers right into the code cells. Then, we executed them one after another. We had no way of **re-using** the code except for either re-executing the cells 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.ipynb), we typed the **business logic** of our little program to calculate the mean of a subset of a list of numbers right into the code cells. Then, we executed them one after another. We had no way of **re-using** the code except for either re-executing the cells 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 re-using the same parts inside core Python every time we use them.\n",
"\n",
"This chapter shows how Python offers language constructs that let us **define** our own functions that we can then **call** just like the built-in ones."
"This chapter shows how Python offers language constructs that let us **define** functions ourselves that we may then **call** just like the built-in ones."
]
},
{
@ -45,19 +45,19 @@
}
},
"source": [
"So-called **[user-defined functions](https://docs.python.org/3/reference/compound_stmts.html#function-definitions)** can be created with the `def` statement. To extend an already familiar example, we re-use the introductory example from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) 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 re-use the introductory example from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) 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 for ordinary variables. In fact, Python manages function names just 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 actually part of the name but must always be written out in the `def` statement for syntactic reasons.\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",
"Functions may define an arbitrary number of **parameters** as inputs that can then be referenced within the indented **code block**: They are simply listed within the parentheses in the `def` statement (i.e., `numbers` below). \n",
"Functions may define an arbitrary number of **parameters** as inputs that can then be referenced within the indented **code block**: They are listed within the parentheses in the `def` statement (i.e., `numbers` below). \n",
"\n",
"The code block is often also called a function's **body** while the first line with the `def` in it is the **header** and must end with a colon.\n",
"The code block is also called a function's **body**, while the first line starting with `def` and ending with a colon is the **header**.\n",
"\n",
"Together, the name and the list of parameters are also referred to as the function's **[signature](https://en.wikipedia.org/wiki/Type_signature)** (i.e., `average_evens(numbers)` below).\n",
"\n",
"A function may come with an *explicit* **[return value](https://docs.python.org/3/reference/simple_stmts.html#the-return-statement)** (i.e., \"result\" or \"output\") specified with 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** (e.g., the [print()](https://docs.python.org/3/library/functions.html#print) built-in). Strictly speaking, they also have an *implicit* return value of `None` that is different from the `False` we saw in Chapter 1.\n",
"\n",
"To maintain good coding practices, 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 with **triple-double quotes** (strings are covered in depth in Chapter 6). Good 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.ipynb). 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)."
]
},
{
@ -92,7 +92,7 @@
}
},
"source": [
"Once defined, a function can be referenced just like any other variable by its name (i.e., *without* the parenthesis). Its value might seem awkward at first: It consists of the location where we defined the function (i.e., `__main__`, which is Python's way of saying \"in this notebook\") and the signature."
"Once defined, a function may be referenced just like any other variable by its name (i.e., *without* the parenthesis). Its value might seem awkward at first: It consists of the location where we defined the function (i.e., `__main__`, which is Python's way of saying \"in this notebook\") and the signature."
]
},
{
@ -142,7 +142,7 @@
{
"data": {
"text/plain": [
"140693945143776"
"140519730762208"
]
},
"execution_count": 3,
@ -254,7 +254,7 @@
}
},
"source": [
"Two questions marks even show a function's source code."
"Two question marks even show a function's source code."
]
},
{
@ -289,7 +289,7 @@
}
},
"source": [
"We can **call** (i.e., \"execute\") a function with the **call operator** `()` as often as we wish. The formal parameters are filled in by passing variables or expressions as **arguments** to the function within the parentheses."
"We **call** (i.e., \"execute\") a function with the **call operator** `()` as often as we wish. The formal parameters are filled in by passing variables or expressions as **arguments** to the function within the parentheses."
]
},
{
@ -337,7 +337,7 @@
}
},
"source": [
"The return value is usually assigned to a new variable for later reference. Otherwise we would loose access to it in memory right away."
"The return value is commonly assigned to a new variable for later reference. Otherwise, we would lose access to it in memory right away."
]
},
{
@ -493,7 +493,7 @@
}
},
"source": [
"[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010%5D%0A%0Adef%20average_evens%28numbers%29%3A%0A%20%20%20%20evens%20%3D%20%5Bn%20for%20n%20in%20numbers%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_evens%28nums%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) visualizes what happens in memory: To be precise, in the exact moment when the function call is initiated and `nums` is passed in as the `numbers` argument, there are *two* pointers to the *same* `list` object (cf., steps 4-5 in the visualization). We also see how Python creates a *new* **frame** that holds the function's local scope (i.e., \"internal names\") in addition to the **global** frame. Frames are nothing but [namespaces](https://en.wikipedia.org/wiki/Namespace) to *isolate* the names of different **scopes** from each other. The list comprehension `[n for n in numbers if n % 2 == 0]` constitutes yet another frame that is in scope as the `list` object assigned to `evens` is *being* created (cf., steps 6-18). When the function returns, only the global frame is left (cf., steps 21-22)."
"[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010%5D%0A%0Adef%20average_evens%28numbers%29%3A%0A%20%20%20%20evens%20%3D%20%5Bn%20for%20n%20in%20numbers%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_evens%28nums%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) visualizes what happens in memory: To be precise, in the exact moment when the function call is initiated and `nums` passed in as the `numbers` argument, there are *two* pointers to the *same* `list` object (cf., steps 4-5 in the visualization). We also see how Python creates a *new* **frame** that holds the function's local scope (i.e., \"internal names\") in addition to the **global** frame. Frames are nothing but [namespaces](https://en.wikipedia.org/wiki/Namespace) to *isolate* the names of different **scopes** from each other. The list comprehension `[n for n in numbers if n % 2 == 0]` constitutes yet another frame that is in scope as the `list` object assigned to `evens` is *being* created (cf., steps 6-18). When the function returns, only the global frame is left (cf., steps 21-22)."
]
},
{
@ -515,7 +515,7 @@
}
},
"source": [
"On the contrary, while a function is being executed, it can reference the variables of **enclosing scopes** (i.e., \"outside\" of it). This is a common source of *semantic* errors. Consider the following stylized (and incorrect) example `average_wrong()`. The error is hard to spot with eyes: The function never references the `numbers` parameter but the `nums` variable in the **global scope** instead."
"On the contrary, while a function is *being* executed, it can reference the variables of **enclosing scopes** (i.e., \"outside\" of it). This is a common source of *semantic* errors. Consider the following stylized (and incorrect) example `average_wrong()`. The error is hard to spot with eyes: The function never references the `numbers` parameter but the `nums` variable in the **global scope** instead."
]
},
{
@ -550,7 +550,7 @@
}
},
"source": [
"`nums` in the global scope is of course unchanged."
"`nums` in the global scope is, of course, unchanged."
]
},
{
@ -657,7 +657,7 @@
"source": [
"[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010%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 points to takes *12* computational steps, namely one for setting up an empty `list` object, *ten* for filling it with elements derived from `nums` in the global scope, and one to make `evens` point at it (cf., steps 6-18).\n",
"\n",
"The frames logic shown by PythonTutor is the mechanism by which Python not only manages the names inside one function call but for potentially many calls occuring simultaneously as we will see in [Chapter 4](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb). It is the reason why we may re-use 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.ipynb). It is the reason why we may re-use 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."
]
},
{
@ -752,7 +752,7 @@
}
},
"source": [
"As good practice, let's first use inputs for which we can calculate the answer in our heads to \"verify\" that `average_odds()` is \"correct\"."
"As good practice, let's first use inputs for which we can calculate the answer in our heads to \"verify\" that `average_odds()` is \"correct.\""
]
},
{
@ -787,7 +787,7 @@
}
},
"source": [
"To make the confusion even bigger, let's also pass the global `nums` as an argument to `average_odds()`."
"To add to the confusion, let's also pass the global `nums` as an argument to `average_odds()`."
]
},
{
@ -857,13 +857,13 @@
}
},
"source": [
"The reason why everything just works is that *every time* we (re-)assign an object to a variable *inside* a function with the `=` statement, this is done in the *local* scope by default. There are ways to change variables existing in an outer scope from within a function but this is a rather advanced topic on its own.\n",
"The reason why everything works is that *every time* we (re-)assign an object to a variable *inside* a function with the `=` statement, this is done in the *local* scope by default. There are ways to change variables existing in an outer scope from within a function, but this is a rather advanced topic on its own.\n",
"\n",
"[PythonTutor](http://pythontutor.com/visualize.html#code=nums%20%3D%20%5B1,%202,%203,%204,%205,%206,%207,%208,%209,%2010%5D%0A%0Adef%20average_odds%28numbers%29%3A%0A%20%20%20%20nums%20%3D%20%5Bint%28n%29%20for%20n%20in%20numbers%5D%0A%20%20%20%20odds%20%3D%20%5Bn%20for%20n%20in%20nums%20if%20n%20%25%202%20!%3D%200%5D%0A%20%20%20%20average%20%3D%20sum%28odds%29%20/%20len%28odds%29%0A%20%20%20%20return%20average%0A%0Arv%20%3D%20average_odds%28%5B1.0,%2010.0,%203.0,%2010.0,%205.0%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) shows how *two* `nums` variables exist in *different* scopes pointing to *different* objects (cf., steps 14-25) when we execute `average_odds([1.0, 10.0, 3.0, 10.0, 5.0])`.\n",
"\n",
"Variables whose names collide with the ones of variables in enclosing scopes - and the global scope is just the most enclosing scope - are said to **shadow** them.\n",
"\n",
"While this is not a problem for Python as we have observed, it may lead to less readable code for us humans and should be avoided if possible. But, as we have also heard, \"[naming things](https://skeptics.stackexchange.com/questions/19836/has-phil-karlton-ever-said-there-are-only-two-hard-things-in-computer-science)\" is often considered hard as well and we have to be prepared to encounter shadowing variables."
"While this is not a problem for Python, it may lead to less readable code for us humans and should be avoided if possible. But, as we have also heard, \"[naming things](https://skeptics.stackexchange.com/questions/19836/has-phil-karlton-ever-said-there-are-only-two-hard-things-in-computer-science)\" is often considered hard as well, and we have to be prepared to encounter shadowing variables."
]
},
{
@ -946,7 +946,7 @@
}
},
"source": [
"We can cast certain objects as a different type. For example, to \"convert\" a float or a text into an integer, we use the [int()](https://docs.python.org/3/library/functions.html#int) built-in. This actually creates a *new* object of type `int` from the provided `avg` or `\"6\"` objects who continue to exist in memory unchanged."
"We may cast objects as a different type. For example, to \"convert\" a float or a text into an integer, we use the [int()](https://docs.python.org/3/library/functions.html#int) built-in. It creates a *new* object of type `int` from the provided `avg` or `\"6\"` objects that continue to exist in memory unchanged."
]
},
{
@ -1088,7 +1088,7 @@
}
},
"source": [
"Not all conversions are valid and *runtime* errors can occur as the `ValueError` shows."
"Not all conversions are valid and *runtime* errors may occur as the `ValueError` shows."
]
},
{
@ -1124,7 +1124,7 @@
}
},
"source": [
"We can also go in the other direction with the [float()](https://docs.python.org/3/library/functions.html#float) built-in function."
"We may also go in the other direction with the [float()](https://docs.python.org/3/library/functions.html#float) built-in function."
]
},
{
@ -1170,7 +1170,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.ipynb), however, we saw the built-in function [divmod()](https://docs.python.org/3/library/functions.html#divmod) taking two arguments. Obviously, the order of the numbers passed in mattered. Whenever we call a function and list its arguments in a comma seperated 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.ipynb), 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**."
]
},
{
@ -1229,7 +1229,7 @@
}
},
"source": [
"For many functions there is a natural order to the arguments. But what if this is not the case? For example, let's create a close relative of the above `average_evens()` function that also scales the resulting average by a factor. What is more natural? Passing in `numbers` first? Or `scalar`? There is no obvious way and we continue with the first alternative for no real reason."
"For many functions, there is a natural order to the arguments. But what if this is not the case? For example, let's create a close relative of the above `average_evens()` function that also scales the resulting average by a factor. What is more natural? Passing in `numbers` first? Or `scalar`? There is no obvious way and we continue with the first alternative for no concrete reason."
]
},
{
@ -1266,7 +1266,7 @@
}
},
"source": [
"As with [divmod()](https://docs.python.org/3/library/functions.html#divmod), we can pass in the arguments by position."
"As with [divmod()](https://docs.python.org/3/library/functions.html#divmod), we pass in the arguments by position."
]
},
{
@ -1301,9 +1301,9 @@
}
},
"source": [
"However, now the function call is a bit harder to comprehend as we need to always remember what the `2` means. This becomes even harder the more parameters we specify.\n",
"However, now the function call is a bit harder to comprehend as we always need to remember what the `2` means. This becomes harder the more parameters we specify.\n",
"\n",
"Luckily, we can also reference the formal parameter names as **keyword arguments**. We can even combine positional and keyword arguments in the same function call. Each of the following does the exact same thing."
"Luckily, we may also reference the formal parameter names as **keyword arguments**. We can even combine positional and keyword arguments in the same function call. Each of the following does the *same*."
]
},
{
@ -1430,11 +1430,11 @@
}
},
"source": [
"Defining both `average_evens()` and `scaled_average_evens()` is also kind of repetitive as most of their code is the same. Such a redundancy will make a code base harder to maintain in the long run as whenever we change the logic in one function we must *not* forget to do so for the other function as well.\n",
"Defining both `average_evens()` and `scaled_average_evens()` is also kind of repetitive as most of their code is the same. Such a redundancy makes a codebase harder to maintain in the long run as whenever we change the logic in one function, we must *not* forget to do so for the other function as well.\n",
"\n",
"A better way is to design related functions in a **modular** fashion such that they re-use each other's logic.\n",
"\n",
"For example, as not scaling an average is just a special case of scaling it with `1`, we could re-define the two functions like below: In this setting, the function resembling the *special* case (i.e., `average_evens()`) simply **forwards** the call to the more *general* function (i.e., `scaled_average_evens()`) using a `scalar=1` argument."
"For example, as not scaling an average is just a special case of scaling it with `1`, we could re-define the two functions like below: In this setting, the function resembling the *special* case (i.e., `average_evens()`) **forwards** the call to the more *general* function (i.e., `scaled_average_evens()`) using a `scalar=1` argument."
]
},
{
@ -1483,7 +1483,7 @@
}
},
"source": [
"The outcome of `average_evens(nums)` is of course still `6.0`."
"The outcome of `average_evens(nums)` is, of course, still `6.0`."
]
},
{
@ -1555,9 +1555,9 @@
}
},
"source": [
"Now we can call the function either with or without the `scalar` argument.\n",
"Now we call the function either with or without the `scalar` argument.\n",
"\n",
"If `scalar` is passed in, this can be done as either a positional or a keyword argument. Which of the two versions where `scalar` is `2` is easier to comprehend in a large program?"
"If `scalar` is to be passed in, this may be done as either a positional or a keyword argument. Which of the two versions where `scalar` is `2` is more \"natural\" and faster to comprehend in a larger program?"
]
},
{
@ -1651,9 +1651,9 @@
}
},
"source": [
"Since we *assumed* that scaling will occur *rarely*, we'd prefer that our new version of `average_evens()` be called with a *keyword argument* whenever `scalar` is passed in explicitly. Then, the second argument is never ambiguous as we could always read its name.\n",
"Since we *assumed* that scaling occurs *rarely*, we'd prefer that our new version of `average_evens()` be called with a *keyword argument* whenever `scalar` is to be passed in explicitly. Then, the second argument is never ambiguous as we could always read its name.\n",
"\n",
"Luckily, Python offers a **keyword-only** syntax, where all we need to do is to place the arguments for which we require *explicit* keyword use after an asterix `*`."
"Luckily, Python offers a **keyword-only** syntax, where all we need to do is to place the arguments for which we require *explicit* keyword use after an asterisk `*`."
]
},
{
@ -1798,13 +1798,13 @@
"source": [
"The `def` statement is a statement because of its side effect of creating a *new* name that points to a *new* `function` object in memory.\n",
"\n",
"We can thus think of it as doing *two* things at once (i.e., either both of them happen or none). First, a `function` object is created that contains the concrete $0$s and $1$s that resemble the instructions we put into the function's body. In the context of a function, these $0$s and $1$s are also called **[byte code](https://en.wikipedia.org/wiki/Bytecode)**. Then, a name is created pointing at the new `function` object.\n",
"We can thus think of it as doing *two* things at once (i.e., either both of them happen or none). First, a `function` object is created that contains the concrete $0$s and $1$s that resemble the instructions we put into the function's body. In the context of a function, these $0$s and $1$s are also called **[byte code](https://en.wikipedia.org/wiki/Bytecode)**. Then, a name pointing at the new `function` object is created.\n",
"\n",
"Only this second aspect makes `def` a statement: Merely creating a new object in memory without making it accessible for later reference does *not* constitute a side effect. This is because the state the program is *not* changed. After all, if we cannot reference an object, how do we know that it is actually existing?\n",
"Only this second aspect makes `def` a statement: Merely creating a new object in memory without making it accessible for later reference does *not* constitute a side effect because the state the program is *not* changed. After all, if we cannot reference an object, how do we know it exists in the first place?\n",
"\n",
"Python provides a so-called **[lambda expression](https://docs.python.org/3/reference/expressions.html#lambda)** syntax that allows us to *only* create a `function` object in memory *without* making a name point to it.\n",
"\n",
"It starts with the keyword `lambda` followed by an optional comma seperated enumeration of parameters, a mandatory colon, and *one* expression that also is the resulting `function` object's return value.\n",
"It starts with the keyword `lambda` followed by an optional comma separated enumeration of parameters, a mandatory colon, and *one* expression that also is the resulting `function` object's return value.\n",
"\n",
"Because it does not create a name pointing to the object, we effectively create \"anonymous\" functions with it. In the example, we create a `function` object that adds `3` to the only argument passed in as the parameter `x` and returns that sum."
]
@ -1845,7 +1845,7 @@
"\n",
"We created a `function` object, dit *not* call it, and Python immediately forgot about it. So what's the point?\n",
"\n",
"Just to prove that the `lambda` expression really creates a callable `function` object, we use the simple `=` statement to assign it to the variable `add_three`, which is really `add_three()` as per our convention from above."
"To prove that a `lambda` expression creates a callable `function` object, we use the simple `=` statement to assign it to the variable `add_three`, which is really `add_three()` as per our convention from above."
]
},
{
@ -1869,7 +1869,7 @@
}
},
"source": [
"Now we can call `add_three()` as if we defined it with the `def` statement to begin with."
"Now we call `add_three()` as if we defined it with the `def` statement in the first place."
]
},
{
@ -1904,7 +1904,7 @@
}
},
"source": [
"Alternatively, we could call any anonymous `function` object created with an `lambda` expression right away (i.e. without assigning it to a variable), which looks really weird for now as we need *two* pairs of parentheses: The first is just a delimiter whereas the second the call operator."
"Alternatively, we could call an anonymous `function` object created with a `lambda` expression right away (i.e., without assigning it to a variable), which looks quite weird for now as we need *two* pairs of parentheses: The first is just a delimiter whereas the second the call operator."
]
},
{
@ -1939,9 +1939,9 @@
}
},
"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 will use the function only once.\n",
"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 *once* only.\n",
"\n",
"Very popular contexts where we will apply lambda expressions are with the **map-filter-reduce** paradigm in Chapter 7 or when we do \"number crunching\" with **arrays** and **data frames** in Chapter 9."
"Popular applications of lambda expressions are with the **map-filter-reduce** paradigm in Chapter 7 or when we do \"number crunching\" with **arrays** and **data frames** in Chapter 9."
]
},
{
@ -1963,13 +1963,13 @@
}
},
"source": [
"So far, we have only used what we refer to as **core** Python in this book. By this, we mean all the syntactical rules as specified in the [language reference](https://docs.python.org/3/reference/) and a minimal set of about 50 built-in [functions](https://docs.python.org/3/library/functions.html). With this we could already implement any algorithm or business logic we can think of!\n",
"So far, we have only used what we refer to as **core** Python in this book. By this, we mean all the syntactical rules as specified in the [language reference](https://docs.python.org/3/reference/) and a minimal set of about 50 built-in [functions](https://docs.python.org/3/library/functions.html). With this, we could already implement any algorithm or business logic we can think of!\n",
"\n",
"However, after our first couple of programs, we would already start seeing recurring patterns in the code we write. In other words, we would constantly be \"re-inventing the wheel\" in each new project.\n",
"\n",
"Would it not be smarter to pull out the re-usable components from our programs and put them into some project independent **library** of generically useful functionalities? Then we would only need a way of including these **utilities** in our projects.\n",
"\n",
"As all programmers across all languages face this very same issue, most programming languages come with a so-called **[standard library](https://en.wikipedia.org/wiki/Standard_library)** that provides utilities to accomplish common tasks without a lot of code. Examples are making an HTTP request to some website, open and read popular file types (e.g., CSV or Excel files), do something on a computer's file system, and many more."
"As all programmers across all languages face this very same issue, most programming languages come with a so-called **[standard library](https://en.wikipedia.org/wiki/Standard_library)** that provides utilities to accomplish everyday tasks without much code. Examples are making an HTTP request to some website, open and read popular file types (e.g., CSV or Excel files), do something on a computer's file system, and many more."
]
},
{
@ -1991,13 +1991,13 @@
}
},
"source": [
"Python also comes with its own [standard library](https://docs.python.org/3/library/index.html) that is structured into coherent modules and packages for given topics: A **module** is just a plain text file with the file extension *.py* that contains Python code while a **package** is a folder that groups several related modules.\n",
"Python also comes with a [standard library](https://docs.python.org/3/library/index.html) that is structured into coherent modules and packages for given topics: A **module** is just a plain text file with the file extension *.py* that contains Python code while a **package** is a folder that groups several related modules.\n",
"\n",
"The code in the [standard library](https://docs.python.org/3/library/index.html) is contributed and maintained by many volunteers around the world. In contrast to so-called \"third-party\" packages (cf., the next section below), the Python core development team closely monitors and tests the code in the [standard library](https://docs.python.org/3/library/index.html). Consequently, we can be reasonably sure that anything provided by it works correctly independent of our computer's operating system and will most likely also be there in the next Python versions. Parts in the [standard library](https://docs.python.org/3/library/index.html) that are computationally expensive are often re-written in C and therefore much faster than anything we could code in Python ourselves. So, whenever we can solve a problem with the help of the [standard library](https://docs.python.org/3/library/index.html), it is almost always the best way to do so as well.\n",
"The code in the [standard library](https://docs.python.org/3/library/index.html) is contributed and maintained by many volunteers around the world. In contrast to so-called \"third-party\" packages (cf., the next section below), the Python core development team closely monitors and tests the code in the [standard library](https://docs.python.org/3/library/index.html). Consequently, we can be reasonably sure that anything provided by it works correctly independent of our computer's operating system and will most likely also be there in the next Python versions. Parts in the [standard library](https://docs.python.org/3/library/index.html) that are computationally expensive are often re-written in C and, therefore, much faster than anything we could write in Python ourselves. So, whenever we can solve a problem with the help of the [standard library](https://docs.python.org/3/library/index.html), it is almost always the best way to do so as well.\n",
"\n",
"The [standard library](https://docs.python.org/3/library/index.html) has grown very big over the years and we refer to the website [PYMOTW](https://pymotw.com/3/index.html) (i.e., \"Python Module of the Week\") that features well written introductory tutorials and how-to guides to most parts of the library. The same author also published a [book](https://www.amazon.com/Python-Standard-Library-Example-Developers/dp/0134291050/ref=as_li_ss_tl?ie=UTF8&qid=1493563121&sr=8-1&keywords=python+3+standard+library+by+example) that many Pythonistas keep on their shelf for reference. Knowing what is in the [standard library](https://docs.python.org/3/library/index.html) is quite valuable for solving real world tasks quickly.\n",
"The [standard library](https://docs.python.org/3/library/index.html) has grown very big over the years, and we refer to the website [PYMOTW](https://pymotw.com/3/index.html) (i.e., \"Python Module of the Week\") that features well written introductory tutorials and how-to guides to most parts of the library. The same author also published a [book](https://www.amazon.com/Python-Standard-Library-Example-Developers/dp/0134291050/ref=as_li_ss_tl?ie=UTF8&qid=1493563121&sr=8-1&keywords=python+3+standard+library+by+example) that many Pythonistas keep on their shelf for reference. Knowing what is in the [standard library](https://docs.python.org/3/library/index.html) is quite valuable for solving real-world tasks quickly.\n",
"\n",
"Throughout this book we will look at many modules and packages from the [standard library](https://docs.python.org/3/library/index.html) in more depth, starting with the [math](https://docs.python.org/3/library/math.html) and [random](https://docs.python.org/3/library/random.html) modules in this chapter."
"Throughout this book, we look at many modules and packages from the [standard library](https://docs.python.org/3/library/index.html) in more depth, starting with the [math](https://docs.python.org/3/library/math.html) and [random](https://docs.python.org/3/library/random.html) modules in this chapter."
]
},
{
@ -2084,7 +2084,7 @@
{
"data": {
"text/plain": [
"140694050824664"
"140519828111832"
]
},
"execution_count": 58,
@ -2132,7 +2132,7 @@
"\n",
"Let's see what we can do with the `math` module.\n",
"\n",
"The [dir()](https://docs.python.org/3/library/functions.html#dir) built-in function can also be used with an argument passed in. Ignoring the dunder-style names, `math` offers quite a lot of ... names. As we cannot know at this point in time if a listed name refers to a function or an ordinary variable, we use the more generic term **attribute** to mean either one of them."
"The [dir()](https://docs.python.org/3/library/functions.html#dir) built-in function may also be used with an argument passed in. Ignoring the dunder-style names, `math` offers quite a lot of names. As we cannot know at this point if a listed name refers to a function or an ordinary variable, we use the more generic term **attribute** to mean either one of them."
]
},
{
@ -2354,9 +2354,9 @@
}
},
"source": [
"Observe how the arguments passed to functions do not need to be just variables or simple literals. Instead, we can pass in any *expression* that evaluates to a *new* object of the type the function expects.\n",
"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.ipynb): An expression is *any* syntactically correct combination of variables and literals with operators. And the call operator `()` is just ... well another operator. So both of the next two code cells are just expressions! They have no permanent side effect in memory. We can 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.ipynb): 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)."
]
@ -2428,7 +2428,7 @@
}
},
"source": [
"If we only need one particular function from a module, we can also use the alternative `from ... import ...` syntax.\n",
"If we only need one particular function from a module, we may also use the alternative `from ... import ...` syntax.\n",
"\n",
"This does *not* create a module object but only makes a variable in our current location point to an object defined inside a module directly."
]
@ -2489,7 +2489,7 @@
}
},
"source": [
"Often times, we need a random variable, for example, when we want to build a simulation program. The [random](https://docs.python.org/3/library/random.html) module in the [standard library](https://docs.python.org/3/library/index.html) often suffices for that."
"Often, we need a random variable, for example, when we want to build a simulation program. The [random](https://docs.python.org/3/library/random.html) module in the [standard library](https://docs.python.org/3/library/index.html) often suffices for that."
]
},
{
@ -2537,7 +2537,7 @@
}
},
"source": [
"Besides the usual dunder-style attributes, the [dir()](https://docs.python.org/3/library/functions.html#dir) built-in function lists some attributes in an upper case naming convention and many others starting with a single underscore \"\\_\". To understand the former, we have to wait until Chapter 10 while the latter are explained further below."
"Besides the usual dunder-style attributes, the built-in [dir()](https://docs.python.org/3/library/functions.html#dir) function lists some attributes in an upper case naming convention and many others starting with a *single* underscore `_`. To understand the former, we must wait until Chapter 10, while the latter is explained further below."
]
},
{
@ -2697,7 +2697,7 @@
{
"data": {
"text/plain": [
"0.15268128055183228"
"0.5291407120147841"
]
},
"execution_count": 75,
@ -2717,7 +2717,7 @@
}
},
"source": [
"While we could build some conditional logic with an `if` statement to map the number generated by [random.random()](https://docs.python.org/3/library/random.html#random.random) to a finite set of elements manually, the [random.choice()](https://docs.python.org/3/library/random.html#random.choice) function provides a lot more **convenience** for us. We simply call it with, for example, the `nums` list and it draws one element out of it with equal chance."
"While we could build some conditional logic with an `if` statement to map the number generated by [random.random()](https://docs.python.org/3/library/random.html#random.random) to a finite set of elements manually, the [random.choice()](https://docs.python.org/3/library/random.html#random.choice) function provides a lot more **convenience** for us. We call it with, for example, the `nums` list and it draws one element out of it with equal chance."
]
},
{
@ -2732,7 +2732,7 @@
{
"data": {
"text/plain": [
"<bound method Random.choice of <random.Random object at 0x56111ba1cba8>>"
"<bound method Random.choice of <random.Random object at 0x5609be5deba8>>"
]
},
"execution_count": 76,
@ -2781,7 +2781,7 @@
{
"data": {
"text/plain": [
"2"
"4"
]
},
"execution_count": 78,
@ -2801,7 +2801,7 @@
}
},
"source": [
"In order to re-produce the same random numbers in a simulation each time we run it, we can set the **[random seed](https://en.wikipedia.org/wiki/Random_seed)**. It is good practice to do this at the beginning of a program or notebook. Then every time we re-start the program, we will get the exact same random numbers again. This becomes very important, for example, when we employ certain machine learning algorithms that rely on randomization, like the infamous [Random Forest](https://en.wikipedia.org/wiki/Random_forest), and want to obtain **re-producable** results.\n",
"To reproduce the same random numbers in a simulation each time we run it, we set the **[random seed](https://en.wikipedia.org/wiki/Random_seed)**. It is good practice to do this at the beginning of a program or notebook. Then every time we re-start the program, we get the *same* random numbers again. This becomes very important, for example, when we employ machine learning algorithms that rely on randomization, like the infamous [Random Forest](https://en.wikipedia.org/wiki/Random_forest), and want to obtain **reproducable** results.\n",
"\n",
"The [random](https://docs.python.org/3/library/random.html) module provides the [random.seed()](https://docs.python.org/3/library/random.html#random.seed) function to do that."
]
@ -2899,11 +2899,11 @@
}
},
"source": [
"As the Python community is based around open source, many developers publish their code, for example, on the Python Package Index [PyPI](https://pypi.org) from where anyone can download and install it for free using command line based tools like [pip](https://pip.pypa.io/en/stable/) or [conda](https://conda.io/en/latest/). This way, we can always customize our Python installation even more. Managing many such packages is actually quite a deep topic on its own, sometimes fearfully called **[dependency hell](https://en.wikipedia.org/wiki/Dependency_hell)**.\n",
"As the Python community is based around open source, many developers publish their code, for example, on the Python Package Index [PyPI](https://pypi.org) from where anyone may download and install it for free using command-line based tools like [pip](https://pip.pypa.io/en/stable/) or [conda](https://conda.io/en/latest/). This way, we can always customize our Python installation even more. Managing many such packages is quite a deep topic on its own, sometimes fearfully called **[dependency hell](https://en.wikipedia.org/wiki/Dependency_hell)**.\n",
"\n",
"The difference between the [standard library](https://docs.python.org/3/library/index.html) and such **third-party** packages is that in the first case the code goes through a much more formalized review process and is officially endorsed by the Python core developers. Yet, many third-party projects also offer the highest quality standards and a lot of such software is actually also relied on by many businesses and researchers.\n",
"The difference between the [standard library](https://docs.python.org/3/library/index.html) and such **third-party** packages is that in the first case, the code goes through a much more formalized review process and is officially endorsed by the Python core developers. Yet, many third-party projects also offer the highest quality standards and are also relied on by many businesses and researchers.\n",
"\n",
"Throughout this book, we will look at many third-party libraries, mostly from Python's [scientific stack](https://scipy.org/about.html), a tightly coupled set of third-party libraries for storing **big data** efficiently ([numpy](http://www.numpy.org/)), \"wrangling\" ([pandas](https://pandas.pydata.org/)) and visualizing them ([matplotlib](https://matplotlib.org/) and [seaborn](https://seaborn.pydata.org/)), fitting classical statistical models ([statsmodels](http://www.statsmodels.org/)), training machine learning models ([sklearn](http://scikit-learn.org/)), and much more.\n",
"Throughout this book, we will look at many third-party libraries, mostly from Python's [scientific stack](https://scipy.org/about.html), a tightly coupled set of third-party libraries for storing **big data** efficiently (e.g., [numpy](http://www.numpy.org/)), \"wrangling\" (e.g., [pandas](https://pandas.pydata.org/)) and visualizing them (e.g., [matplotlib](https://matplotlib.org/) or [seaborn](https://seaborn.pydata.org/)), fitting classical statistical models (e.g., [statsmodels](http://www.statsmodels.org/)), training machine learning models (e.g., [sklearn](http://scikit-learn.org/)), and much more.\n",
"\n",
"Below, we briefly show how to install third-party libraries."
]
@ -2927,11 +2927,11 @@
}
},
"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 will look at it in depth in Chapter 9.\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.\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.ipynb), to execute terminal commands from within a Jupyter notebook, we just need to 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_start_up.ipynb), 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, will just confirm that."
"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."
]
},
{
@ -2963,7 +2963,7 @@
}
},
"source": [
"[numpy](http://www.numpy.org/) is conventionally imported with the shorter **idiomatic** name `np`. The `as` in the import statement just changes the resulting variable name. It is a shortcut for the three lines `import numpy`, `np = numpy`, and `del numpy`."
"[numpy](http://www.numpy.org/) is conventionally imported with the shorter **idiomatic** name `np`. The `as` in the import statement changes the resulting variable name. It is a shortcut for the three lines `import numpy`, `np = numpy`, and `del numpy`."
]
},
{
@ -2987,7 +2987,7 @@
}
},
"source": [
"`np` can be used in the same way as `math` or `random` above."
"`np` is used in the same way as `math` or `random` above."
]
},
{
@ -3094,9 +3094,9 @@
}
},
"source": [
"[numpy](http://www.numpy.org/) somehow magically adds new behavior to Python's built-in arithmetic operators. For example, we can now [scalar-multiply](https://en.wikipedia.org/wiki/Scalar_multiplication) `vec`.\n",
"[numpy](http://www.numpy.org/) somehow magically adds new behavior to Python's built-in arithmetic operators. For example, we may now [scalar-multiply](https://en.wikipedia.org/wiki/Scalar_multiplication) `vec`.\n",
"\n",
"[numpy](http://www.numpy.org/)'s functions are implemented in highly optimized C code and therefore fast, especially when it comes to big data."
"[numpy](http://www.numpy.org/)'s functions are implemented in highly optimized C code and, therefore, are fast, especially when dealing with bigger amounts of data."
]
},
{
@ -3236,13 +3236,13 @@
}
},
"source": [
"For sure, we can create our own modules and packages. In the repository's main directory, there is a [*sample_module.py*](https://github.com/webartifex/intro-to-python/blob/master/sample_module.py) file that contains, among others, a function equivalent to the final version of `average_evens()`. To be realistic, this sample module is structured in a modular manner with several functions building on each other. It is best to skim over it *now* before reading on.\n",
"For sure, we can create local modules and packages. In the repository's main directory, there is a [*sample_module.py*](https://github.com/webartifex/intro-to-python/blob/master/sample_module.py) file that contains, among others, a function equivalent to the final version of `average_evens()`. To be realistic, this sample module is structured in a modular manner with several functions building on each other. It is best to skim over it *now* before reading on.\n",
"\n",
"To make code we put into a *.py* file available in our program, we import it as a module just as we did above with modules in the [standard library](https://docs.python.org/3/library/index.html) or third-party packages.\n",
"\n",
"The *name* to be imported is the file's name except for the *.py* part. In order for this to work, the file's name *must* adhere to the *same* rules as hold for [variable names](https://docs.python.org/3/reference/lexical_analysis.html#identifiers) in general.\n",
"The *name* to be imported is the file's name except for the *.py* part. For this to work, the file's name *must* adhere to the *same* rules as hold for [variable names](https://docs.python.org/3/reference/lexical_analysis.html#identifiers) in general.\n",
"\n",
"What happens during an import is conceptually as follows. When Python sees the `import sample_module` part, it first creates a *new* object of type `module` in memory. This is effectively an *empty* namespace. Then, it executes the imported file's code from top to bottom. Whatever variables are still defined at the end of this, are put into the module's namespace. Only if the file's code does *not* raise an error, will Python make a variable in our current location (i.e., `mod` here) point to the created `module` object. Otherwise, it is discarded. In essence, it is as if we copied and pasted the file's code in place of the import statement. If we import an already imported module again, Python is smart enough to avoid doing all this work all over and does nothing."
"What happens during an import is as follows. When Python sees the `import sample_module` part, it first creates a *new* object of type `module` in memory. This is effectively an *empty* namespace. Then, it executes the imported file's code from top to bottom. Whatever variables are still defined at the end of this, are put into the module's namespace. Only if the file's code does *not* raise an error, will Python make a variable in our current location (i.e., `mod` here) point to the created `module` object. Otherwise, it is discarded. In essence, it is as if we copied and pasted the file's code in place of the import statement. If we import an already imported module again, Python is smart enough to avoid doing all this work all over and does nothing."
]
},
{
@ -3292,7 +3292,7 @@
"source": [
"Disregarding the dunder-style attributes, `mod` defines the five attributes `_default_scalar`, `_scaled_average`, `average`, `average_evens`, and `average_odds`, which are exactly the ones we would expect from reading the [*sample_module.py*](https://github.com/webartifex/intro-to-python/blob/master/sample_module.py) file.\n",
"\n",
"An important convention when working with imported code is to *disregard* any attributes starting with an underscore \"\\_\". These are considered **private** and constitute **implementation details** the author of the imported code might change in a future version of his software. We *must* not rely on them in any way.\n",
"A convention when working with imported code is to *disregard* any attributes starting with an underscore `_`. These are considered **private** and constitute **implementation details** the author of the imported code might change in a future version of his software. We *must* not rely on them in any way.\n",
"\n",
"In contrast, the three remaining **public** attributes are the functions `average()`, `average_evens()`, and `average_odds()` that we may use after the import."
]
@ -3341,7 +3341,7 @@
}
},
"source": [
"We can use the imported `mod.average_evens()` just like `average_evens()` defined above. The advantage we get from **modularization** with *.py* files is that we can now easily re-use functions across different Jupyter notebooks without re-defining them again and again. Also, we can \"source out\" code that distracts from the storyline told in a notebook."
"We use the imported `mod.average_evens()` just like `average_evens()` defined above. The advantage we get from **modularization** with *.py* files is that we can now easily re-use functions across different Jupyter notebooks without re-defining them again and again. Also, we can \"source out\" code that distracts from the storyline told in a notebook."
]
},
{
@ -3433,9 +3433,9 @@
}
},
"source": [
"Packages are a generalization of modules and we will look at one in Chapter 10 in detail. You can, however, already look at a [sample package](https://github.com/webartifex/intro-to-python/tree/master/sample_package) in the repository, which is nothing but a folder with *.py* files in it.\n",
"Packages are a generalization of modules, and we look at one in detail in Chapter 10. You may, however, already look at a [sample package](https://github.com/webartifex/intro-to-python/tree/master/sample_package) in the repository, which is nothing but a folder with *.py* files in it.\n",
"\n",
"As a further references on modules, we refer to the [official tutorial](https://docs.python.org/3/tutorial/modules.html)."
"As a further reading on modules and packages, we refer to the [official tutorial](https://docs.python.org/3/tutorial/modules.html)."
]
},
{
@ -3461,14 +3461,14 @@
"\n",
"Functions provide benefits as they:\n",
"\n",
"- make programs easier to comprehend and debug for humans as they give names to the smaller parts of a larger program (i.e., they **modularize** a code base), and\n",
"- make programs easier to comprehend and debug for humans as they give names to the smaller parts of a larger program (i.e., they **modularize** a codebase), and\n",
"- eliminate redundancies by allowing **re-use of code**.\n",
"\n",
"Functions are **defined** once with the `def` statement. Then, they can be **called** many times with the call operator `()`.\n",
"Functions are **defined** once with the `def` statement. Then, they may be **called** many times with the call operator `()`.\n",
"\n",
"They may process **parameterized** inputs, **passed** in as **arguments**, and output a **return value**.\n",
"\n",
"Arguments can be passed in by **position** or **keyword**. Some functions may even require **keyword-only** arguments.\n",
"Arguments may be passed in by **position** or **keyword**. Some functions may even require **keyword-only** arguments.\n",
"\n",
"**Lambda expressions** create anonymous functions.\n",
"\n",

View file

@ -324,9 +324,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q11.5**: Using the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in, write a `for`-loop and calculate the volume of a sphere with `radius = 42.0` for all `digits` from `1` through `20`. Print out each volume on a seperate line.\n",
"**Q11.5**: Using the [range()](https://docs.python.org/3/library/functions.html#func-range) built-in, write a `for`-loop and calculate the volume of a sphere with `radius = 42.0` for all `digits` from `1` through `20`. Print out each volume on a separate line.\n",
"\n",
"Note: This is the first task where you actually need to use the [print()](https://docs.python.org/3/library/functions.html#print) built-in function."
"Note: This is the first task where you need to use the built-in [print()](https://docs.python.org/3/library/functions.html#print) function."
]
},
{
@ -349,7 +349,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q11.6**: What important lesson did you learn about the `float` type?"
"**Q11.6**: What lesson did you learn about the `float` type?"
]
},
{

View file

@ -19,9 +19,9 @@
}
},
"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.ipynb) except for the `if` part. While it seems to intuitively do what we expect it to, there is a whole lot more to be learned from taking it apart. In particular, the `if` can occur within both a **statement** as in our introductory example in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) but also an **expression** as in `average_evens()`. This is 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 versions of the `if` 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.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 and raising **exceptions**."
"After deconstructing `if` in the first part of this chapter, we take a close look at a similar concept, namely handling **exceptions**."
]
},
{
@ -43,7 +43,7 @@
}
},
"source": [
"Any expression that is either true or not is called a **boolean expression**. If you think such expressions are boring or just not so useful, read a bit on [propositional logic](https://en.wikipedia.org/wiki/Propositional_calculus) and you will quickly realize how mathematicians and originally philosophers base their rules of how to prove or disprove a conclusion on simple true-or-false \"statements\" about the world. It is the underlying principle of all of reasoning.\n",
"Any expression that is either true or not is called a **boolean expression**. It is such simple true-or-false \"statements\" about the world on which mathematicians, and originally philosophers, base their rules of reasoning: They are studied formally in the field of [propositional logic](https://en.wikipedia.org/wiki/Propositional_calculus).\n",
"\n",
"A trivial example involves the equality operator `==` that evaluates to either `True` or `False` depending on its operands \"comparing equal\" or not."
]
@ -104,7 +104,7 @@
}
},
"source": [
"Observe how `==` can handle objects of *different* type. This shows how it implements a notion of equality in line with how we humans think of things being equal or not. After all, `42` and `42.0` are totally different $0$s and $1$s for a computer and many programming languages would actually say `False` here! Technically, this is yet another example of operator overloading."
"The `==` operator handles objects of *different* types: It implements a notion of equality in line with how humans think of things being equal or not. After all, `42` and `42.0` are different $0$s and $1$s for a computer and other programming languages might say `False` here! Technically, this is yet another example of operator overloading."
]
},
{
@ -139,7 +139,7 @@
}
},
"source": [
"There are, however, cases where even well-behaved Python does not make us happy. Chapter 5 will provide more insights on 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.ipynb) provides more insights into this \"bug.\""
]
},
{
@ -174,7 +174,7 @@
}
},
"source": [
"`True` and `False` are special built-in *objects* of type `bool`."
"`True` and `False` are built-in *objects* of type `bool`."
]
},
{
@ -189,7 +189,7 @@
{
"data": {
"text/plain": [
"94163040564192"
"94906834637792"
]
},
"execution_count": 5,
@ -213,7 +213,7 @@
{
"data": {
"text/plain": [
"94163040564160"
"94906834637760"
]
},
"execution_count": 6,
@ -281,11 +281,11 @@
}
},
"source": [
"Let's not confuse the boolean `False` with `None`, another special built-in object! We saw the latter before in [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb) 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.ipynb) 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 will see further below!\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",
"Whereas `False` is of type `bool`, `None` is of type `NoneType`. So, they are totally unrelated. On the contrary, as both `True` and `False` are of the same type, we could call them \"siblings\"."
"Whereas `False` is of type `bool`, `None` is of type `NoneType`. So, they are unrelated. On the contrary, as both `True` and `False` are of the same type, we could call them \"siblings.\""
]
},
{
@ -313,7 +313,7 @@
{
"data": {
"text/plain": [
"94163040551152"
"94906834624752"
]
},
"execution_count": 10,
@ -357,9 +357,9 @@
}
},
"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 will *not* mutate its value (i.e., to re-use the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb), 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 already 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 re-use the bag analogy from [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb), 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 can verify this with either the `is` operator or by comparing memory addresses."
"We verify this with either the `is` operator or by comparing memory addresses."
]
},
{
@ -523,7 +523,7 @@
}
},
"source": [
"The \"less than\" `<` or \"greater than\" `>` operators on their own mean \"strictly less than\" or \"strictly greater than\" but can be combined with the equality operator into just `<=` and `>=`. This is a shortcut for using the logical `or` operator as described in the next section."
"The \"less than\" `<` or \"greater than\" `>` operators mean \"strictly less than\" or \"strictly greater than\" but may be combined with the equality operator into just `<=` and `>=`. This is a shortcut for using the logical `or` operator as described in the next section."
]
},
{
@ -641,9 +641,9 @@
}
},
"source": [
"Boolean expressions can be combined or negated with the **logical operators** `and`, `or`, and `not` to form new boolean expressions. Of course, this may be done *recursively* as well to obtain boolean expressions of arbitrary complexity.\n",
"Boolean expressions may be combined or negated with the **logical operators** `and`, `or`, and `not` to form new boolean expressions. Of course, this may be done *recursively* as well to obtain boolean expressions of arbitrary complexity.\n",
"\n",
"Their usage is similar to how the equivalent words are used in plain English:\n",
"Their usage is similar to how the equivalent words are used in everyday English:\n",
"\n",
"- `and` evaluates to `True` if *both* sub-expressions evaluate to `True` and `False` otherwise,\n",
"- `or` evaluates to `True` if either one *or* both sub-expressions evaluate to `True` and `False` otherwise, and\n",
@ -672,7 +672,7 @@
}
},
"source": [
"Relational operators have a **[higher precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence)** over logical operators. So the following expression means what we intuitively think it does."
"Relational operators have **[higher precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence)** over logical operators. So the following expression means what we intuitively think it does."
]
},
{
@ -707,7 +707,7 @@
}
},
"source": [
"However, sometimes it is good to use *parentheses* around each sub-expression for clarity."
"However, sometimes, it is good to use *parentheses* around each sub-expression for clarity."
]
},
{
@ -742,7 +742,7 @@
}
},
"source": [
"This is especially useful when several logical operators are combined."
"This is especially the case when several logical operators are combined."
]
},
{
@ -825,9 +825,9 @@
}
},
"source": [
"For even better readability, [some practitioners](https://llewellynfalco.blogspot.com/2016/02/dont-use-greater-than-sign-in.html) suggest to *never* use the `>` and `>=` operators (note that the included example is written in [Java](https://en.wikipedia.org/wiki/Java_%28programming_language%29) and `&&` means `and` and `||` means `or`).\n",
"For even better readability, some practitioners suggest to *never* use the `>` and `>=` operators (cf., [source](https://llewellynfalco.blogspot.com/2016/02/dont-use-greater-than-sign-in.html); note that the included example is written in [Java](https://en.wikipedia.org/wiki/Java_%28programming_language%29) where `&&` means `and` and `||` means `or`).\n",
"\n",
"Python allows **chaining** relational operators that are combined with the `and` operator. For example, the following two cells implement the same logic where the second is a lot easier to read."
"Python allows **chaining** relational operators that are combined with the `and` operator. For example, the following two cells implement the same logic, where the second is a lot easier to read."
]
},
{
@ -897,9 +897,9 @@
}
},
"source": [
"The operands of the logical operators do not actually have to be *boolean* expressions as defined above but may be *any* kind of expression. If a sub-expression does *not* evaluate to an object of type `bool`, Python automatically casts the resulting object as such.\n",
"The operands of the logical operators do not need to be *boolean* expressions as defined above but may be *any* expression. If a sub-expression does *not* evaluate to an object of type `bool`, Python automatically casts it as such.\n",
"\n",
"For example, any non-zero numeric object becomes `True`. While this behavior allows writing conciser and thus more \"beautiful\" code, it is also a common source of confusion."
"For example, any non-zero numeric object becomes `True`. While this behavior allows writing more concise and thus more \"beautiful\" code, it is also a common source of confusion. `(x - 9)` is cast as `True` and then the overall expression evaluates to `True` as well."
]
},
{
@ -923,7 +923,7 @@
}
],
"source": [
"(x - 9) and (y < 100) # = 33 and (y < 100)"
"(x - 9) and (y < 100) # = 33 and (y < 100) = 33 and True"
]
},
{
@ -934,7 +934,7 @@
}
},
"source": [
"Whenever we are unsure as to how Python will evaluate a non-boolean expression in a boolean context, the [bool()](https://docs.python.org/3/library/functions.html#bool) built-in allows us to check it ourselves."
"Whenever we are unsure as to how Python evaluates a non-boolean expression in a boolean context, the [bool()](https://docs.python.org/3/library/functions.html#bool) built-in allows us to check it ourselves."
]
},
{
@ -1028,7 +1028,7 @@
}
},
"source": [
"In a boolean context, `None` is casted as `False`! So, `None` is really *not* a \"maybe\" answer but a \"no\"."
"In a boolean context, `None` is cast as `False`! So, `None` is *not* a \"maybe\" answer but a \"no.\""
]
},
{
@ -1063,7 +1063,7 @@
}
},
"source": [
"Another good rule to know is that container types (e.g., `list`) evaluate to `True` whenever they are not empty and `False` otherwise."
"Another good rule to know is that container types (e.g., `list`) evaluate to `True` whenever they are *not* empty and `False` if they are."
]
},
{
@ -1133,7 +1133,7 @@
}
},
"source": [
"## Conditional Statements"
"### Short-Circuiting"
]
},
{
@ -1144,24 +1144,406 @@
}
},
"source": [
"In order to write useful programs, we need to control the flow of execution, for example, to react to user input. The logic by which a program does that is referred to as **business logic**.\n",
"When evaluating boolean expressions with logical operators in it, Python follows the **[short-circuiting](https://en.wikipedia.org/wiki/Short-circuit_evaluation)** strategy: First, the inner-most sub-expressions are evaluated. Second, with identical **[operator precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence)**, evaluation goes from left to right. Once it is clear what the overall truth value is, no more sub-expressions are evaluated, and the result is *immediately* returned.\n",
"\n",
"One major language construct to do so is the **[conditional statement](https://docs.python.org/3/reference/compound_stmts.html#the-if-statement)** or `if` statement. It consists of:\n",
"In summary, data science practitioners must know *how* the following two generic expressions are evaluated:\n",
"\n",
"- `x or y`: The `y` expression is evaluated *only if* `x` evaluates to `False`, in which case `y` is returned; otherwise, `x` is returned *without* even looking at `y`.\n",
"- `x and y`: The `y` expression is evaluated *only if* `x` evaluates to `True`. Then, if `y` also evaluates to `True`, it is returned; otherwise, `x` is returned.\n",
"\n",
"Let's look at a couple of examples."
]
},
{
"cell_type": "code",
"execution_count": 36,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [],
"source": [
"x = 0\n",
"y = 1\n",
"z = 2"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"We define a helper function `expr()` that prints out the only argument it is passed before returning it. With `expr()`, we can see if a sub-expression is evaluated or not."
]
},
{
"cell_type": "code",
"execution_count": 37,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [],
"source": [
"def expr(arg):\n",
" \"\"\"Print and return the only argument.\"\"\"\n",
" print(\"Arg:\", arg)\n",
" return arg"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"With the `or` operator, the first sub-expression that evaluates to `True` is returned."
]
},
{
"cell_type": "code",
"execution_count": 38,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 0\n",
"Arg: 1\n"
]
},
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 38,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(x) or expr(y)"
]
},
{
"cell_type": "code",
"execution_count": 39,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 1\n"
]
},
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 39,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(y) or expr(z)"
]
},
{
"cell_type": "code",
"execution_count": 40,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 0\n",
"Arg: 1\n"
]
},
{
"data": {
"text/plain": [
"1"
]
},
"execution_count": 40,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(x) or expr(y) or expr(z)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"If all sub-expressions evaluate to `False`, the last one is the result."
]
},
{
"cell_type": "code",
"execution_count": 41,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: False\n",
"Arg: []\n",
"Arg: 0\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 41,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(False) or expr([]) or expr(x)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"With the `and` operator, the first sub-expression that evaluates to `False` is returned."
]
},
{
"cell_type": "code",
"execution_count": 42,
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 0\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 42,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(x) and expr(y)"
]
},
{
"cell_type": "code",
"execution_count": 43,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 1\n",
"Arg: 0\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 43,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(y) and expr(x)"
]
},
{
"cell_type": "code",
"execution_count": 44,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 2\n",
"Arg: 1\n",
"Arg: 0\n"
]
},
{
"data": {
"text/plain": [
"0"
]
},
"execution_count": 44,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(z) and expr(y) and expr(x)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"If all sub-expressions evaluate to `True`, the last one is returned."
]
},
{
"cell_type": "code",
"execution_count": 45,
"metadata": {
"slideshow": {
"slide_type": "fragment"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Arg: 1\n",
"Arg: 2\n"
]
},
{
"data": {
"text/plain": [
"2"
]
},
"execution_count": 45,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"expr(y) and expr(z)"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"The crucial takeaway is that Python does *not* necessarily evaluate *all* sub-expressions and, therefore, our code should never rely on that assumption."
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "slide"
}
},
"source": [
"## The `if` Statement"
]
},
{
"cell_type": "markdown",
"metadata": {
"slideshow": {
"slide_type": "skip"
}
},
"source": [
"To write useful programs, we need to control the flow of execution, for example, to react to user input. The logic by which a program does that is referred to as **business logic**.\n",
"\n",
"One language construct to do so is the **[conditional statement](https://docs.python.org/3/reference/compound_stmts.html#the-if-statement)**, or `if` statement for short. It consists of:\n",
"\n",
"- *one* mandatory `if`-clause,\n",
"- an *arbitrary* number of `elif`-clauses (i.e. \"else if\"), and\n",
"- an *optional* `else`-clause.\n",
"\n",
"The `if`- and `elif`-clauses each specify one *boolean* expression, also called **condition**, while the `else`-clause serves as a \"catch everything else\" case.\n",
"The `if`- and `elif`-clauses each specify one *boolean* expression, also called **condition**, while the `else`-clause serves as the \"catch everything else\" case.\n",
"\n",
"In terms of syntax, the header lines end with a colon and the code blocks are indented.\n",
"In terms of syntax, the header lines end with a colon, and the code blocks are indented.\n",
"\n",
"In contrast to our intuitive interpretation in natural languages, only the code in *one* of the alternatives, also called **branches**, is executed. To be precise, it is always the code in the first branch whose condition evaluates to `True`."
]
},
{
"cell_type": "code",
"execution_count": 36,
"execution_count": 46,
"metadata": {
"code_folding": [],
"slideshow": {
@ -1175,7 +1557,7 @@
},
{
"cell_type": "code",
"execution_count": 37,
"execution_count": 47,
"metadata": {
"code_folding": [],
"slideshow": {
@ -1212,12 +1594,12 @@
"source": [
"In many situations, we only need a reduced form of the `if` statement.\n",
"\n",
"We could **inject** code only at random to, for example, implement some sort of [A/B testing](https://en.wikipedia.org/wiki/A/B_testing)."
"We could **inject** code only at random, for example, to implement an [A/B testing](https://en.wikipedia.org/wiki/A/B_testing) strategy."
]
},
{
"cell_type": "code",
"execution_count": 38,
"execution_count": 48,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1230,24 +1612,16 @@
},
{
"cell_type": "code",
"execution_count": 39,
"execution_count": 49,
"metadata": {
"slideshow": {
"slide_type": "-"
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"You will read this just as often as you see heads when tossing a coin\n"
]
}
],
"outputs": [],
"source": [
"if random.random() > 0.5:\n",
" print(\"You will read this just as often as you see heads when tossing a coin\")"
" print(\"You read this just as often as you see heads when tossing a coin\")"
]
},
{
@ -1258,12 +1632,12 @@
}
},
"source": [
"More often than not, we might model a binary choice."
"More often than not, we model a **binary choice**."
]
},
{
"cell_type": "code",
"execution_count": 40,
"execution_count": 50,
"metadata": {
"slideshow": {
"slide_type": "skip"
@ -1293,12 +1667,14 @@
}
},
"source": [
"We may **nest** `if` statements to control the flow of execution in a more granular way. Every additional layer, however, makes the code less readable, in particular, if we have more than one line per code block."
"We may **nest** `if` statements to control the flow of execution in a more granular way. Every additional layer, however, makes the code *less* readable, in particular, if we have more than one line per code block.\n",
"\n",
"The code cell below *either* checks if a number is even or odd *or* if it is positive or negative."
]
},
{
"cell_type": "code",
"execution_count": 41,
"execution_count": 51,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1309,7 +1685,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"z is odd\n"
"z is positive\n"
]
}
],
@ -1334,12 +1710,14 @@
}
},
"source": [
"A good way to make this code more readable is to introduce **temporary variables** *in combination* with using the `and` operator to **flatten** the branching logic. The `if` statement then reads almost like plain English. In contrast to many other languages, creating variables is a computationally *cheap* operation in Python and also helps to document the code *inline*. Without temporary variables, the `and` flattening could actually lead to more sub-expressions in the conditions be evaluated than necessary. Do you see why?"
"A way to make this code more readable is to introduce **temporary variables** *in combination* with the `and` operator to **flatten** the branching logic. The `if` statement then reads almost like plain English. In contrast to many other languages, creating variables is a computationally *cheap* operation in Python and also helps to document the code *inline* with meaningful variable names.\n",
"\n",
"Flattening the logic *without* temporary variables could lead to *more* sub-expressions in the conditions be evaluated than necessary. Do you see why?"
]
},
{
"cell_type": "code",
"execution_count": 42,
"execution_count": 52,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1377,7 +1755,7 @@
}
},
"source": [
"## Conditional Expressions"
"## The `if` Expression"
]
},
{
@ -1388,7 +1766,7 @@
}
},
"source": [
"When all we do with an `if` statement is to assign an object to a variable with respect to a single true-or-false condition (cf., binary choice above), there is a shortcut for that: We could simply assign the result of a so-called **conditional expression** or `if` expression to the variable.\n",
"When all we do with an `if` statement is to assign an object to a variable according to a single true-or-false condition (i.e., a binary choice), there is a shortcut: We assign the variable the result of a so-called **conditional expression**, or `if` expression for short, instead.\n",
"\n",
"Think of a situation where we evaluate a piece-wise functional relationship $y = f(x)$ at a given $x$, for example:"
]
@ -1412,7 +1790,7 @@
},
{
"cell_type": "code",
"execution_count": 43,
"execution_count": 53,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1436,7 +1814,7 @@
},
{
"cell_type": "code",
"execution_count": 44,
"execution_count": 54,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -1452,7 +1830,7 @@
},
{
"cell_type": "code",
"execution_count": 45,
"execution_count": 55,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -1465,7 +1843,7 @@
"9"
]
},
"execution_count": 45,
"execution_count": 55,
"metadata": {},
"output_type": "execute_result"
}
@ -1487,7 +1865,7 @@
},
{
"cell_type": "code",
"execution_count": 46,
"execution_count": 56,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -1500,7 +1878,7 @@
},
{
"cell_type": "code",
"execution_count": 47,
"execution_count": 57,
"metadata": {
"slideshow": {
"slide_type": "skip"
@ -1513,7 +1891,7 @@
"9"
]
},
"execution_count": 47,
"execution_count": 57,
"metadata": {},
"output_type": "execute_result"
}
@ -1530,12 +1908,12 @@
}
},
"source": [
"In this concrete example, however, the most elegant solution would be to use the built-in [max()](https://docs.python.org/3/library/functions.html#max) function."
"In this example, however, the most elegant solution would be to use the built-in [max()](https://docs.python.org/3/library/functions.html#max) function."
]
},
{
"cell_type": "code",
"execution_count": 48,
"execution_count": 58,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -1548,7 +1926,7 @@
},
{
"cell_type": "code",
"execution_count": 49,
"execution_count": 59,
"metadata": {
"slideshow": {
"slide_type": "skip"
@ -1561,7 +1939,7 @@
"9"
]
},
"execution_count": 49,
"execution_count": 59,
"metadata": {},
"output_type": "execute_result"
}
@ -1578,7 +1956,7 @@
}
},
"source": [
"Conditional expressions may not only be used in the way described in this section. We already saw them as part of a list comprehension that is introduced in Chapter 7."
"Conditional expressions may not only be used in the way described in this section. We already saw them as part of a *list comprehension* in [Chapter 1](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/01_elements.ipynb) and [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb) and revisit this in Chapter 7 in greater detail."
]
},
{
@ -1589,7 +1967,7 @@
}
},
"source": [
"## Exceptions"
"## The `try` Statement"
]
},
{
@ -1600,16 +1978,16 @@
}
},
"source": [
"In the previous two chapters we already encountered a couple of *runtime* errors. A natural urge we might have after reading about conditional statements is to write code that somehow reacts to the occurence of such exceptions. All we need for that is a way to formulate a condition for that.\n",
"In the previous two chapters, we encountered a couple of *runtime* errors. A natural urge we might have after reading about conditional statements is to write code that somehow reacts to the occurrence of such exceptions. All we need is a way to formulate a condition for that.\n",
"\n",
"For sure, this is such a common thing to do that Python provides its own language construct for it, namely the `try` [statement](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement).\n",
"For sure, this is such a common thing to do that Python provides a language construct for it, namely the `try` [statement](https://docs.python.org/3/reference/compound_stmts.html#the-try-statement).\n",
"\n",
"In its simplest form, it comes with just two branches: `try` and `except`. The following basically tells Python to execute the code in the `try`-branch and if *anything* goes wrong, continue in the `except`-branch instead of **raising** an error to us. Of course, if nothing goes wrong, the `except`-branch is *not* executed."
"In its simplest form, it comes with just two branches: `try` and `except`. The following tells Python to execute the code in the `try`-branch, and if *anything* goes wrong, continue in the `except`-branch instead of **raising** an error to us. Of course, if nothing goes wrong, the `except`-branch is *not* executed."
]
},
{
"cell_type": "code",
"execution_count": 50,
"execution_count": 60,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1622,7 +2000,7 @@
},
{
"cell_type": "code",
"execution_count": 51,
"execution_count": 61,
"metadata": {
"slideshow": {
"slide_type": "-"
@ -1652,16 +2030,16 @@
}
},
"source": [
"However, it is good practise to *not* **handle** *any* possible exception but only the ones we may expect from the code in the `try`-branch. The reasoning why this is done is a bit involved. We only remark here that the code base becomes easier to understand as we clearly communicate to any human reader what could go wrong during execution. Python comes with a lot of [built-in exceptions](https://docs.python.org/3/library/exceptions.html#concrete-exceptions) that we should familiarize ourselves with.\n",
"However, it is good practice *not* to **handle** *any* possible exception but only the ones we may *expect* from the code in the `try`-branch. The reasoning why this is done is a bit involved. We only remark that the codebase becomes easier to understand as we communicate to any human reader what could go wrong during execution in an *explicit* way. Python comes with a lot of [built-in exceptions](https://docs.python.org/3/library/exceptions.html#concrete-exceptions) that we should familiarize ourselves with.\n",
"\n",
"Another good practise is to always keep the code in the `try`-branch short so as to not accidently handle an exception we do not want to handle.\n",
"Another good practice is to always keep the code in the `try`-branch short to not *accidentally* handle an exception we do *not* want to handle.\n",
"\n",
"In the example, we are dividing numbers and may therefore expect a `ZeroDivisionError`."
"In the example, we are dividing numbers and may expect a `ZeroDivisionError`."
]
},
{
"cell_type": "code",
"execution_count": 52,
"execution_count": 62,
"metadata": {
"slideshow": {
"slide_type": "fragment"
@ -1691,16 +2069,16 @@
}
},
"source": [
"Often, we must have some code run independent of an exception occuring (e.g., to close a connection to a database). To achieve that, we can add an optional `finally`-branch to the `try` statement.\n",
"Often, we may have to run some code *independent* of an exception occurring, for example, to close a connection to a database. To achieve that, we add a `finally`-branch to the `try` statement.\n",
"\n",
"Similarly, we might have some code that must be run exactly when no exception occurs but we do not want to put it in the `try`-branch as per the good practice mentioned. To achieve that, we can add an optional `else`-branch to the `try` statement.\n",
"Similarly, we may have to run some code *only if* no exception occurs, but we do not want to put it in the `try`-branch as per the good practice mentioned above. To achieve that, we add an `else`-branch to the `try` statement.\n",
"\n",
"To showcase everything together, we look at one last example. To spice it up a bit, we randomize the input. So run the cell several times and see for yourself. It's actually quite easy."
"To showcase everything together, we look at one last example. To spice it up a bit, we randomize the input. So run the cell several times and see for yourself."
]
},
{
"cell_type": "code",
"execution_count": 53,
"execution_count": 63,
"metadata": {
"slideshow": {
"slide_type": "slide"
@ -1711,7 +2089,7 @@
"name": "stdout",
"output_type": "stream",
"text": [
"Oops. Division by 0. How does that work?\n",
"Yes, division worked smoothly.\n",
"I am always printed\n"
]
}
@ -1751,9 +2129,9 @@
"- **boolean expressions** evaluate to either `True` or `False`\n",
"- **relational operators** compare operands according to \"human\" interpretations\n",
"- **logical operators** combine boolean sub-expressions to more \"complex\" expressions\n",
"- the **conditional statement** is a *major* concept to **control** the **flow of execution** depending on some **conditions**\n",
"- the **conditional statement** allows **controlling** the **flow of execution** depending on some **conditions**\n",
"- a **conditional expression** is a short form of a conditional statement\n",
"- **exception handling** is also a common way of **controlling** the **flow of execution**, in particular if we have to be prepared for bad input data"
"- **exception handling** is also a common way of **controlling** the **flow of execution**, in particular, if we have to be prepared for bad input data"
]
}
],

View file

@ -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.ipynb) of the book. Then work through the seven review questions."
"Read [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb) of the book. Then work through the eight review questions."
]
},
{
@ -68,7 +68,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q3**: Explain how the conceptual difference between a **statement** and an **expression** relates to the difference between a **conditional statement** and a **conditional expression**."
"**Q3**: Describe in your own words the concept of **short-circuiting**! What does it imply for an individual sub-expression in a boolean expression?"
]
},
{
@ -82,7 +82,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q4**: Why is the use of **temporary variables** encouraged in Python?"
"**Q4**: Explain how the conceptual difference between a **statement** and an **expression** relates to the difference between a **conditional statement** and a **conditional expression**."
]
},
{
@ -96,7 +96,21 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q5**: What does the `finally`-branch enforce in this code snippet? How can a `try` statement be useful *without* an `except`-branch?"
"**Q5**: Why is the use of **temporary variables** encouraged in Python?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q6**: What does the `finally`-branch enforce in this code snippet? How can a `try` statement be useful *without* an `except`-branch?"
]
},
{
@ -136,7 +150,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q6**: The objects `True`, `False`, and `None` represent the idea of \"yes\", \"no\", and \"maybe\" answers in a natural language.\n",
"**Q7**: The objects `True`, `False`, and `None` represent the idea of *yes*, *no*, and *maybe* answers in a natural language.\n",
"\n",
"Hint: you also respond with a code cell."
]
@ -152,7 +166,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q7**: The `try` statement is useful for handling **syntax** errors."
"**Q8**: The `try` statement is useful for handling **syntax** errors."
]
},
{
@ -180,7 +194,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q8.1**: Write a function `discounted_price()` that takes the positional arguments `unit_price` (of type `float`) and `quantity` (of type `int`) and implements a discount scheme for a line item in a customer order as follows:\n",
"**Q9.1**: Write a function `discounted_price()` that takes the positional arguments `unit_price` (of type `float`) and `quantity` (of type `int`) and implements a discount scheme for a line item in a customer order as follows:\n",
"\n",
"- if the unit price is over 100 dollars, grant 10% relative discount\n",
"- if a customer orders more than 10 items, one in every five items is for free\n",
@ -218,7 +232,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q8.2**: Calculate the final price for the following line items of an order:\n",
"**Q9.2**: Calculate the final price for the following line items of an order:\n",
"- $7$ smartphones @ $99.00$ USD\n",
"- $3$ workstations @ $999.00$ USD\n",
"- $19$ GPUs @ $879.95$ USD\n",
@ -265,7 +279,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q8.3**: Re-calculate the last two line items with order quantities of $20$ and $15$. What do you observe?"
"**Q9.3**: Re-calculate the last two line items with order quantities of $20$ and $15$. What do you observe?"
]
},
{
@ -297,7 +311,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q8.4**: Looking at the `if`-`else`-logic in the function, why do you think the four example line items in **Q8.2** were chosen as they were?"
"**Q9.4**: Looking at the `if`-`else`-logic in the function, why do you think the four example line items in **Q9.2** were chosen as they were?"
]
},
{
@ -318,16 +332,16 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The kids game [Fizz Buzz](https://en.wikipedia.org/wiki/Fizz_buzz) is said to be often used in job interviews for entry level positions. However, opinions vary as to how good of a test it actually is ([source](https://news.ycombinator.com/item?id=16446774)).\n",
"The kids game [Fizz Buzz](https://en.wikipedia.org/wiki/Fizz_buzz) is said to be often used in job interviews for entry-level positions. However, opinions vary as to how good of a test it is (cf., [source](https://news.ycombinator.com/item?id=16446774)).\n",
"\n",
"In its simplest form, a group of people start counting upwards in an alternating fashion. Whenever a number is divisible by $3$, the person must say \"Fizz\" instead of the number. The same holds for numbers divisible by $5$ when the person must say \"Buzz\". If a number is divisible by both numbers, one must say \"FizzBuzz\". Probably, this game would also make a good drinking game with the \"right\" beverages."
"In its simplest form, a group of people starts counting upwards in an alternating fashion. Whenever a number is divisible by $3$, the person must say \"Fizz\" instead of the number. The same holds for numbers divisible by $5$ when the person must say \"Buzz.\" If a number is divisible by both numbers, one must say \"FizzBuzz.\" Probably, this game would also make a good drinking game with the \"right\" beverages."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q9.1**: First, create a list `numbers` with the numbers from 1 through 100. You could type all numbers manually but there is of course a smarter way. The built-in [range()](https://docs.python.org/3/library/functions.html#func-range) may be useful here. Read how it works in the documentation. To make the output of [range()](https://docs.python.org/3/library/functions.html#func-range) a `list` object, you have to wrap it with the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in (i.e., `list(range(...))`)."
"**Q10.1**: First, create a list `numbers` with the numbers from 1 through 100. You could type all numbers manually, but there is, of course, a smarter way. The built-in [range()](https://docs.python.org/3/library/functions.html#func-range) may be useful here. Read how it works in the documentation. To make the output of [range()](https://docs.python.org/3/library/functions.html#func-range) a `list` object, you have to wrap it with the [list()](https://docs.python.org/3/library/functions.html#func-list) built-in (i.e., `list(range(...))`)."
]
},
{
@ -343,11 +357,11 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q9.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",
"**Q10.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 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.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 checking the actual `number` for its divisors.\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",
"Hint: the order of the conditions is important!"
]
@ -372,7 +386,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q9.3**: Create a loop that prints out either the number or any of the Fizz Buzz substitutes. Do it in such a way that we do not end up with 100 lines of output here."
"**Q10.3**: Create a loop that prints out either the number or any of the Fizz Buzz substitutes. Do it in such a way that we do not end up with 100 lines of output here."
]
},
{

File diff suppressed because it is too large Load diff

View file

@ -54,7 +54,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q2**: Solving a problem with a **recursion** is not only popular in computer science and math. Name some examples from the fields of business or economics where problems are also solved in a **backwards** fashion!"
"**Q2**: Solving a problem by **recursion** is not only popular in computer science and math. Name some examples from the fields of business or economics where problems are also solved in a **backward** fashion!"
]
},
{
@ -68,7 +68,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q3**: Explain what **duck typing** means! Why can it cause problems? Why it is [not a bug but a feature](https://www.urbandictionary.com/define.php?term=It%27s%20not%20a%20bug%2C%20it%27s%20a%20feature)?"
"**Q3**: Explain what **duck typing** means! Why can it cause problems? Why is it [not a bug but a feature](https://www.urbandictionary.com/define.php?term=It%27s%20not%20a%20bug%2C%20it%27s%20a%20feature)?"
]
},
{
@ -208,7 +208,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q12**: Whereas a **recursion** may accidently result in a **never ending** program, `while`-loops and `for`-loops are guaranteed to **terminate**."
"**Q12**: Whereas a **recursion** may accidentally result in a **never-ending** program, `while`-loops and `for`-loops are guaranteed to **terminate**."
]
},
{
@ -275,7 +275,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"A popular example for a problem that is solved with a recursion art the **[Towers of Hanoi](https://en.wikipedia.org/wiki/Tower_of_Hanoi)**.\n",
"A popular example of a problem that is solved by recursion art the **[Towers of Hanoi](https://en.wikipedia.org/wiki/Tower_of_Hanoi)**.\n",
"\n",
"In its basic version, a tower consisting of, for example, four disks with increasing radii, is placed on the left-most of **three** adjacent spots. In the following, we refer to the number of disks as $n$, so here $n = 4$.\n",
"\n",
@ -304,9 +304,9 @@
"source": [
"Watch the following video by [MIT](https://www.mit.edu/)'s professor [Richard Larson](https://idss.mit.edu/staff/richard-larson/) for a comprehensive introduction.\n",
"\n",
"The [MIT Blossoms Initative](https://blossoms.mit.edu/) is primarily aimed at high school students and does not have any prerequisites.\n",
"The [MIT Blossoms Initiative](https://blossoms.mit.edu/) is primarily aimed at high school students and does not have any prerequisites.\n",
"\n",
"The video consists of three segments the last of which is *not* necessary to have watched in order to solve the tasks below. So, watch the video until 37:55."
"The video consists of three segments, the last of which is *not* necessary to have watched to solve the tasks below. So, watch the video until 37:55."
]
},
{
@ -393,7 +393,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"As most likely the first couple of tries will result in *semantic* errors, it is advisable to have some sort of **visualization tool** for the progam's output: For example, an online version of the game can be found **[here](https://www.mathsisfun.com/games/towerofhanoi.html)**."
"As most likely the first couple of tries will result in *semantic* errors, it is advisable to have some sort of **visualization tool** for the program's output: For example, an online version of the game can be found **[here](https://www.mathsisfun.com/games/towerofhanoi.html)**."
]
},
{
@ -402,7 +402,7 @@
"source": [
"Let's first **generalize** the mathematical relationship from above.\n",
"\n",
"While the first number of $Sol(\\cdot)$ is the number of `disks` $n$, the second and third \"numbers\" are actually the **labels** for the three spots. Instead of spots `1`, `2`, and `3` we could also call them `\"left\"`, `\"center\"`, and `\"right\"` in our Python implementation. When \"passed\" to the $Sol(\\cdot)$ \"function\" they take on the role of an `origin` (= $o$) and `destination` (= $d$) pair.\n",
"While the first number of $Sol(\\cdot)$ is the number of `disks` $n$, the second and third \"numbers\" are the **labels** for the three spots. Instead of spots `1`, `2`, and `3`, we could also call them `\"left\"`, `\"center\"`, and `\"right\"` in our Python implementation. When \"passed\" to the $Sol(\\cdot)$ \"function\" they take on the role of an `origin` (= $o$) and `destination` (= $d$) pair.\n",
"\n",
"So, the expression $Sol(4, 1, 3)$ is the same as $Sol(4, \\text{\"left\"}, \\text{\"right\"})$ and describes the problem of moving a tower consisting of $n = 4$ disks from `origin` `1` / `\"left\"` to `destination` `3` / `right`. As we have seen in the video, we need some `intermediate` (= $i$) spot."
]
@ -420,9 +420,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"In words, this means that in order to move a tower consisting of $n$ disks from an `origin` $o$ to a `destination` $d$, we three steps must be executed:\n",
"In words, this means that to move a tower consisting of $n$ disks from an `origin` $o$ to a `destination` $d$, three steps must be executed:\n",
"\n",
"1. Move the top most $n - 1$ disks of the tower temporarily from $o$ to $i$ (= sub-problem 1)\n",
"1. Move the topmost $n - 1$ disks of the tower temporarily from $o$ to $i$ (= sub-problem 1)\n",
"2. Move the remaining and largest disk from $o$ to $d$\n",
"3. Move the the $n - 1$ disks from the temporary spot $i$ to $d$ (= sub-problem 2)\n",
"\n",
@ -435,9 +435,9 @@
"source": [
"$Sol(\\cdot)$ can be written in Python as a function `sol()` that takes three arguments `disks`, `origin`, and `destination` that mirror $n$, $o$, and $d$.\n",
"\n",
"Assume that all arguments to `sol()` will be `int` objects!\n",
"Assume that all arguments to `sol()` are `int` objects!\n",
"\n",
"Once completed, `sol()` should print out all the moves in the correct order. With **printing a move**, we simply mean a line like \"1 -> 3\", short for \"Move the top-most disk from spot 1 to spot 3\".\n",
"Once completed, `sol()` should print out all the moves in the correct order. With **printing a move**, we mean a line like \"1 -> 3\", short for \"Move the top-most disk from spot 1 to spot 3\".\n",
"\n",
"Write your answers to **Q15.5** to **Q15.7** into the subsequent code cell and finalize `sol()`! No need to write a docstring or validate the input here."
]
@ -550,9 +550,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The previous `sol()` implementation does the job but the conditional statement needed in unnecessarily tedious. \n",
"The previous `sol()` implementation does the job, but the conditional statement needed in unnecessarily tedious. \n",
"\n",
"Let's create a more concise `hanoi()` function that in addition to a positional `disks` argument takes three keyword-only arguments `origin`, `intermediate`, and `destination` with default values `\"left\"`, `\"center\"`, and `\"right\"`.\n",
"Let's create a more concise `hanoi()` function that, in addition to a positional `disks` argument, takes three keyword-only arguments `origin`, `intermediate`, and `destination` with default values `\"left\"`, `\"center\"`, and `\"right\"`.\n",
"\n",
"Write your answers to **Q15.9** and **Q15.10** into the subsequent code cell and finalize `hanoi()`! No need to write a docstring or validate the input here."
]
@ -577,7 +577,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q15.9**: Copy the base case from `sol()`."
"**Q15.9**: Copy the base case from `sol()`!"
]
},
{
@ -588,7 +588,7 @@
"\n",
"Figure out how the arguments are passed on in the two recursive `hanoi()` calls!\n",
"\n",
"Also, write a `print()` statement analogous to the one in `sol()` in between the two recursive function calls. Is it ok to just copy and paste it?"
"Also, write a `print()` statement analogous to the one in `sol()` in between the two recursive function calls. Is it ok to copy and paste it?"
]
},
{
@ -638,7 +638,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"We could of course also use **numeric labels** for the three steps like so."
"We could, of course, also use **numeric labels** for the three steps like so."
]
},
{
@ -661,13 +661,13 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Let's say, we did not know about the **analytical formula** for the number of **minimal moves** given $n$.\n",
"Let's say we did not know about the **analytical formula** for the number of **minimal moves** given $n$.\n",
"\n",
"In such cases, we could modify a recursive function to return a count value to be passed up the recursion tree.\n",
"\n",
"In fact, 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.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.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",
"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",
"Write your answers to **Q15.12** to **Q15.14** into the subsequent code cell and finalize `hanoi_moves()`! No need to write a docstring or validate the input here."
]
@ -742,7 +742,7 @@
"source": [
"Observe how quickly the `hanoi_moves()` function slows down for increasing `disks` arguments.\n",
"\n",
"With `disks` in the range from `24` through `26` the computation time roughly doubles for each increase of `disks` by 1.\n",
"With `disks` in the range from `24` through `26`, the computation time roughly doubles for each increase of `disks` by 1.\n",
"\n",
"**Q15.16**: Execute the code cells below and see for yourself!"
]
@ -788,7 +788,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"The above `hanoi()` prints the optimal solution's moves in the correct order but fails to label each move with an order number. This can be build in by passing on one more argument `offset` down the recursion tree. As the logic gets a bit \"involved\", `hanoi_ordered()` below is almost finished.\n",
"The above `hanoi()` prints the optimal solution's moves in the correct order but fails to label each move with an order number. This can be built in by passing on one more argument `offset` down the recursion tree. As the logic gets a bit \"involved,\" `hanoi_ordered()` below is almost finished.\n",
"\n",
"Write your answers to **Q15.17** and **Q15.18** into the subsequent code cell and finalize `hanoi_ordered()`! No need to write a docstring or validate the input here."
]
@ -879,7 +879,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"Lastly, it is to be mentioned that for problem instances with a small `disks` argument it is easier to collect all the moves first in a list and then add the order number with the [enumerate()](https://docs.python.org/3/library/functions.html#enumerate) built-in."
"Lastly, it is to be mentioned that for problem instances with a small `disks` argument, it is easier to collect all the moves first in a list and then add the order number with the [enumerate()](https://docs.python.org/3/library/functions.html#enumerate) built-in."
]
},
{

7068
05_numbers.ipynb Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,722 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"# Chapter 5: Numbers"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Content Review"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Read [Chapter 5](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb) of the book. Then work through the eighteen review questions."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Essay Questions "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Answer the following questions briefly with *at most* 300 characters per question!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q1**: In what way is the **binary representation** of `int` objects *similar* to the **decimal system** taught in elementary school?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q2**: Why may objects of type `bool` be regarded a **numeric type** as well?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q3**: Why is it *inefficient* to store `bool` objects in bits resembling a **hexadecimal representation**?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q4**: Colors are commonly expressed in the **hexadecimal system** in websites (cf., the [HTML](https://en.wikipedia.org/wiki/HTML) and [CSS](https://en.wikipedia.org/wiki/Cascading_Style_Sheets) formats).\n",
"\n",
"For example, $#000000$, $#ff9900$, and $#ffffff$ turn out to be black, orange, and white. The six digits are read in *pairs of two* from left to right, and the *three pairs* correspond to the proportions of red, green, and blue mixed together. They reach from $0_{16} = 0_{10}$ for $0$% to $\\text{ff}_{16} = 255_{10}$ for $100$% (cf., this [article](https://en.wikipedia.org/wiki/RGB_color_model) for an in-depth discussion).\n",
"\n",
"In percent, what are the proportions of red, green, and blue that make up orange? Calculate the three percentages separately! How many **bytes** are needed to encode a color? How many **bits** are that?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q5**: What does it mean for a code fragment to **fail silently**?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q6**: Explain why the mathematical set of all real numbers $\\mathbb{R}$ can only be **approximated** by floating-point numbers on a computer!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q7**: How do we deal with a `float` object's imprecision if we need to **check for equality**?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q8**: What data type, built-in or from the [standard library](https://docs.python.org/3/library/index.html), is best suited to represent the [transcendental numbers](https://en.wikipedia.org/wiki/Transcendental_number) $\\pi$ and $\\text{e}$?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q9**: How can **abstract data types**, for example, as defined in the **numeric tower**, be helpful in enabling **duck typing**?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### True / False Questions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Motivate your answer with *one short* sentence!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q10**: The precision of `int` objects depends on how we choose to represent them in memory. For example, using a **hexadecimal representation** gives us $16^8$ digits whereas with a **binary representation** an `int` object can have *at most* $2^8$ digits."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q11**: With the built-in [round()](https://docs.python.org/3/library/functions.html#round) function, we obtain a *precise* representation for any `float` object if we can live with *less than* $15$ digits of precision."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q12**: As most currencies operate with $2$ or $3$ decimals (e.g., EUR $9.99$), the `float` type's limitation of *at most* $15$ digits is *not* a problem in practice."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q13**: The [IEEE 754](https://en.wikipedia.org/wiki/IEEE_754) standard's **special values** provide no benefit in practice as we could always use a **[sentinel](https://en.wikipedia.org/wiki/Sentinel_value)** value (i.e., a \"dummy\"). For example, instead of `nan`, we can always use `0` to indicate a *missing* value."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q14**: The following code fragment raises an `InvalidOperation` exception. That is an example of code **failing loudly**.\n",
"```python\n",
"float(\"inf\") + float(\"-inf\")\n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q15**: Python provides a `scientific` type (e.g., `1.23e4`) that is useful mainly to model problems in the domains of physics or astrophysics."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q16**: From a practitioner's point of view, the built-in [format()](https://docs.python.org/3/library/functions.html#format) function does the *same* as the built-in [round()](https://docs.python.org/3/library/functions.html#round) function."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q17**: The `Decimal` type from the [decimal](https://docs.python.org/3/library/decimal.html) module in the [standard library](https://docs.python.org/3/library/index.html) allows us to model the set of the real numbers $\\mathbb{R}$ *precisely*."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q18**: The `Fraction` type from the [fractions](https://docs.python.org/3/library/fractions.html) module in the [standard library](https://docs.python.org/3/library/index.html) allows us to model the set of the rational numbers $\\mathbb{Q}$ *precisely*."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Coding Exercises"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Discounting Customer Orders (revisited)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q11** in [Chapter 2's Review & Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions_review_and_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 **Q9** from [Chapter 3's Review & Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_review_and_exercises.ipynb#Discounting-Customer-Orders) section, and make the `discounted_price()` function work *correctly* for real-life sales data."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q19.1**: Execute the code cells below! What results would you have *expected*, and why?"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"round(1.5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"round(2.5)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"round(2.675, 2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q19.2**: The built-in [round()](https://docs.python.org/3/library/functions.html#round) function implements the \"**[round half to even](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even)**\" strategy. Describe in one or two sentences what that means!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q19.3**: For the revised `discounted_price()` function, we have to tackle *two* issues: First, we have to replace the built-in `float` type with a data type that allows us to control the precision. Second, the discounted price should be rounded according to a more human-friendly rounding strategy, namely \"**[round half away from zero](https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero)**.\"\n",
"\n",
"Describe in one or two sentences how \"**[round half away from zero](https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero)**\" is more in line with how humans think of rounding!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q19.4**: We use the `Decimal` type from the [decimal](https://docs.python.org/3/library/decimal.html) module in the [standard library](https://docs.python.org/3/library/index.html) to tackle *both* issues simultaneously.\n",
"\n",
"Assign `euro` a numeric object such that both `Decimal(\"1.5\")` and `Decimal(\"2.5\")` are rounded to `Decimal(\"2\")` (i.e., no decimal) with the [quantize()](https://docs.python.org/3/library/decimal.html#decimal.Decimal.quantize) method!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from decimal import Decimal"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"euro = ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Decimal(\"1.5\").quantize(...)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Decimal(\"2.5\").quantize(...)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q19.5**: Obviously, the two preceding code cells still [round half to even](https://en.wikipedia.org/wiki/Rounding#Round_half_to_even).\n",
"\n",
"The [decimal](https://docs.python.org/3/library/decimal.html) module defines a `ROUND_HALF_UP` flag that we can pass as the second argument to the [quantize()](https://docs.python.org/3/library/decimal.html#decimal.Decimal.quantize) method. Then, it [rounds half away from zero](https://en.wikipedia.org/wiki/Rounding#Round_half_away_from_zero).\n",
"\n",
"Add `ROUND_HALF_UP` to the code cells! `Decimal(\"2.5\")` should now be rounded to `Decimal(\"3\")`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from decimal import ROUND_HALF_UP"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Decimal(\"1.5\").quantize(...)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Decimal(\"2.5\").quantize(...)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q19.6**: Instead of `euro`, define `cents` such that rounding occurs to *two* decimals! `Decimal(\"2.675\")` should now be rounded to `Decimal(\"2.68\")`. Do *not* forget to include the `ROUND_HALF_UP` flag!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"cents = ..."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"Decimal(\"2.675\").quantize(...)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q19.7**: Re-write the function `discounted_price()` from [Chapter 3's Review & Exercises](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals_review_and_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",
"- if the unit price is over 100 dollars, grant 10% relative discount\n",
"- if a customer orders more than 10 items, one in every five items is for free\n",
"\n",
"Only one of the two discounts is granted, whichever is better for the customer.\n",
"\n",
"The function then returns the overall price for the line item as a `Decimal` number with a precision of *two* decimals.\n",
"\n",
"Enable **duck typing** by allowing the function to be called with various numeric types as the arguments, in particular, `quantity` may be a non-integer as well: Use an appropriate **abstract data type** 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 verify the arguments' types and also that they are both positive!\n",
"\n",
"It is considered a *best practice* to only round towards the *end* of the calculations."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import numbers"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def discounted_price(...):\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ...\n",
" ..."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q19.8**: Execute the code cells below and verify the final price for the following four test cases:\n",
"\n",
"- $7$ smartphones @ $99.00$ USD\n",
"- $3$ workstations @ $999.00$ USD\n",
"- $19$ GPUs @ $879.95$ USD\n",
"- $14$ Raspberry Pis @ $35.00$ USD\n",
"\n",
"The output should now *always* be a `Decimal` number with *two* decimals!"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"discounted_price(99, 7)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"discounted_price(999, 3)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"discounted_price(879.95, 19)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"discounted_price(35, 14)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"This also works if `quantity` is passed in as a `float` type."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"discounted_price(99, 7.0)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Decimals beyond the first two are gracefully discarded (i.e., *without* rounding errors accumulating)."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"discounted_price(99.0001, 7)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The basic input validation ensures that the user of `discounted_price()` does not pass in invalid data. Here, the `\"abc\"` creates a `TypeError`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"discounted_price(\"abc\", 7)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"A `-1` passed in as `unit_price` results in a `ValueError`."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"discounted_price(-1, 7)"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": true,
"skip_h1_title": true,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}

2787
06_text.ipynb Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,205 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n",
"# Chapter 6: Text"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Content Review"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Read [Chapter 6](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb) of the book. Then work through the eight review questions."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Essay Questions "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Answer the following questions briefly with *at most* 300 characters per question!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q1**: In what sense is a **\"string\" of characters** a **sequence**? What is a **sequence** after all? A *concrete* **data type**, or something else?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q2**: What is a direct consequence of the `str` type's property of being **ordered**? What operations could we *not* do with it if it were *unordered*?"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q3**: What does it mean for an object to be **immutable**? Discuss how we can verify the `str` type's immutability by comparing the two variables `example` and `full_slice` below. Are they pointing to the *same* object in memory?\n",
"```python\n",
"example = \"text\"\n",
"full_slice = example[:]\n",
"```\n",
"Hint: Find out what `[:]` does first!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q4**: Describe in your own words what we mean with **string interpolation**!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### True / False Questions"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Motivate your answer with *one short* sentence!"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q5**: **Triple-double** quotes `\"\"\"` and **triple-single** quotes `'''` create a *new* object of type `text` that model so-called **multi-line strings**."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q6**: A **substring** is a string that *subsumes* another string."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q7**: Indexing into a `str` object with a *negative* index **fails silently**: It does *not* raise an error but also does *not* do anything useful."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q8**: We *cannot* assign a *different* character to an index or slice of a `str` object because it is **immutable**."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
" "
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.7.3"
},
"toc": {
"base_numbering": 1,
"nav_menu": {},
"number_sections": false,
"sideBar": true,
"skip_h1_title": true,
"title_cell": "Table of Contents",
"title_sidebar": "Contents",
"toc_cell": false,
"toc_position": {},
"toc_section_display": false,
"toc_window_display": false
}
},
"nbformat": 4,
"nbformat_minor": 2
}

View file

@ -19,6 +19,8 @@ As such they can be viewed in a plain web browser:
- [02 - Functions & Modularization](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb)
- [03 - Conditionals & Exceptions](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb)
- [04 - Recursion & Looping](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/04_iteration.ipynb)
- [05 - Numbers](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/05_numbers.ipynb)
- [06 - Text](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/06_text.ipynb)
However, it is recommended that students **install Python and Jupyter
locally** and run the code in the notebooks on their own.

View file

@ -1,6 +1,6 @@
[tool.poetry]
name = "intro-to-python"
version = "0.1.0"
version = "0.4.0"
description = "An introduction to Python and programming for wanna-be data scientists"
authors = ["Alexander Hess <alexander@webartifex.biz>"]
license = "MIT"

BIN
static/complex_numbers.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
static/floating_point.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
static/numbers.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB