diff --git a/docs/python-tutorial/chapters/02-intro-to-variables.md b/docs/python-tutorial/chapters/02-intro-to-variables.md index 9eb965d..8788148 100644 --- a/docs/python-tutorial/chapters/02-intro-to-variables.md +++ b/docs/python-tutorial/chapters/02-intro-to-variables.md @@ -86,12 +86,17 @@ Python. There are 4 simple rules which follow: Here is a list of **invalid** python variables: ```python -full name = "James Bond" # Contains a space -age! = 90 # Contains a special character -finally = "yes" # Conflicts with the Python keyword "finally" -20money = 900 # Starts with a number +full name = "James Bond" +age! = 90 +finally = "yes" +20money = 900 ``` +1. `full name` contains a space in it +1. `age!` contains a special character (`!`) +1. `finally` conflicts with the Python keyword of the same name +1. `20money` starts with a number + Below is a list of **valid** python variables: ```python diff --git a/docs/python-tutorial/chapters/05-string-functions.md b/docs/python-tutorial/chapters/05-string-functions.md new file mode 100644 index 0000000..b038dd1 --- /dev/null +++ b/docs/python-tutorial/chapters/05-string-functions.md @@ -0,0 +1,224 @@ +--- +description: String concatenation and interpolation in Python +--- + +# String Interpolation and Concatenation + +We learned what the string data type was from our [third chapter](03-data-types-pt01.md). A quick +recap: Strings are used to represent any textual data. + +We also saw how adding two inputs resulted in a different output than we expected. + +```py +num1 = input("Enter the first number: ") +num2 = input("Enter the second number: ") +result = num1 + num2 + +print("The sum of", num1, "and", num2, "is", result) +``` + +After running the program: + +```text +Enter the first number: 23 +Enter the second number: 12 +The sum of 23 and 12 is 2312 +``` + +We briefly touched on the fact that this was caused by _string concatenation_. In this chapter, we +will look at what concatenation is, and at a more powerful way of combining text and variables +called _string interpolation_. + +## Why do we need this? + +Most programs need to build sentences out of a mix of fixed text and changing data. For example, +greeting a user by name, or showing a player's score. So far, the only way we've done this is by +passing multiple values to `print`: + +```python +name = "Alan" +age = 34 + +print("My name is", name, "and I am", age, "years old.") +``` + +This works, but it only works with `print`. What if we want to, for example, store the full sentence +in a variable instead? This is where concatenation and interpolation come in. + +## String Concatenation + +Concatenation simply means joining two or more strings together, one after the other. In Python, we +can do this with the `+` operator. + +```python +first_name = "Alan" +last_name = "Turing" + +full_name = first_name + " " + last_name +print(full_name) +``` + +```text +Alan Turing +``` + +Notice that we added `" "` (a string containing a single space) in the middle. Concatenation joins +strings _exactly_ as they are, so Python will not add any spaces for us. Without it, we would get +`AlanTuring` as the output. + +### Concatenating with other data types + +Concatenation only works between strings. This means that if we try to join a string with a number, +Python will raise an error: + +```python +name = "Alan" +age = 34 + +print("My name is " + name + " and I am " + age + " years old.") +``` + +```text +TypeError: can only concatenate str (not "int") to str +``` + +Python doesn't know whether `"I am " + 34` should mean "add" or "join", so instead of guessing, it +stops with an error. To fix it, we need to convert the number to a string first. Remember type +casting from the previous chapter? We can use the `str` function for this: + +```python +name = "Alan" +age = 34 + +print("My name is " + name + " and I am " + str(age) + " years old.") +``` + +```text +My name is Alan and I am 34 years old. +``` + +## String Interpolation + +Interpolation is the process of inserting values directly into a string. Instead of breaking the +string apart and gluing the pieces back together, we write the whole sentence at once and mark the +places where the values should go. Python gives us two ways of doing this. + +### f-strings + +An f-string (short for _formatted string literal_) is a string with an `f` placed right before the +opening quote. Inside it, anything wrapped in curly braces `{}` is replaced with its value. + +```python +name = "Alan" +age = 34 + +print(f"My name is {name} and I am {age} years old.") +``` + +```text +My name is Alan and I am 34 years old. +``` + +That's the same output as before, but much easier to read and write! Also notice that we didn't need +to use `str(age)`. This is because f-strings convert the values for us automatically. + +!!! warning + + Don't forget the `f` before the quote! Without it, Python treats the string as normal text and + prints the curly braces as-is: `My name is {name} and I am {age} years old.` + +#### Expressions inside f-strings + +You can put any valid Python expression (not just variable names) inside the curly braces, and +Python will work out the result: + +```python +price = 20 +quantity = 3 + +print(f"Total cost: {price * quantity}") +``` + +```text +Total cost: 60 +``` + +#### Formatting values + +You can also control how a value is displayed by adding a colon `:` followed by a format +specification inside the braces. One of the most common uses of this is limiting the number of +decimal places of a float: + +```python +pi = 3.14159265 + +print(f"Pi is roughly {pi:.2f}") +``` + +```text +Pi is roughly 3.14 +``` + +Here, `.2f` means "show this as a float with 2 digits after the decimal point". + +### The `str.format()` method + +Before f-strings were introduced in Python 3.6, the most common way to interpolate was the `format` +method of strings. You will still see this in a lot of older code, so it is worth knowing. + +Instead of placing the variables inside the string, you leave empty curly braces `{}` as +placeholders, and pass the values to `.format()` afterwards. The values are filled in order like so: + +```python +name = "Alan" +age = 34 + +print("My name is {} and I am {} years old.".format(name, age)) +``` + +```text +My name is Alan and I am 34 years old. +``` + +You can also number the placeholders to control which value goes where, or give them names: + +```python +# Using positions +print("{1} is {0} years old.".format(age, name)) + +# Using names +print("{n} is {a} years old.".format(n=name, a=age)) +``` + +!!! note + + Anything after a `#` on a line is a comment. Comments are notes for humans reading the code, so + Python ignores them completely. + +It's output: + +```text +Alan is 34 years old. +Alan is 34 years old. +``` + +## Which one should I use? + +All three approaches produce the same kind of result: a new string. Here's a quick comparison using +the same example. + +```python +name = "Alan" +age = 34 + +print("My name is " + name + " and I am " + str(age) + " years old.") # concatenation +print("My name is {} and I am {} years old.".format(name, age)) # str.format() +print(f"My name is {name} and I am {age} years old.") # f-string +``` + +Here are some general rules for their usage. + +- Use **f-string** interpolation for most situations. They are the shortest, the most readable, and + the most common way to write modern Python. +- Use **concatenation (`+`)** for simple cases where you want to join two strings only. +- **`str.format()`** when you are reading older code. diff --git a/docs/python-tutorial/chapters/06-operators-pt01.md b/docs/python-tutorial/chapters/06-operators-pt01.md new file mode 100644 index 0000000..f18fbc0 --- /dev/null +++ b/docs/python-tutorial/chapters/06-operators-pt01.md @@ -0,0 +1,445 @@ +--- +description: Comparison and Arithmetic Operators in Python. +--- + +# Comparison and Arithmetic Operators + +A quick revision of the concepts we have learned so far: + +- Brief on Python history +- Variables +- Data types (strings, integers, floats, booleans) +- Built in functions +- String concatenation & interpolation + +In this chapter, we will be looking at what comparison and arithmetic operations are. + +## Comparison Operators + +Comparison Operators (also known as Relational Operators) are used to compare values. They work very +similarly to how they do in mathematics. + +There are six comparison operators: + +| Operator Symbol | Name | +| ---------------- | ----------------------------- | +| `>` | Greater than | +| `<` | Less than | +| `==` | Equal to | +| `!=` | Not equal to | +| `>=` | Greater than or equal To | +| `<=` | Less than or equal to | + +Comparison operators always return a boolean value (`True` or `False`) when used. + +
+ +![Image title](/static/python-tutorial/06-operators.png){ width="640" } + +
+ Either side of an operator is what we call an operand. An operator is a symbol that performs an action on values, called operands. +
+ +
+ +### Greater Than Operator (`>`) + +Checks if the left-hand side operand is larger than the right-hand side operand. + +```python +print(1 > 2) +print(20 > 1) +print(3.2 > 9) +``` + +Running this will give us the following output: ```text False True False ``` + +This reads almost like plain English! 1 is not greater than 2, hence it returns `False` and prints +it out. 20 is larger than 1, which results in `True` being the output, and so on. + +### Less Than Operator (`<`) + +Checks if the right-hand side operand is larger than the left-hand side operand. + +```python +print(3 < 9) +print(200 < 100) +print(23.12 < 9) +``` + +Output: + +```text +True +False +False +``` + +### Equal To Operator (`==`) + +Checks if both left and right-hand side operands are exactly equal. + +```python +print(123 == 321) +print(909 == 909) +print(812 == 22) +``` + +Output: + +```text +False +True +False +``` + +!!! warning + + Do not confuse the Equal To Operator (`==`) with the Assignment Operator (`=`). The Equal To + Operator is used to check if both the operands are equal, whereas the Assignment Operator is used to + assign data to a variable. + +### Not Equal To Operator (`!=`) + +Checks if both the operands are _not_ equal. + +```python +print(10 != 10) +print(3 != 4) +print(3 != 8) +``` + +Output: + +```text +False +True +True +``` + +### Greater Than Or Equal To Operator (`>=`) + +Checks if the left-hand side operand is either greater than or equal to the right-hand side operand. + +```python +print(90 >= 18) +print(23 >= 32) +print(1 >= 0) +``` + +Output: + +```text +True +False +True +``` + +Here, 90 is greater than 18 which gives us `True` as the output. 23 is not greater but it is equal +to 23 which also gives us `True` as the output. + +### Less Than Or Equal To Operator (`<=`) + +Checks if the right-hand side operand is either greater than or equal to the left-hand side operand. + +```python +print(4 <= 18) +print(9 <= 3) +print(10 <= 10) +``` + +Output: + +```text +True +False +True +``` + +### Comparison with Strings + +Comparison operators aren't limited to numbers. They work with strings too. The most common use is +checking whether two strings are equal: + +```python +print("Alan" == "Alan") +print("Alan" != "James") +``` + +Output: + +```text +True +True +``` + +!!! warning + + String comparison is case sensitive, so `"alan"` and `"Alan"` are **not** equal: + +```python +print("alan" == "Alan") +``` + +Output: + +```text +False +``` + +Python compares strings character by character, so even a single difference, including an extra +space, makes the strings unequal. + +??? note "Using `<` and `>` with strings" + + The other operators work on strings as well. Python compares strings alphabetically, character by + character, so `"apple" < "banana"` is `True` because `"a"` comes before `"b"`. + + Be careful with uppercase and lowercase, though. Every uppercase letter is considered "smaller" than + every lowercase letter, so `"Zebra" < "apple"` is `True`. + +## Arithmetic Operators + +Arithmetic operators let us perform mathematical calculations in Python. You've already seen one of +them, the `+` operator, in our calculator example. Python supports seven of them: + +| Operator | Name | Example | Result | +| -------- | -------------- | -------- | ------ | +| `+` | Addition | `7 + 2` | `9` | +| `-` | Subtraction | `7 - 2` | `5` | +| `*` | Multiplication | `7 * 2` | `14` | +| `/` | Division | `7 / 2` | `3.5` | +| `//` | Floor Division | `7 // 2` | `3` | +| `%` | Modulus | `7 % 2` | `1` | +| `**` | Exponentiation | `7 ** 2` | `49` | + +Let's take a look at each of them. + +### Addition, Subtraction & Multiplication + +These three work exactly as they do in mathematics: + +```python +apples = 10 +oranges = 4 + +print(apples + oranges) +print(apples - oranges) +print(apples * oranges) +``` + +```text +14 +6 +40 +``` + +!!! note + + Notice that we use `*` for multiplication, not `x`. The same goes for division, where we use `/` + instead of `÷`. + +### Division + +The `/` operator divides the left value by the right value: + +```python +print(10 / 4) +print(10 / 5) +``` + +```text +2.5 +2.0 +``` + +Notice that the second result is `2.0` and not `2`. In Python, the `/` operator **always** returns a +float, even when the result is a whole number. + +!!! warning + + Dividing by zero is not possible, in Python or in mathematics. If you try, Python will stop your + program with a `ZeroDivisionError`. + +### Floor Division + +Floor division (`//`) divides the left value by the right value, and then rounds the result **down** +to the nearest whole number. In other words, it throws away the decimal part: + +```python +print(7 // 2) +print(10 // 3) +``` + +```text +3 +3 +``` + +This is useful when you only care about how many _complete_ times a number fits into another. For +example, how many full hours are in 150 minutes: + +```python +minutes = 150 +print(minutes // 60) +``` + +Output: + +```text +2 +``` + +??? note "Floor division and negative numbers" + + Floor division always rounds **down**, toward negative infinity. With positive numbers this looks + like the decimal part is simply cut off, but with negative numbers it behaves differently: + + ```python + print(7 // 2) + print(-7 // 2) + ``` + + Output: + + ```text + 3 + -4 + ``` + + `-7 / 2` is `-3.5`. Rounding down means moving to the next smaller number, which is `-4`, not `-3`. + +### Modulus + +The modulus operator (`%`) gives us the **remainder** left over after division. Remember long +division from school? `7 ÷ 2` is `3` with a remainder of `1`, so `7 % 2` is `1`: + +```python +print(7 % 2) +print(10 % 3) +print(10 % 5) +``` + +```text +1 +1 +0 +``` + +If we continue our minutes example, `%` tells us how many minutes are _left over_ after taking out +the full hours: + +```python +minutes = 150 +print(minutes // 60) # full hours +print(minutes % 60) # leftover minutes +``` + +```text +2 +30 +``` + +So 150 minutes is 2 hours and 30 minutes. + +### Exponentiation + +The `**` operator raises the left value to the power of the right value: + +```python +print(2 ** 3) +print(5 ** 2) +``` + +```text +8 +25 +``` + +`2 ** 3` means `2 * 2 * 2`, which is `8`. + +## Order of Operations + +When an expression has more than one operator, Python follows the same order of operations you +learned in mathematics (often remembered as PEMDAS or BODMAS). Operators with the same priority are +evaluated from left to right. Let's see it in action: + +```python +print(2 + 3 * 4) +print((2 + 3) * 4) +``` + +```text +14 +20 +``` + +In the first line, multiplication happens before addition, so `3 * 4` is calculated first, giving +`2 + 12`. In the second line, the parentheses force `2 + 3` to be calculated first, giving `5 * 4`. + +!!! tip + + When in doubt, use parentheses. Even if they aren't needed, they make your code easier to read and + make sure the calculation happens in the order you intended. + +## Mixing Integers and Floats + +When you do arithmetic between an integer and a float, the result will always be a float: + +```python +print(5 + 2.0) +print(3 * 1.5) +``` + +```text +7.0 +4.5 +``` + +## In-place Operations + +It's very common to update a variable using its own value, such as adding to a score: + +```python +score = 10 +score = score + 5 +print(score) +``` + +```text +15 +``` + +Python provides a shorter way of writing this. Placing the operator before the `=` does the same +thing: + +```python +score = 10 +score += 5 +print(score) +``` + +```text +15 +``` + +`score += 5` is exactly the same as `score = score + 5`. This works with all of the arithmetic +operators: + +```python +number = 100 + +number -= 20 # number = number - 20 +number *= 2 # number = number * 2 +number /= 4 # number = number / 4 +number %= 10 # number = number %= 10 +number += 1 # number = number + 1 + +print(number) +``` + +Output: + +```text +1.0 +``` diff --git a/docs/python-tutorial/chapters/07-conditional-statements.md b/docs/python-tutorial/chapters/07-conditional-statements.md new file mode 100644 index 0000000..bba9c2d --- /dev/null +++ b/docs/python-tutorial/chapters/07-conditional-statements.md @@ -0,0 +1,703 @@ +--- +description: Conditional Statements and Control Flow in Python. +--- + +# Conditional Statements + +When developing programs, we often need our code to execute certain instructions _conditionally_. +Let's take a simple banking program as an example. + +Our task is to ask the user how much money they have so they can open a bank account. If they have +less than `$25`, we print a message declining the request. If they have `$25` or more, we accept the +money and deposit it into their new account. + +One way of doing this problem is like so: + +```python +bank_amount = 0 + +print("Welcome to Practical Python Bank!") +print("Let's open you an account!") + +current_amount = int(input("How much money do you have (in dollars)? ")) +# Don't forget to convert user input to an integer +# so we can compare it with another integer. + +if current_amount >= 25: + bank_amount += current_amount + current_amount = 0 + + print("You have successfully opened a bank account!") + print("All your money has been deposited.") + print(f"You have ${bank_amount} in your account.") + +else: + print("Sorry, you cannot open an account.") + print("You need at least $25 to open a bank account.") +``` + +Running the program and entering a number below 25 gives us: + +``` +Welcome to Practical Python Bank! +Let's open you an account! +How much money do you have (in dollars)? 10 +Sorry, you cannot open an account. +You need at least $25 to open a bank account. +``` + +Now let's enter a value of 25 or more: + +``` +Welcome to Practical Python Bank! +Let's open you an account! +How much money do you have (in dollars)? 25 +You have successfully opened a bank account! +All your money has been deposited. +You have $25 in your account. +``` + +!!! warning + + When entering input, type only the number itself, with no `$` symbol or other characters. The + `int()` function can only convert strings that look like whole numbers (such as `"25"`), so text or + symbols (such as `"$25"` or `"twenty"`) will make it fail with an error. The same applies to + `float()`, which accepts numbers like `"12.5"`. + +The code almost reads like plain English! If you don't understand what's going on immediately, it's +alright. We'll take it apart and see what each piece is doing. First, the `if` statement. + +## `if` Condition Statement + +This is the starting block of any conditional statement. Its general syntax is: + +``` +if : + +``` + +!!! note + + In programming, syntax refers to the grammar of a language. Just as grammar lets us form coherent + sentences in human languages, syntax tells the computer how to read our code. + +The `if` condition statement only runs the `` within it when the `` is `True`. Here's +an example: + +```python +if True: + print("Hi") + print("Running from the True statement") + print("Good bye!") + +if False: + print("Hello") + print("Running from the False statement") + print("See you later!") +``` + +Upon running this code, we get the following output: + +```text +Hi +Running from the True statement +Good bye! +``` + +The code within the `if False:` statement never ran. + +One important thing you may have noticed so far is the indentation (the four spaces in front of each +`print` calls). In Python, indentation is what tells the computer that "this block of code belongs +to this statement". + +
+ +![Conditional Statements](/static/python-tutorial/07-conditional-statements-01.png){ width="640" } + +
+ +A quick way to remember when you need to apply indentation is to look out for colons (`:`). If a +statement ends with a colon, it means that the next line must be indented one level further. Python +recommends 1 indent to consist of 4 spaces. + +!!! warning + + You can press the ++tab++ key to place indents in your code. Depending on the code editor you use, + it can either place spaces or a single tab character. If your editor places a tab character, make + sure to change it to spaces. + +From the previous chapter, we have learned about how comparison operators return a bool. The same +concept is being used here. Let's take a look at an example and an animation that explains how it +works. + +```python +print("Program start") + +age = 15 + +if age >= 18: + print("Is an adult") + +if age >= 13: + print("Is a teenager") + +print("Program end") +``` + +When you run your code, this is how Python will interpret it: + +
+ +![Image title](/static/python-tutorial/07-conditional-statements-02.gif){ width="640" } + +
+ +```text +Program start +Is a teenager +Program end +``` + +!!! note + + This program isn't perfect. There are some glaring issues; can you notice them before we fix it in + the next subtopics? + +## `else` Condition Statement + +The else statement runs when the condition of the if directly above it is False. Its general syntax +is: + +```text +if : + +else: + +``` + +`` only executes when the `` of the `if` statement is `False`. Let's look at a few +examples to get familiar with it. + +=== "Example 1" + + ```python + if False: + print("if statement executed") + else: + print("else statement executed") + ``` + + Output: + + ```text + else statement executed + ``` + +=== "Example 2" + + ```python + if False: + print("if statement 1 executed") + if False: + print("if statement 2 executed") + else: + print("else statement executed") + ``` + + Output: + + ```text + else statement executed + ``` +=== "Example 3" + + ```python + if True: + print("if statement 1 executed") + if False: + print("if statement 2 executed") + else: + print("else statement executed") + ``` + + Output: + + ```text + if statement 1 executed + else statement executed + ``` + +=== "Example 4" + + ```python + if True: + print("if statement 1 executed") + if True: + print("if statement 2 executed") + else: + print("else statement executed") + ``` + + Output: + + ```text + if statement 1 executed + if statement 2 executed + ``` + +=== "Example 5" + + ```python + if 5 > 1: + print("Five is greater than one") + else: + print("Five is not greater than one") + ``` + + Output: + + ```text + Five is greater than one + ``` + +--- + +!!! note + + An `else` always belongs to the `if` directly above it, and it can't stand on its own. Writing an + `else` without an `if` before it raises a `SyntaxError`. + +Now that we are familiar with its syntax, let's take a look at our example from the previous +section. + +```python +print("Program start") + +age = 15 + +if age >= 18: + print("Is an adult") + +if age >= 13: + print("Is a teenager") + +print("Program end") +``` + +You may have noticed a few problems with it. If not, assume `age` is `7` instead. What would be the +output then? Once you have figured it out, check your answer in the collapsible block below: + +??? note "Output" + + ```text + Program start + Program end + ``` + +### Fixing our age program (v1) + +As you can see, that is _not_ the output we'd like. We would still want the program to print +_something_. This is where our `else` statement can help us. + +```python +print("Program start") + +age = 7 + +if age >= 18: + print("Is an adult") + +if age >= 13: + print("Is a teenager") + +else: + print("Is below 13") + +print("Program end") +``` + +Output: + +```text +Program start +Is below 13 +Program end +``` + +Our program still isn't perfect. Try finding the issue by tweaking the value of the `age` variable. + +## Nesting Conditional Statements + +An `if` or `else` block can contain any code, including other `if` and `else` statements. Placing a +conditional statement inside another one is called **nesting**. The inner statement only gets +checked if the outer one allows its block to run. + +Our previous example still had one problem in it. What if the `age` variable was, let's say, 25? + +```python +print("Program start") + +age = 25 + +if age >= 18: + print("Is an adult") + +if age >= 13: + print("Is a teenager") + +else: + print("Is below 13") + +print("Program end") +``` + +Its output would be: + +```text +Program start +Is an adult +Is a teenager +Program end +``` + +This is wrong again. We would like the program to only print out `Is an adult` for ages `18` and +above. But that doesn't seem to be the case since the age satisfies both conditions. + +Let's look at how nested conditional statements helps solve this with different values. + +### Fixing our age program (v2) + +=== "For age = 25" + + ```python + print("Program start") + + age = 25 + + if age >= 18: + print("Is an adult") + else: + if age >= 13: + print("Is a teenager") + else: + print("Is below 13") + + print("Program end") + ``` + +
+ + ![Nested Statements 01](/static/python-tutorial/07-conditional-statements-03.gif){ width="640" } + +
+ + Gives us the output: + + ``` + Program start + Is an adult + Program end + ``` + +=== "For age = 15" + + ```python + print("Program start") + + age = 15 + + if age >= 18: + print("Is an adult") + else: + if age >= 13: + print("Is a teenager") + else: + print("Is below 13") + + print("Program end") + ``` + +
+ + ![Nested Statements 2](/static/python-tutorial/07-conditional-statements-04.gif){ width="640" } + +
+ + Output: + + ``` + Program start + Is a teenager + Program end + ``` + +--- + +!!! note + + There's no limit to how deeply you can nest statements, but each level adds more indentation and + makes the code harder to follow. If you find yourself nesting more than two or three levels deep, + there is usually a cleaner way to write it. We'll look at one in the next section. + +## `elif` Statement + +The `elif` statement is a combination of `else` and `if` with a cleaner syntax. As always, let's +have a look at its syntax: + +```text +if : + +elif : + +``` + +`` only executes when the `` of the `if` is `False` **and** the `` of the +`elif` is `True`. + +In a series of regular `if` statements, each statement is independent of the others. But `if`- and +`elif`-statements are dependent on each other. This is because the pseudocode above is the same as: + +```text +if : + +else: + if : + +``` + +Remember the `else:` followed by an indented `if` from our nested example? `elif` is just a shorter +way of writing it. + +### Fixing our age program (v3) + +Let's rewrite our age program using `elif`: + +```python +print("Program start") + +age = 25 + +if age >= 18: + print("Is an adult") +elif age >= 13: + print("Is a teenager") +else: + print("Is below 13") + +print("Program end") +``` + +This does exactly the same thing as our nested version, but with no extra indentation. + +Take `age = 25`. Python checks `age >= 18`, finds it `True`, and runs that block. It then skips the +`elif` and `else` entirely, without even checking `age >= 13`. With `age = 15`, the first condition +is `False`, so Python moves on to the `elif`, which is `True`, so it runs that block and skips the +`else`. Only when every condition above is `False` does the `else` run. + +### Using multiple `elif` statements + +You can chain as many `elif` statements as you need between the `if` and the `else`: + +```text +if : + +elif : + +elif : + +else: + +``` + +Python checks the conditions from top to bottom, and runs the block of the **first** condition that +is `True`. Every other block in the chain is skipped, even if its condition would also have been +`True`. Let's take a grading program as an example: + +```python +score = 85 + +if score >= 90: + print("Grade: A") +elif score >= 80: + print("Grade: B") +elif score >= 70: + print("Grade: C") +else: + print("Grade: F") +``` + +Output: + +```text +Grade: B +``` + +A score of `85` is also greater than or equal to `70`, but Python never gets that far. It stops at +the first `True` condition, `score >= 80`. + +!!! warning + + Because Python stops at the first `True` condition, the **order** of your conditions matters. What + do you think happens if we check the smaller age first? + + ```python + age = 25 + + if age >= 13: + print("Is a teenager") + elif age >= 18: + print("Is an adult") + ``` + + Output: + + ```text + Is a teenager + ``` + + `25 >= 13` is `True`, so Python runs the first block and never reaches `age >= 18`. The adult block + can never run for any value. When using ranges like this, check the most specific (or highest) + condition first. + +### `if` vs `elif` + +Let's compare the two with the same value, `age = 25`: + +=== "Separate `if` statements" + + ```python + age = 25 + + if age >= 18: + print("Is an adult") + if age >= 13: + print("Is a teenager") + ``` + + Output: + + ```text + Is an adult + Is a teenager + ``` + +=== "`if` and `elif`" + + ```python + age = 25 + + if age >= 18: + print("Is an adult") + elif age >= 13: + print("Is a teenager") + ``` + + Output: + + ```text + Is an adult + ``` + +--- + +With separate `if` statements, every condition is checked on its own, so more than one block can +run. With `elif`, the chain stops after the first match. Use separate `if` statements when the +checks are unrelated, and `elif` when you want exactly one outcome out of several. + +!!! note + + A conditional chain follows these rules: + + - It must start with exactly one `if`. + - It can have as many `elif` statements as you need, all placed after the `if`. + - It can end with at most one `else`, which is optional and always comes last. + + An `elif` or `else` without an `if` before it raises a `SyntaxError`. + +## Truthy and Falsy Values + +In Python, every value can be treated as a bool. Values that aren't actually a bool are considered +either truthy (they behave like `True`) or falsy (they behave like `False`). Let's take a +look at what exactly makes a value one or the other. + +Any non-empty string, or in the case of integers and floats, any number other than `0`, is +considered truthy. + +The opposite is true for falsy values. An empty string, or the number `0` (or `0.0`), is considered +falsy. + +We can confirm this by using the `bool()` function. It takes in a value of any data type and +converts it into a bool, following the rules above. This is type casting again, just like `int()` +and `str()`. + +```python +print(bool(100)) +print(bool(-330)) +print(bool(0)) + +print() # Prints out an empty line + +print(bool(0.0)) +print(bool(0.1)) + +print() + +print(bool("This is a non-empty string.")) +print(bool("")) +print(bool("0")) # This is a string, and it's non-empty. +``` + +Its output is as follows: + +```text +True +True +False + +False +True + +True +False +True +``` + +!!! warning + + The string `"0"` is **truthy**, even though the number `0` is falsy. Only a completely empty + string (`""`) is falsy. The same goes for `"False"`, which is just text, and a string containing + only a space (`" "`). + +### Using truthy and falsy values in conditions + +So far, we have placed bools and comparisons (like `age >= 18`) after an `if`. But an `if` statement +actually accepts _any_ value and implicitly converts it into a bool. This lets us skip the comparison +in some cases. + +A common use is checking whether the user typed anything at all: + +```python +name = input("Enter your name: ") + +if name: + print(f"Hello, {name}!") +else: + print("You didn't enter a name.") +``` + +If the user types `Alan`, `name` is `"Alan"`, which is a non-empty string and therefore, truthy: + +```text +Enter your name: Alan +Hello, Alan! +``` + +If the user just presses ++enter++, `name` is `""`, which is falsy, so the `else` block runs: + +```text +Enter your name: +You didn't enter a name. +``` + +This is the same as writing `if name != "":`, only shorter. Both are correct, so use whichever you +find easier to read. diff --git a/docs/python-tutorial/chapters/index.md b/docs/python-tutorial/chapters/index.md index 7a6f00c..efb24c5 100644 --- a/docs/python-tutorial/chapters/index.md +++ b/docs/python-tutorial/chapters/index.md @@ -12,10 +12,10 @@ in-depth Python features. - [Brief Python History](01-python-history.md) - [Introduction to Variables](02-intro-to-variables.md) - [Data Types pt 1 (`string`, `int`, `float` & `bool`)](03-data-types-pt01.md) -- [Builtin Functions pt 1 (`print` & `input` and type casting)](04-built-in-functions-pt01.md) -- String Interpolation & Concatenation (f-strings, str.format & +) -- Operators pt 1 (Comparison & Arithmetic) -- Conditional Statements (`if`, `else` & `elif`) +- [Builtin Functions pt 1 (`print`, `input` & type casting)](04-built-in-functions-pt01.md) +- [String Interpolation & Concatenation (f-strings, `str.format` & `+`)](05-string-functions.md) +- [Operators pt 1 (Comparison & Arithmetic)](06-operators-pt01.md) +- [Conditional Statements (`if`, `else` & `elif`)](07-conditional-statements.md) - Operators & Conditional Statements pt 2 (Logical operators) - Data Types pt 2 (`list` & `tuple`) - Data Types pt 3 (dictionary) diff --git a/docs/static/python-tutorial/02-memory.png b/docs/static/python-tutorial/02-memory.png index bbd145b..e4f1031 100644 Binary files a/docs/static/python-tutorial/02-memory.png and b/docs/static/python-tutorial/02-memory.png differ diff --git a/docs/static/python-tutorial/06-operators.png b/docs/static/python-tutorial/06-operators.png new file mode 100644 index 0000000..9eb8932 Binary files /dev/null and b/docs/static/python-tutorial/06-operators.png differ diff --git a/docs/static/python-tutorial/07-conditional-statements-01.png b/docs/static/python-tutorial/07-conditional-statements-01.png new file mode 100644 index 0000000..78f2761 Binary files /dev/null and b/docs/static/python-tutorial/07-conditional-statements-01.png differ diff --git a/docs/static/python-tutorial/07-conditional-statements-02.gif b/docs/static/python-tutorial/07-conditional-statements-02.gif new file mode 100644 index 0000000..b9a6085 Binary files /dev/null and b/docs/static/python-tutorial/07-conditional-statements-02.gif differ diff --git a/docs/static/python-tutorial/07-conditional-statements-03.gif b/docs/static/python-tutorial/07-conditional-statements-03.gif new file mode 100644 index 0000000..ce71136 Binary files /dev/null and b/docs/static/python-tutorial/07-conditional-statements-03.gif differ diff --git a/docs/static/python-tutorial/07-conditional-statements-04.gif b/docs/static/python-tutorial/07-conditional-statements-04.gif new file mode 100644 index 0000000..1504032 Binary files /dev/null and b/docs/static/python-tutorial/07-conditional-statements-04.gif differ diff --git a/zensical.toml b/zensical.toml index 74bf513..2773037 100644 --- a/zensical.toml +++ b/zensical.toml @@ -25,6 +25,9 @@ nav = [ "python-tutorial/chapters/02-intro-to-variables.md", "python-tutorial/chapters/03-data-types-pt01.md", "python-tutorial/chapters/04-built-in-functions-pt01.md", + "python-tutorial/chapters/05-string-functions.md", + "python-tutorial/chapters/06-operators-pt01.md", + "python-tutorial/chapters/07-conditional-statements.md", ] }, { "Resources" = [ "resources/index.md",