Streamline text

This commit is contained in:
Alexander Hess 2020-02-02 22:27:49 +01:00
parent 18a0ee7c4c
commit 522eeb1b43
2 changed files with 77 additions and 77 deletions

View file

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

View file

@ -33,9 +33,9 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q1.1**: Read about the [print()](https://docs.python.org/3/library/functions.html#print) built-in. How can you use it to print both `greeting` and `audience` *without* concatenating the two strings with the `+` operator?\n",
"**Q1**: Read the documentation on the built-in [print()](https://docs.python.org/3/library/functions.html#print) function! How can you use it to print both `greeting` and `audience` *without* concatenating the two strings with the `+` operator?\n",
"\n",
"Hint: The `*objects` in the documentation implies that we can insert several comma-seperated variables."
"Hint: The `*objects` in the documentation implies that we can insert several *comma-seperated* variables."
]
},
{
@ -61,7 +61,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q1.2**: What does the `sep=\" \"` mean in the documentation? Use it to print out the three names in `first`, `second`, and `third` on one line seperated by commas with one [print()](https://docs.python.org/3/library/functions.html#print) statement."
"**Q2**: What does the `sep=\" \"` mean in the documentation? Use it and print out the three names in `first`, `second`, and `third` on one line seperated by *commas* with only *one* call of the [print()](https://docs.python.org/3/library/functions.html#print) function!"
]
},
{
@ -88,7 +88,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
"**Q1.3**: Lastly, what does the `end=\"\\n\"` mean in the documentation? Use it in the `for`-loop to print the numbers 1 through 10 in just one line."
"**Q3**: Lastly, what does the `end=\"\\n\"` mean in the documentation? Use it in the `for`-loop and print the numbers 1 through 10 in just *one* line!"
]
},
{