Streamline previous content
- run grammarly on all notebooks - add section on short-circuiting in chapter 03
This commit is contained in:
parent
6bebe70e24
commit
dbc3a67af4
11 changed files with 1345 additions and 1156 deletions
|
|
@ -20,11 +20,11 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Do you remember how you first learned to speak in your mother tounge? Probably not. No one's memory goes back that far. Your earliest memory as a child should probably be around the age of three or four years old when you could already say simple things and interact with your environment. Although you did not know any grammar rules yet, other people just understood what you said. Well, most of the time.\n",
|
||||
"Do you remember how you first learned to speak in your mother tongue? Probably not. No one's memory goes back that far. Your earliest memory as a child should probably be around the age of three or four years old when you could already say simple things and interact with your environment. Although you did not know any grammar rules yet, other people just understood what you said. Well, most of the time.\n",
|
||||
"\n",
|
||||
"It is intuitively best to take the very mindset of a small child when learing a foreign language and we do so for learning the Python language as well. This first chapter introduces simplistic examples and we better just accept them as they are without knowing any of the \"grammar\" rules yet. Then, we analyze them in parts and slowly build up our understanding.\n",
|
||||
"It is intuitively best to take the very mindset of a small child when learning a foreign language. This first chapter introduces simplistic examples, and we accept them as they are *without* knowing any of the \"grammar\" rules yet. Then, we analyze them in parts and slowly build up our understanding.\n",
|
||||
"\n",
|
||||
"Consequently, if parts of this chapter do not make sense right away, let's not worry too much. Besides introducing some basics that we need to understand, it also serves as an outlook for what is to come. So, many terms and concepts used here will be covered in great detail in following chapters."
|
||||
"Consequently, if parts of this chapter do not make sense right away, let's not worry too much. Besides introducing the basic elements, it also serves as an outlook for what is to come. So, many terms and concepts used here are deconstructed in great detail in the following chapters."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -75,7 +75,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"To verify that something happened in our computer's memory, we simply **reference** `numbers`."
|
||||
"To verify that something happened in our computer's memory, we **reference** `numbers`."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -116,11 +116,11 @@
|
|||
"\n",
|
||||
"The `if number % 2 == 0` may look disturbing at first sight. Both the `%` and `==` must have an unintuitive meaning here. Luckily, the **comment** in the same line after the `#` symbol has the answer: The program only does something if the current `number` is even.\n",
|
||||
"\n",
|
||||
"In particular, it increases `count` by $1$ and adds the current `number` onto the [running](https://en.wikipedia.org/wiki/Running_total) `total`. Both `count` and `number` were initially set to $0$ and the single `=` symbol reads as \"... is *set* equal to ...\". It could not indicate a mathematical equation as, for example, `count` is generally not equal to `count + 1`.\n",
|
||||
"In particular, it increases `count` by $1$ and adds the current `number` onto the [running](https://en.wikipedia.org/wiki/Running_total) `total`. Both `count` and `number` are initially set to $0$ and the single `=` symbol reads as \"... is *set* equal to ...\". It could not indicate a mathematical equation as, for example, `count` is generally not equal to `count + 1`.\n",
|
||||
"\n",
|
||||
"Lastly, the `average` is calculated as the ratio of the final **values** of `total` and `count`. Overall, we divide the sum of all even numbers by the count of all even numbers, which is exactly what we are looking for.\n",
|
||||
"Lastly, the `average` is calculated as the ratio of the final **values** of `total` and `count`. Overall, we divide the sum of all even numbers by their count: This is nothing but the definition of an average.\n",
|
||||
"\n",
|
||||
"The lines of code \"within\" the `for` and `if` **statements** are **indented** and *aligned* with multiples of **four spaces**: This shows immediately how the lines relate to each other."
|
||||
"The lines of code \"within\" the `for` and `if` **statements** are **indented** and **aligned** with multiples of **four spaces**: This shows immediately how the lines relate to each other."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -133,8 +133,8 @@
|
|||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"count = 0 # initialize variables to keep track of the sum\n",
|
||||
"total = 0 # so far and the count of the even numbers\n",
|
||||
"count = 0 # initialize variables to keep track of the\n",
|
||||
"total = 0 # running total and the count of even numbers\n",
|
||||
"\n",
|
||||
"for number in numbers:\n",
|
||||
" if number % 2 == 0: # only look at even numbers\n",
|
||||
|
|
@ -152,7 +152,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"We do not see any **output** yet but obtain the value of `average` by simply referencing it again."
|
||||
"We do not see any **output** yet but obtain the value of `average` by referencing it again."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -249,7 +249,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"To visualize something before the end of the cell, we use the [print()](https://docs.python.org/3/library/functions.html#print) built-in **function**."
|
||||
"To visualize something before the end of the cell, we use the built-in [print()](https://docs.python.org/3/library/functions.html#print) **function**. Here, the parentheses `()` indicate that we execute code defined somewhere else."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -283,7 +283,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Outside Jupyter notebooks, the semicolon `;` is actually used as a **seperator** between several statements that would otherwise have to be on a line on their own. However, it as *not* considered good practice to use it as it makes code less readable."
|
||||
"Outside Jupyter notebooks, the semicolon `;` is used as a **separator** between statements that must otherwise be on a line on their own. However, it is *not* considered good practice to use it as it makes code less readable."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -327,11 +327,11 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Python comes with many **[operators](https://docs.python.org/3/reference/lexical_analysis.html#operators)** built in: They are **tokens** (i.e., \"symbols\") that have a special meaning to the Python interpreter.\n",
|
||||
"Python comes with many built-in **[operators](https://docs.python.org/3/reference/lexical_analysis.html#operators)**: They are **tokens** (i.e., \"symbols\") that have a special meaning to the Python interpreter.\n",
|
||||
"\n",
|
||||
"The arithmetic operators either \"operate\" with the number immediately following them (= **unary** operators; e.g., negation) or \"process\" the two numbers \"around\" them (= **binary** operators; e.g., addition). But we will see many exceptions from that as well.\n",
|
||||
"The arithmetic operators either \"operate\" with the number immediately following them (= **unary** operators; e.g., negation) or \"process\" the two numbers \"around\" them (= **binary** operators; e.g., addition).\n",
|
||||
"\n",
|
||||
"By definition, operators have **no** permanent **side effects** in the computer's memory. Although the code cells in this section do indeed create *new* numbers in memory (e.g., `77 + 13` creates `90`), they are immediately \"forgotten\" as they are not stored in a **variable** like `numbers` or `average` above. We will continue this thought further below when we compare **expressions** with **statements**.\n",
|
||||
"By definition, operators have **no** permanent **side effects** in the computer's memory. Although the code cells in this section do indeed create *new* numbers in memory (e.g., `77 + 13` creates `90`), they are immediately \"forgotten\" as they are not stored in a **variable** like `numbers` or `average` above. We continue this thought further below when we compare **expressions** with **statements**.\n",
|
||||
"\n",
|
||||
"Let's see some examples of operators. We start with the binary `+` and the `-` operators for addition and subtraction. Binary operators are designed to resemble what mathematicians call [infix notation](https://en.wikipedia.org/wiki/Infix_notation) and have the expected meaning."
|
||||
]
|
||||
|
|
@ -427,7 +427,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"When we compare the output of the `*` and `/` operators for multiplication and division, we note the subtle *difference* between the $42$ and the $42.0$. This is a first illustration of the concept of a **data type**."
|
||||
"When we compare the output of the `*` and `/` operators for multiplication and division, we note the subtle *difference* between the $42$ and the $42.0$: They are the *same* number represented as a *different* **data type**."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -486,7 +486,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The so-called **floor division operator** `//` always \"rounds\" to the next integer and is thus also called **integer division operator**. This is a first example of an operator we commonly do not know from high school mathematics."
|
||||
"The so-called **floor division operator** `//` always \"rounds\" to an integer and is thus also called **integer division operator**. It is an example of an arithmetic operator we commonly do not know from high school mathematics."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -615,7 +615,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Note that the remainder is $0$ *only if* a number is *divisable* by another."
|
||||
"The remainder is $0$ *only if* a number is *divisible* by another.\n",
|
||||
"\n",
|
||||
"A popular convention in both, computer science and mathematics, is to abbreviate \"only if\" as **iff**, which is short for \"**[if and only if](https://en.wikipedia.org/wiki/If_and_only_if)**.\" The iff means that a remainder of $0$ implies that a number is divisible by another but also that a number divisible by another implies a remainder of $0$. The implication goes in *both* directions!"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -744,7 +746,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Raising a number to a power is performed with the **exponentiation operator** `**`. This is different from the `^` operator many other programming languages use and that also exists in Python with a *different* meaning."
|
||||
"Raising a number to a power is performed with the **exponentiation operator** `**`. It is different from the `^` operator other programming languages may use and that also exists in Python with a *different* meaning."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -779,7 +781,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The normal [order of precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) from mathematics applies (i.e., \"PEMDAS\" rule)."
|
||||
"The standard [order of precedence](https://docs.python.org/3/reference/expressions.html#operator-precedence) from mathematics applies (i.e., \"PEMDAS\" rule)."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -908,7 +910,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"There are many more non-mathematical operators that are introduced throughout this book together with the concepts they implement. Some of these are already shown in the next section."
|
||||
"There exist many non-mathematical operators that are introduced throughout this book, together with the concepts they implement. They often come in a form different from the unary and binary mentioned above."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -932,9 +934,9 @@
|
|||
"source": [
|
||||
"Python is a so-called **object-oriented** language, which is a paradigm of organizing a program's memory.\n",
|
||||
"\n",
|
||||
"An **object** can be viewed as a \"bag\" of $0$s and $1$s in a distinct memory location that not only portrayes the idea of a certain **value** but also has some associated rules as to how this value is treated and may be worked with.\n",
|
||||
"An **object** may be viewed as a \"bag\" of $0$s and $1$s in a distinct memory location. The concrete $0$s and $1$s in a bag portray the idea of the object's **value**, and there exist different **types** of bags that each come with associated rules as to how the $0$s and $1$s are interpreted and may be worked with.\n",
|
||||
"\n",
|
||||
"An object *always* has **three** main characteristics. Let's look at the following examples and work them out."
|
||||
"So, an object *always* has **three** main characteristics. Let's look at the following examples and work them out."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -986,7 +988,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"140098012863472"
|
||||
"139829040614096"
|
||||
]
|
||||
},
|
||||
"execution_count": 28,
|
||||
|
|
@ -1010,7 +1012,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"140098013042536"
|
||||
"139829040789352"
|
||||
]
|
||||
},
|
||||
"execution_count": 29,
|
||||
|
|
@ -1034,7 +1036,7 @@
|
|||
{
|
||||
"data": {
|
||||
"text/plain": [
|
||||
"140098012714672"
|
||||
"139829040474736"
|
||||
]
|
||||
},
|
||||
"execution_count": 30,
|
||||
|
|
@ -1054,7 +1056,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"These addresses are really not that meaningful for anything other than checking if two variables actually **point** at the same object. This may be helpful as, for example, different objects in memory may of course have the same value."
|
||||
"These addresses are *not* meaningful for anything other than checking if two variables **point** at the same object. Let's create a second variable `d` and also set it to `789`."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1078,7 +1080,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"`a` and `d` indeed have the same value as is checked with the **equality operator** `==`. The resulting `True` (and the `False` below) is yet another data type, a so-called **boolean**. We will look into that closely in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb)."
|
||||
"`a` and `d` indeed have the same value as is checked with the **equality operator** `==`. The resulting `True` (and the `False` further below) is yet another data type, a so-called **boolean**. We look into them closely in [Chapter 3](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/03_conditionals.ipynb)."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1113,7 +1115,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"On the contrary, `a` and `d` are different objects as the **identity operator** `is` shows: they are stored at seperate addresses in the memory."
|
||||
"On the contrary, `a` and `d` are different objects as the **identity operator** `is` shows: they are stored at separate addresses in the memory."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1220,9 +1222,7 @@
|
|||
"source": [
|
||||
"Different types imply different behaviors for the objects. The `b` object, for example, can be \"asked\" if it could also be interpreted as an `int` with the [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) \"functionality\" that comes with every `float` object.\n",
|
||||
"\n",
|
||||
"Formally, we call such type-specific functionalities **methods** (to differentiate them from functions) and we will eventually fully introduce them when we talk about object-orientation in Chapter 10. For now, it suffices to know that we access them using the **dot operator** `.`. Of course `b` could be converted into an `int`, which the boolean value `True` tells us.\n",
|
||||
"\n",
|
||||
"Also note how the `.` operator is neiter a unary nor a binary operator as specified above."
|
||||
"Formally, we call such type-specific functionalities **methods** (to differentiate them from functions) and we formally introduce them in Chapter 10. For now, it suffices to know that we access them using the **dot operator** `.`. Of course, `b` could be converted into an `int`, which the boolean value `True` tells us."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1257,7 +1257,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"For an `int` object this [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) check does not make sense as we know it is an `int` to begin with. This is why we see the `AttributeError` below as `a` does not even know what `is_integer()` means."
|
||||
"For an `int` object, this [is_integer()](https://docs.python.org/3/library/stdtypes.html#float.is_integer) check does *not* make sense as we already know it is an `int`: We see the `AttributeError` below as `a` does not even know what `is_integer()` means."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1293,7 +1293,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The `c` object is a so-called **string** type (i.e., `str`), which is Python's way of representing \"text\". Strings also come with their own behaviors, for example, to convert a text to lower or upper case."
|
||||
"The `c` object is a so-called **string** type (i.e., `str`), which is Python's way of representing \"text.\" Strings also come with peculiar behaviors, for example, to convert a text to lower or upper case."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1411,9 +1411,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Almost trivially, every object also has a value to which it \"evaluates\" when referenced. We think of the value as the **conceptual idea** of what the $0$s and $1$s in memory mean to us humans. A machine does not really see beyond the $0$s and $1$s. At least, not yet.\n",
|
||||
"Almost trivially, every object also has a value to which it \"evaluates\" when referenced. We think of the value as the **conceptual idea** of what the $0$s and $1$s in memory mean to humans as machines cannot see beyond $0$s and $1$s.\n",
|
||||
"\n",
|
||||
"For built-in data types, Python prints out the object's value in a so-called **[literal](https://docs.python.org/3/reference/lexical_analysis.html#literals)** notation. This basically means that we can just copy & paste the output back into a code cell to create a *new* object with the *same* value."
|
||||
"For built-in data types, Python prints out the object's value as a so-called **[literal](https://docs.python.org/3/reference/lexical_analysis.html#literals)**: This means that we can copy and paste the output back into a code cell to create a *new* object with the *same* value."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1472,7 +1472,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"In this book, we follow the convention of creating strings with **double quotes** `\"` instead of the **single quotes** `'` to which Python defaults in its literal output for `str` objects. Both types of quotes may be used interchangebly."
|
||||
"In this book, we follow the convention of creating strings with **double quotes** `\"` instead of the **single quotes** `'` to which Python defaults in its literal output for `str` objects. Both types of quotes may be used interchangeably."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1544,7 +1544,7 @@
|
|||
"source": [
|
||||
"If we do not follow the rules, the code cannot be **parsed** correctly, i.e., the program does not even start to run but **raises** a **syntax error** indicated as `SyntaxError` in the output. Computers are very dumb in the sense that the slightest syntax error leads to the machine not understanding our code.\n",
|
||||
"\n",
|
||||
"For example, if we wanted to write an accounting program that adds up currencies, we would have to model dollar prices as `float` objects as the dollar symbol cannot be read by Python."
|
||||
"For example, if we wanted to write an accounting program that adds up currencies, we would have to model dollar prices as `float` objects as the dollar symbol cannot be understood by Python."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1577,7 +1577,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Python requires certain symbols at certain places (e.g., a `:` is missing here) ..."
|
||||
"Python requires certain symbols at certain places (e.g., a `:` is missing here)."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1611,7 +1611,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"... and relies on whitespace (i.e., indentation) unlike many other programming languages. An `IndentationError` is just a special type of a `SyntaxError`."
|
||||
"Furthermore, it relies on whitespace (i.e., indentation), unlike many other programming languages. The `IndentationError` below is just a particular type of a `SyntaxError`."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1656,7 +1656,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Syntax errors as above are easy to find as the code will not even run to begin with.\n",
|
||||
"Syntax errors are easy to find as the code does not even run in the first place.\n",
|
||||
"\n",
|
||||
"However, there are also so-called **runtime errors**, often called **exceptions**, that occur whenever otherwise (i.e., syntactically) correct code does not run because of invalid input.\n",
|
||||
"\n",
|
||||
|
|
@ -1709,7 +1709,7 @@
|
|||
"source": [
|
||||
"So-called **semantic errors**, on the contrary, are hard to spot as they do *not* crash the program. The only way to find such errors is to run a program with test input for which we can predict the output. However, testing software is a whole discipline on its own and often very hard to do in practice.\n",
|
||||
"\n",
|
||||
"The cell below copies our introductory example from above with a \"tiny\" error. How fast could you have spotted it without the comment?"
|
||||
"The cell below copies our first example from above with a \"tiny\" error. How fast could you have spotted it without the comment?"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1766,7 +1766,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Finding errors in a systematic way is called **debugging**. For the history of the term, see this [article](https://en.wikipedia.org/wiki/Debugging)."
|
||||
"Systematically finding errors is called **debugging**. For the history of the term, see this [article](https://en.wikipedia.org/wiki/Debugging)."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1788,7 +1788,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Adhering to just syntax rules is therefore *never* enough. Over time, **best practices** and common **style guides** were created to make it less likely for a developer to mess up a program and also to allow \"onboarding\" him as a contributor to an established code base, often called **legacy code**, faster. These rules are not enforced by Python itself: Badly styled and un-readable code will still run. At the very least, Python programs should be styled according to [PEP 8](https://www.python.org/dev/peps/pep-0008/) and documented \"inline\" (i.e., in the code itself) according to [PEP 257](https://www.python.org/dev/peps/pep-0257/).\n",
|
||||
"Thus, adhering to just syntax rules is *never* enough. Over time, **best practices** and **style guides** were created to make it less likely for a developer to mess up a program and also to allow \"onboarding\" him as a contributor to an established code base, often called **legacy code**, faster. These rules are not enforced by Python itself: Badly styled code still runs. At the very least, Python programs should be styled according to [PEP 8](https://www.python.org/dev/peps/pep-0008/) and documented \"inline\" (i.e., in the code itself) according to [PEP 257](https://www.python.org/dev/peps/pep-0257/).\n",
|
||||
"\n",
|
||||
"An easier to read version of PEP 8 is [here](https://pep8.org/). The video below features a well known \"[Pythonista](https://en.wiktionary.org/wiki/Pythonista)\" talking about the importance of code style."
|
||||
]
|
||||
|
|
@ -1817,7 +1817,7 @@
|
|||
" "
|
||||
],
|
||||
"text/plain": [
|
||||
"<IPython.lib.display.YouTubeVideo at 0x7f6b1c40e8d0>"
|
||||
"<IPython.lib.display.YouTubeVideo at 0x7f2c7c4206d8>"
|
||||
]
|
||||
},
|
||||
"execution_count": 51,
|
||||
|
|
@ -1838,7 +1838,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"For example, while the above code to calculate the average of the even numbers from 1 through 10 is correct, a Pythonista would re-write it in a more \"Pythonic\" way and use the [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) (= \"length\") built-in functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb)) as well as a so-called **list comprehension** (cf., Chapter 7). Pythonic code runs faster in many cases and is less error prone."
|
||||
"For example, while the above code to calculate the average of the even numbers from 1 through 10 is correct, a Pythonista would re-write it in a more \"Pythonic\" way and use the [sum()](https://docs.python.org/3/library/functions.html#sum) and [len()](https://docs.python.org/3/library/functions.html#len) (= \"length\") built-in functions (cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb)) as well as a so-called **list comprehension** (cf., Chapter 7). Pythonic code runs faster in many cases and is less error-prone."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -1936,7 +1936,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"To get a rough overview of the mindsets of a typical Python programmer, check these rules by an early Python core developer that are deemed so important that they are actually included in every Python installation."
|
||||
"To get a rough overview of the mindsets of a typical Python programmer, see these rules by an early Python core developer deemed so important that they are included in every Python installation."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2012,7 +2012,7 @@
|
|||
"source": [
|
||||
"Observe that you can run the code cells in a Jupyter notebook in any arbitrary order.\n",
|
||||
"\n",
|
||||
"That means, for example, that a variable defined towards the bottom could accidently be referenced at the top of the notebook. This happens easily if we iteratively built a program and go back and forth between cells.\n",
|
||||
"That means, for example, that a variable defined towards the bottom could accidentally be referenced at the top of the notebook. This happens quickly when we iteratively built a program and go back and forth between cells.\n",
|
||||
"\n",
|
||||
"As a good practice, it is recommended to click on \"Kernel\" > \"Restart & Run All\" in the navigation bar once a notebook is finished. That restarts the Python process forgetting any **state** (i.e., all variables) and ensures that the notebook runs top to bottom without any errors the next time it is opened."
|
||||
]
|
||||
|
|
@ -2036,11 +2036,11 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"While this book is built with Jupyter notebooks, it is important to understand that \"real\" programs are almost always just \"linear\" (= top to bottom) sequences of instructions but instead may take many different **flows of execution**.\n",
|
||||
"While this book is built with Jupyter notebooks, it is crucial to understand that \"real\" programs are almost always just \"linear\" (= top to bottom) sequences of instructions but instead may take many different **flows of execution**.\n",
|
||||
"\n",
|
||||
"At the same time, for a beginner's course it is often easier to just code in a linear fashion.\n",
|
||||
"At the same time, for a beginner's course, it is often easier to code linearly.\n",
|
||||
"\n",
|
||||
"In real data science projects one would probably employ a mixed approach and put re-usable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb)) and then use Jupyter notebooks to built up a linear report or story line for a business argument to be made."
|
||||
"In real data science projects, one would probably employ a mixed approach and put re-usable code into so-called Python modules (i.e., *.py* files; cf., [Chapter 2](https://nbviewer.jupyter.org/github/webartifex/intro-to-python/blob/master/02_functions.ipynb)) and then use Jupyter notebooks to build up a linear report or storyline for a business argument to be made."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2064,7 +2064,7 @@
|
|||
"source": [
|
||||
"**Variables** are created with the **[assignment statement](https://docs.python.org/3/reference/simple_stmts.html#assignment-statements)** `=`, which is *not* an operator, mainly because of its side effect of making a **[name](https://docs.python.org/3/reference/lexical_analysis.html#identifiers)** point to an object in memory.\n",
|
||||
"\n",
|
||||
"We will read the terms **variable**, **name**, and **identifier** used interchangebly in many Python related texts. In this book, we adopt the following convention: First, we treat *name* and *identifier* as perfect synonyms but only use the term *name* in the text for clarity. Second, whereas *name* only refers to a string of letters, numbers, and some other symbols, a *variable* refers to the combination of a *name* and a *pointer* to some object in memory."
|
||||
"We read the terms **variable**, **name**, and **identifier** used interchangebly in many Python-related texts. In this book, we adopt the following convention: First, we treat *name* and *identifier* as perfect synonyms but only use the term *name* in the text for clarity. Second, whereas *name* only refers to a string of letters, numbers, and some other symbols, a *variable* refers to the combination of a *name* and a *pointer* to some object in memory."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2089,7 +2089,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"When referenced, a variable evaluates to the value of the object it points to. Colloquially, we could say that `a` evaluates to `20.0` here but this would not be a full description of what is really going on in memory. We will see some more colloquial jargons in this section but should always relate this to what Python actually does in memory."
|
||||
"When referenced, a variable evaluates to the value of the object it points to. Colloquially, we could say that `a` evaluates to `20.0`, but this would not be an accurate description of what is going on in memory. We see some more colloquialisms in this section but should always relate this to what Python actually does in memory."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2172,7 +2172,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"If we want to re-assign a variable while referencing its \"old\" (i.e., current) object, we may also **update** it using a so-called **[augmented assignment statement](https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements)** (*not* operator), originally introduced with [PEP 203](https://www.python.org/dev/peps/pep-0203/). This implicitly inserts the currently mapped object as the first operand on the right-hand side."
|
||||
"If we want to re-assign a variable while referencing its \"old\" (i.e., current) object, we may also **update** it using a so-called **[augmented assignment statement](https://docs.python.org/3/reference/simple_stmts.html#augmented-assignment-statements)** (*not* operator), introduced with [PEP 203](https://www.python.org/dev/peps/pep-0203/): The currently mapped object is implicitly inserted as the first operand on the right-hand side."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2246,7 +2246,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Variables are **[de-referenced](https://docs.python.org/3/reference/simple_stmts.html#the-del-statement)** (i.e., \"deleted\") with the `del` statement. This does *not* delete the object to which a variable points to. It merely removes the variable's name from the \"global list of all names\"."
|
||||
"Variables are **[de-referenced](https://docs.python.org/3/reference/simple_stmts.html#the-del-statement)** (i.e., \"deleted\") with the `del` statement. It does *not* delete the object to which a variable points to but merely removes the variable's name from the \"global list of all names.\""
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2294,7 +2294,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"If we refer to an unknown name, a *runtime* error occurs, namely a `NameError`. The `Name` in `NameError` gives a hint as to why we prefer the term *name* over *identifier*: Python just uses it more often in its error messages."
|
||||
"If we refer to an unknown name, a *runtime* error occurs, namely a `NameError`. The `Name` in `NameError` gives a hint as to why we prefer the term *name* over *identifier*: Python uses it more often in its error messages."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2557,9 +2557,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"It is important to understand that *several* variables may point to the *same* object in memory. This may be counter-intuitive in the beginning and lead to many hard to track down bugs.\n",
|
||||
"It is *crucial* to understand that *several* variables may point to the *same* object in memory. Not having this in mind may lead to many hard to track down bugs.\n",
|
||||
"\n",
|
||||
"This makes `b` point to whatever object `a` is pointing to."
|
||||
"Make `b` point to whatever object `a` is pointing to."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2631,9 +2631,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"For \"simple\" types like `int` or `float` this will never cause troubles.\n",
|
||||
"For \"simple\" types like `int` or `float` this never causes troubles.\n",
|
||||
"\n",
|
||||
"Let's \"change the value\" of `a`. Really, let's create a *new* `123` object and make `a` point to it."
|
||||
"Let's \"change the value\" of `a`. To be precise, let's create a *new* `123` object and make `a` point to it."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2681,7 +2681,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"`b` \"is still the same\" as before. Really, `b` still points to the same object as before."
|
||||
"`b` \"is still the same\" as before. To be precise, `b` still points to the *same object* as before."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2779,7 +2779,7 @@
|
|||
"source": [
|
||||
"Let's change the first element of `x`.\n",
|
||||
"\n",
|
||||
"Chapter 7 discusses lists in more depth. For now, let's just view a `list` object as some sort of **container** that holds an arbitrary number of pointers to other objects and treat the brackets `[]` attached to it as just another operator, called the **indexing operator**. `x[0]` instructs Python to first follow the pointer from the global list of all names to the `x` object. Then, it follows the first pointer it finds there to the `1` object. The indexing operator must be an operator as we merely read the first element and do not change anything in memory.\n",
|
||||
"Chapter 7 discusses lists in more depth. For now, let's view a `list` object as some sort of **container** that holds an arbitrary number of pointers to other objects and treat the brackets `[]` attached to it as just another operator, called the **indexing operator**. `x[0]` instructs Python to first follow the pointer from the global list of all names to the `x` object. Then, it follows the first pointer it finds there to the `1` object. The indexing operator must be an operator as we merely read the first element and do not change anything in memory.\n",
|
||||
"\n",
|
||||
"Note how Python **begins counting at 0**. This is not the case for many other languages, for example, [MATLAB](https://en.wikipedia.org/wiki/MATLAB), [R](https://en.wikipedia.org/wiki/R_%28programming_language%29), or [Stata](https://en.wikipedia.org/wiki/Stata). To understand why this makes sense, see this short [note](https://www.cs.utexas.edu/users/EWD/transcriptions/EWD08xx/EWD831.html) by one of the all-time greats in computer science, the late [Edsger Dijkstra](https://en.wikipedia.org/wiki/Edsger_W._Dijkstra)."
|
||||
]
|
||||
|
|
@ -2816,7 +2816,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"To change the first entry in the list, we use the assignment statement `=` again. Here, this does actually *not* create a *new* variable (or overwrite an existing one) but only changes the object to which the first pointer in the `x` list points to. As we only change parts of the `x` object, we say that we **mutate** (i.e., \"change\") its **state**. To use the bag analogy from above, we keep the same bag but \"flip\" some of the $0$s into $1$s and some of the $1$s into $0$s."
|
||||
"To change the first entry in the list, we use the assignment statement `=` again. Here, this does *not* create a *new* variable (or overwrite an existing one) but only changes the object to which the first pointer in the `x` list points to. As we only change parts of the `x` object, we say that we **mutate** (i.e., \"change\") its **state**. To use the bag analogy from above, we keep the same bag but \"flip\" some of the $0$s into $1$s and some of the $1$s into $0$s."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -2901,11 +2901,11 @@
|
|||
"source": [
|
||||
"The illustrated difference in behavior has to do with the fact that integers and floats are **immutable** types while lists are **mutable**.\n",
|
||||
"\n",
|
||||
"In the first case, an object cannot be changed \"in place\" once it is created in memory. When we assigned `123` to the already existing `a`, we actually did not change the $0$s and $1$s in the object `a` pointed to before the assignment but created a new integer object and made `a` point to it while the `b` variable is *not* affected.\n",
|
||||
"In the first case, an object cannot be changed \"in place\" once it is created in memory. When we assigned `123` to the already existing `a`, we did not change the $0$s and $1$s in the object `a` pointed to before the assignment but created a new integer object and made `a` point to it while the `b` variable is *not* affected.\n",
|
||||
"\n",
|
||||
"In the second case, `x[0] = 99` creates a *new* integer object `99` and merely changes the first pointer in the `x` list.\n",
|
||||
"\n",
|
||||
"In general, the assignment statement creates (or overwrites) a variable and makes it point to whatever object is on the right-hand side *only if* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it mutates some already existing object. And we always have to expect that the latter might have more than one variable pointing at it.\n",
|
||||
"In general, the assignment statement creates a new name and makes it point to whatever object is on the right-hand side *iff* the left-hand side is a *pure* name (i.e., it contains no operators like the indexing operator in the example). Otherwise, it *mutates* an already existing object. And, we always must expect that the latter might have more than one variable pointing to it.\n",
|
||||
"\n",
|
||||
"Visualizing what is going on in the memory with a tool like [PythonTutor](http://pythontutor.com/visualize.html#code=x%20%3D%20%5B1,%202,%203%5D%0Ay%20%3D%20x%0Ax%5B0%5D%20%3D%2099%0Aprint%28y%5B0%5D%29&cumulative=false&curInstr=0&heapPrimitives=nevernest&mode=display&origin=opt-frontend.js&py=3&rawInputLstJSON=%5B%5D&textReferences=false) might be helpful for a beginner."
|
||||
]
|
||||
|
|
@ -2944,7 +2944,7 @@
|
|||
"source": [
|
||||
"Variable names may contain upper and lower case letters, numbers, and underscores (i.e., `_`) and be as long as we want them to be. However, they must not begin with a number. Also, they must not be any of Python's built-in **[keywords](https://docs.python.org/3/reference/lexical_analysis.html#keywords)**.\n",
|
||||
"\n",
|
||||
"Variable names are usually chosen such that they do not need any more documentation and are self-explanatory. A very common convention is to use so-called **[snake\\_case](https://en.wikipedia.org/wiki/Snake_case)**: Keep everything lowercase and use underscores to seperate words.\n",
|
||||
"Variable names should be chosen such that they do not need any more documentation and are self-explanatory. A widespread convention is to use so-called **[snake\\_case](https://en.wikipedia.org/wiki/Snake_case)**: Keep everything lowercase and use underscores to separate words.\n",
|
||||
"\n",
|
||||
"See this [link](https://en.wikipedia.org/wiki/Naming_convention_%28programming%29#Python_and_Ruby) for a comparison of different naming conventions."
|
||||
]
|
||||
|
|
@ -3092,7 +3092,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"If a variable name collides with a built-in name, just add a trailing underscore."
|
||||
"If a variable name collides with a built-in name, we add a trailing underscore."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3116,7 +3116,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Variables with leading and trailing double underscores, referred to as **dunder** in Python jargon, are used for important built-in functionalities. Do *not* use this style for custom variables unless you know exactly what you are doing!"
|
||||
"Variables with leading and trailing double underscores, referred to as **dunder** in Python jargon, are used for built-in functionalities. Do *not* use this style for custom variables unless you exactly know what you are doing!"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3162,7 +3162,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"This PyCon talk by [Ned Batchelder](https://nedbatchelder.com/), a well-known Pythonista and the organizer of the [Python User Group](https://www.meetup.com/bostonpython/) in Boston, summarizes all situations where some sort of variable assignment is done in Python. The content is intermediate and therefore it is ok if you do not understand everything at this point. However, the contents should be known by everyone claiming to be proficient in Python."
|
||||
"This PyCon talk by [Ned Batchelder](https://nedbatchelder.com/), a well-known Pythonista and the organizer of the [Python User Group](https://www.meetup.com/bostonpython/) in Boston, summarizes all situations where some sort of assignment is done in Python. The content is intermediate, and, thus, it might be worthwhile to come back to this talk at a later point in time. However, the contents should be known by everyone claiming to be proficient in Python."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3189,7 +3189,7 @@
|
|||
" "
|
||||
],
|
||||
"text/plain": [
|
||||
"<IPython.lib.display.YouTubeVideo at 0x7f6b1c4606d8>"
|
||||
"<IPython.lib.display.YouTubeVideo at 0x7f2c7c41bc50>"
|
||||
]
|
||||
},
|
||||
"execution_count": 94,
|
||||
|
|
@ -3225,7 +3225,7 @@
|
|||
"\n",
|
||||
"In simple words, anything that may be used on the right-hand side of an assignment statement without creating a `SyntaxError` is an expression.\n",
|
||||
"\n",
|
||||
"What we said about individual operators above, namely that they have *no* side effects, should have been put here to begin with. The examples in the section on operators above were actually all expressions!\n",
|
||||
"What we said about individual operators above, namely that they have *no* side effects, should have been put here, to begin with. The code cells in the section on operators above are all expressions!\n",
|
||||
"\n",
|
||||
"The simplest possible expressions contain only one variable or literal."
|
||||
]
|
||||
|
|
@ -3313,7 +3313,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The definition of an expression is **recursive**. So, here the sub-expression `a + b` is combined with the literal `3` by the operator `**` to form the full expression."
|
||||
"The definition of an expression is **recursive**. So, the sub-expression `a + b` is combined with the literal `3` by the operator `**` to form the full expression."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3383,7 +3383,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"When not used as a delimiter, parentheses also constitute an operator, namely the **call operator** `()`. We have seen this syntax above when we \"called\" (i.e., executed) built-in functions and methods."
|
||||
"When not used as a delimiter, parentheses also constitute an operator, namely the **call operator** `()`. We saw this syntax above when we \"called\" (i.e., executed) built-in functions and methods."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3429,7 +3429,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"Python **overloads** certain operators. For example, you may not only \"add\" numbers but also strings. This is called **string concatenation**."
|
||||
"Python **overloads** certain operators. For example, you may not only \"add\" numbers but also strings: This is called **string concatenation**."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3524,9 +3524,9 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"A **[statement](https://docs.python.org/3/reference/simple_stmts.html)** is anything that *changes* the *state of a program* or has some other *side effect*. Statements do not just evaluate to a value like expressions; instead, they create or change values.\n",
|
||||
"A **[statement](https://docs.python.org/3/reference/simple_stmts.html)** is anything that *changes* the *state of a program* or has another *side effect*. Statements, unlike expressions, do not just evaluate to a value; instead, they create or change values.\n",
|
||||
"\n",
|
||||
"Most notably of course are the `=` and `del` statements."
|
||||
"Most notably, of course, are the `=` and `del` statements."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3563,7 +3563,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"The built-in [print()](https://docs.python.org/3/library/functions.html#print) function is regarded a \"statement\" as well. In fact, it used to be a real statement in Python 2 and has all the necessary properties. It is a bit of a corner case as expressions are also \"printed\" in a Jupyter notebook when evaluated last in a code cell."
|
||||
"The built-in [print()](https://docs.python.org/3/library/functions.html#print) function is regarded as a \"statement\" as well. It used to be an actual statement in Python 2 and has all the necessary properties. It is a bit of a corner case as expressions are also \"printed\" in a Jupyter notebook when evaluated last in a code cell."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3608,9 +3608,9 @@
|
|||
"source": [
|
||||
"We use the `#` symbol to write comments in plain English right into the code.\n",
|
||||
"\n",
|
||||
"As a good practice, comments should not describe what happens (this should be evident by reading the code, otherwise it is most likely badly written code) but why something happens.\n",
|
||||
"As a good practice, comments should not describe *what* happens (this should be evident by reading the code; otherwise, it is most likely badly written code) but *why* something happens.\n",
|
||||
"\n",
|
||||
"Comments may be added either at the end of a line of code, by convention seperated with two spaces, or on a line on their own."
|
||||
"Comments may be added either at the end of a line of code, by convention separated with two spaces, or on a line on their own."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3637,8 +3637,8 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"But let's think wisely if we really need to use a comment.\n",
|
||||
"The second cell is a lot more \"Pythonic\"."
|
||||
"But let's think wisely if we need to use a comment.\n",
|
||||
"The second cell is a lot more Pythonic."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3686,7 +3686,7 @@
|
|||
}
|
||||
},
|
||||
"source": [
|
||||
"We end each chapter with a summary of the main points. The essence in this first chapter is that just like a sentence in a real language like English may be decomposed into its parts (subject, predicate, objects, ...) the same may be done with programming languages."
|
||||
"We end each chapter with a summary of the main points. The essence in this first chapter is that just like a sentence in a real language like English may be decomposed into its parts (e.g., subject, predicate, and objects), the same may be done with programming languages."
|
||||
]
|
||||
},
|
||||
{
|
||||
|
|
@ -3707,18 +3707,18 @@
|
|||
" - (numeric) data from a CSV file\n",
|
||||
" - text entered on a command line\n",
|
||||
" - (relational) data obtained from a database\n",
|
||||
" - ...\n",
|
||||
" - etc.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"- output (examples)\n",
|
||||
" - result of a computation (e.g., statistical summary of a sample dataset)\n",
|
||||
" - a \"side effect\" (e.g., a transformation of raw input data into cleaned data)\n",
|
||||
" - a physical \"behavior\" (e.g., a robot moving or a document printed)\n",
|
||||
" - ...\n",
|
||||
" - etc.\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"- objects\n",
|
||||
" - distinct and well-contained areas / parts of the memory that hold the actual data\n",
|
||||
" - distinct and well-contained areas/parts of the memory that hold the actual data\n",
|
||||
" - the concept by which Python manages the memory for us\n",
|
||||
" - can be classified into objects of the same **type** (i.e., same abstract \"structure\" but different concrete data)\n",
|
||||
" - built-in objects (incl. **literals**) vs. user-defined objects (cf., Chapter 8)\n",
|
||||
|
|
@ -3733,13 +3733,13 @@
|
|||
"\n",
|
||||
"- operators\n",
|
||||
" - special built-in symbols that perform operations with objects in memory\n",
|
||||
" - usually operate with one or two objects\n",
|
||||
" - usually, operate with one or two objects\n",
|
||||
" - e.g., addition `+`, subtraction `-`, multiplication `*`, and division `/` all take two objects whereas the negation `-` only takes one\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"- expressions\n",
|
||||
" - **combinations** of **variables** (incl. **literals**) and **operators**\n",
|
||||
" - do *not* change the involved objects / state of the program\n",
|
||||
" - do *not* change the involved objects/state of the program\n",
|
||||
" - evaluate to a **value** (i.e., the \"result\" of the expression, usually a new object)\n",
|
||||
" - e.g., `x + 2` evaluates to the (new) object `3` and `1 - 1.0` to `0.0`\n",
|
||||
"\n",
|
||||
|
|
@ -3747,7 +3747,7 @@
|
|||
"- statements\n",
|
||||
" - instructions that **\"do\" something** and **have side effects** in memory\n",
|
||||
" - re-map names to different objects and *change* the state of the program\n",
|
||||
" - usually work with expressions\n",
|
||||
" - usually, work with expressions\n",
|
||||
" - e.g., the assignment statement `=` makes a name point to an object\n",
|
||||
"\n",
|
||||
"\n",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue