## Motivating Example for Learning Python Conditionals, Logicals & Loops

Again we find ourselves in the role of a teacher in a class on geography. Each of your five students picked a country, and the following table was prepared based on their reports. Once again, Marie did not turn in her report.

Student Country GDP (billion USD) Population In Africa?
Mary Luxembourg 64.2 602005 False
Matthew Eritrea 6.856 4954645 True
Marie None None None None
Manuel Lesotho 2.721 2203821 True
Malala Poland 614.190 38433600 False

In the previous tutorials, we checked values or lists of values manually. With the skills we’ll develop in this tutorial, we will automate processing items in the table to eliminate missing elements and summarize the given information.

## Introduction to Logicals, Conditionals & Loops

This introduction will walk through the basics of Python conditionals and logical expressions, including `if` statements and examples of their use with various data types. The section on loops will cover the basics of looping operations using Python’s `while` and `for` loops, and the simpler comprehensions. We will walk through the basics of Python flow control, specifically covering the following:

Want us to make more free Python tutorials? Share this article on Facebook and Twitter! When you spread the word on social media, you’re helping us grow so we can continue to provide free tutorials like this one for years to come.

I put together a Python Developer Kit with over 100 pre-built Python scripts covering data structures, Pandas, NumPy, Seaborn, machine learning, file processing, web scraping and a whole lot more - and I want you to have it for free. Enter your email address below and I'll send a copy your way.

Yes, I'll take a free Python Developer Kit

## Python Logicals and Conditionals

This section will focus on the way Python processes logical through the use of `if` statements, Boolean operators, and other logical tests.

### Boolean Operations & Value Comparisons

Operations on Python’s data types (Boolean, numeric, string, etc.) can be used to compare object values and perform logical operations. The following table contains Python’s logical operators:

Operator Operation
Equivalence (Equals) ==
Not Equal !=
Greater Than >
Less Than <
Greater Than or Equal To >=
Less Than or Equal To <=
And and
Or or
not not

Note that equivalence is defined as two equals signs `==`, whereas assignment uses a single equals sign `=`. In other words, you use two equal signs to compare values and you use one equal sign to set a value equal to something.

### Python Order of Operations

The following list is the order of operations from greatest precedence to lowest. Precedence just means the order in which the operations are processed. Items in the same group are evaluated in-line left to right.

1. Parenthetical partitions: `()`, `[]`, and `{}`
2. `in`, `not in`, `is`, `is not`, `<`, `<=`, `>`, `>=`, `!=`, and `==`
3. `not`
4. `and`
5. `or`

Python evaluates the `and` statement using the shortcut technique of evaluating the statement on its left and determining if the output should be `False` prior to evaluating the right side. If the left side is `False`, then the right side is not evaluated and `False` is returned. For example:

``````print(None and False)
> None
print(False and None)
> False``````

Notice in the above statement that when a `None` object is evaluated with an `and` or `or` statement, the result will be a `None`. This is because Python will return the final evaluated argument for `and` or `or`:

``````print(True and "best")
> 'best'
print(False or "best")
> 'best'``````

### Compound Comparisons

Python allows the use of compound value comparisons such as `a < x < b` which is equivalent to `(a < x) and (x < b)`. For example:

``````x = 5
1 <= x < 10
> True
x = 10
1 <= x < 10
> False``````

### Identity Comparisons: is Operator

One point of confusion to beginners of Python is the difference between the equivalence operator `==` and the object comparison operator `is`. If used to compare values, the two will behave identically:

``````15 == 15
> True
15 is 15
> True``````

However, this property can break down when comparing variables:

``````a = [1, 2, 3]
b = [1, 2, 3]
a == b
> True
a is b
> False``````

The reason is that `==` compares the value of the two given objects, and `is` compares the two objects themselves. Each object possesses its own unique identifier, which may be thought of as the object’s location in memory. Using the `id(object)` function we can determine the id’s of `a` and `b`:

``````id(a) # Note these values may be different on your device
> 1393032855176
id(b)
> 1393032854856``````

The object id’s of `a` and `b` are different, therefore `a is b` returned false. The values of the two objects are the same; they contain the same lists, therefore `a == b` returns true.

### Membership Tests: in Operator

The `a in b` operator tests the membership of `a` within a given set `b`. The given set can be any sequence (list, tuple, string, etc.). If `b` is a string, then the expression will determine if `a` is a substring of `b`.

``````a = [1, 2, 3]
b = "The best of times."
1 in a
> True
4 in a
> False
"best" in b
True``````

### Conditional Expressions: if Statements

If statements follow the format: `if [condition]: [action]`. If the condition evaluates to `True`, the the action is performed. If statements are standard in all programming languages, therefore this introduction will focus on Python’s implementation.

If statements can be either in-line for short tests, or can be extended over multiple lines.

``````if (1 < 2): print("That's true!")
> That's true!``````

If extended over multiple lines, Python uses tabs (or 4 spaces) to determine what lines are to be included in the `[action]` execution. If a Python terminal is used, then any line following a line ending with a colon `:` will start an additional line beginning with `...` and a tab to indicate that a further lines are included in `[action]`.

``````if (1 < 2): # Script style
a = 15
print(a)
> 15``````
``````>>> if (1 < 2): # Terminal style
...     a = 15
...     print(a)
...     # Extra line for additional input. If left blank, the entire block is run
> 15``````

``````if (1 < 2): # Script style
a = 15
if (a == 15):
b = 42
print(b)
print(a)
> 42
> 15``````

To evaluate multiple exclusive `[condition]` statements, the `elif` and `else` statements can be used. These statements have the following form:

``````if [condition 1]:
[action 1]
elif [condition 2]:
[action 2]
... # Additional elif statements can be inserted
else:
[Else action] # Else action is performed if none of the previous statements are true``````

If any previous previous `if` or `elif` `[condition]` does not evaluate to True, the the `else` `[action]` will be performed. Python does not include a native `case` statement, as multiple `elif` statements is equivalent to a `case` statement.

Suppose for the following example the following `if` block is constructed:

``````if x == 1:
print("a")
elif x == 2:
print("b")
elif x == 3:
print("c")
else:
print("None of the above.")``````

If the `x` variable has an assignment prior to the above `if` statement block, then the following output will occur:

``````x = 1
... # Above if block
> 'a'
x = 2
... # Above if block
> 'b'
x = 5
... # Above if block
> 'None of the above.'``````

If any one of the `if` or `elif` conditions does evaluate to true, then the remaining `elif` of `else` statements in the block will be ignored. For example:

``````x = 12
if [x == 12]:
print("a")
elif [x > 10]:
print("b")
> 'a'``````

Notice in the above code that the `elif` statement was ignored, despite its condition evaluating to true. If multiple condition evaluations need to occur, then multiple `if` statements should be used:

``````x = 12
if x == 12:
print("a")
if x > 10:
print("b")
> 'a'
> 'b'``````

I put together a Python Developer Kit with over 100 pre-built Python scripts covering data structures, Pandas, NumPy, Seaborn, machine learning, file processing, web scraping and a whole lot more - and I want you to have it for free. Enter your email address below and I'll send a copy your way.

Yes, I'll take a free Python Developer Kit

## Python Loops

Python’s loop control flows allow for the performance of a given action while a conditional expression holds true. In general loops follow the ` [loop] [condition]: [action]` format, where the `[loop]` type performs a calculation for the `[condition]` expression that, while true, will perform the `[action]`.

### while Loops

The simplest application of the `[loop] [condition]: [action]` format is the `while` loop, which will continue to perform the `[action]` while the `[condition]` holds at the start of the loop. Like `if` statements, the `[action]` statement can be extended over multiple lines using tabs (or 4 spaces). For example:

``````x = True
while x:
a = 15
print(a)
x = False # Setting x to false will cause the [condition] to fail
> 15``````

`while` can be extended over multiple iterations using counters:

``````x = 1
while (x <= 15):
x += x
print(x)
> 2
> 4
> 8
> 16``````

In the above example, the `x` variable is initially set to 1, and for each iteration of the `while` loop `x` is doubled and printed. At the end of the loop where `x` is 16, the condition `(x <= 15)` fails and the loop is exited.

Caution: If variables used within `condition` statement are not modified in the body of the loop, then an infinite loop can occur.

### for Loops

`for` loops behave similar to `while` loops, however they have the form `for [variable] in [sequence]: [action]`. The `for` loop initializes the `[variable]` to be the first element of the given ordered `[sequence]`, and will update the `[variable]` to be the next value of the sequence after the loop has completed an iteration. When all elements in the sequence have been exhausted, the loop will complete. For example:

``````for i in [0, 1, 2, 3, 4]:
print(i)
> 0
> 1
> 2
> 3
> 4``````

As you can see from the above code, the `i` variable takes on a different value within the given list at each iteration of the `print` statement. Any of the ordered data structures we discussed previously can be used as a sequence, and sequences do not have to contain only numbers:

``````for i in ("The", "best", "of", "times."): # Tuple of strings
print(i)
> The
> best
> of
> times.``````

The `[variable]` statement can also be used to “catch” tuples:

``````for (i, j) in [("The", "best"), ("of", "times.")]: # List of string tuples
print(i + " " + j)  # + will concatenate strings
> The best
> of times.``````

A string is also an acceptable sequence:

``````for i in "abcd":
print(i)
> a
> b
> c
> d``````

The most common form of `for` loops are those in which an integer is increased or decreased over a given range, like in our first example. Rather than preparing a list containing each of the integers, the `range(a, b, k)` function can be used to iterate over the range `[a,b)` in steps of `k`. If `b` is not included, the default will be 0, and if `k` is not included, the default will be 1.

``````for i in range(5): # Note that 5 will not be included
print(i)
> 0
> 1
> 2
> 3
> 4``````
``````for i in range(0, 20, 5):
print(i)
> 0
> 5
> 10
> 15``````

`range` will also accept negative ranges and steps for counting down. In this case, the range `(b,a]` in reverse order will be output.

``````for i in range(5, 0, -1):
print(i)
> 5
> 4
> 3
> 2
> 1``````

### Implicit Loops: Comprehensions

Suppose there is a sequence of objects in variable `x`, which need to be mapped to another sequence of objects in variable `y`. Rather than writing an entire `for` loop to perform this mapping, a comprehension can be used to quickly map elements in one line. This is performed by including the `for` statement in some sequence structure. The general format of these comprehensions are `[open set] [output element] for [variable] in [input sequence] [close set]` For example, suppose we have a list `x` of numbers and we want to create a new list `y` wherein each element is the square of each element in `x`:

``````x = [1, 2, 3, 4, 5, 6]
y = [i**2 for i in x]
print(y)
> [1, 4, 9, 16, 25, 36]``````

`y` is defined as a list using `[open set] = [` and `[close set] = ]`, sets the iterating `[variable]` as `i`, which iterates over the `[input sequence] = x`. Each element in the list will be `[output element] = i**2`, or the square of the values of the input. The comprehension doesn’t have to be for just lists. For example:

``````x = [1, 2, 3, 4, 5, 6]
y = {i**2 for i in x} # Outputs  a set
print(y)
> {1, 4, 36, 9, 16, 25}``````

Note: Suppose you want to generate a list of numbers in the range `[1,11)` with step size 1. You may think that this can be done using the following code1:

``````x = range(0, 11)
print(x)
> range(0, 11)``````

We see that the output is not a list, but unhelpfully, the `range` object itself. This is because the `range` function outputs a generator object rather than a list. The reason for this becomes clear if you consider wanting a loop to iterate over 1,000,000,000 elements. If `range(1, 1000000000)` created a list, then a 1,000,000,000 number list would need to be stored, taking up an enormous amount of memory. The generator object rather generates each number in `range` on-the-fly, and calculates a new value each time the object is iterated over. To generate the `[1,11)`, you can use a list comprehension:

``````x = [i for i in range(0, 11)]
print(x)
> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]``````

### Loop Operations: break Statement

The `break` statement will cause the loop to be exited when executed. `break` statements are valuable in search-type loops, where once a value is found, no further values in the loop need to be executed. For example:

``````for i in range(5):
if i == 3:
break
print(i)
> 0
> 1
> 2``````

When variable `i` is updated to the value of 3, the `if` statement within the `for` loop is satisfied, and the `break` statement is executed. Because the loop is broken, no additional numbers are printed.

### Loop Operations: continue Statement

The `continue` statement tells Python to start back at the top of a loop and update the variable if it is a `for` loop. For example:

``````for i in range(5):
if i == 2 or i == 3:
continue
print(i)
> 0
> 1
> 4``````

When variable `i` is updated to the value of 3 or 2, the `if` statement within the `for` loop is satisfied, and the `continue` statement is executed. The loop is restarted with a new index and continued, eventually reaching the end of the given range.

I put together a Python Developer Kit with over 100 pre-built Python scripts covering data structures, Pandas, NumPy, Seaborn, machine learning, file processing, web scraping and a whole lot more - and I want you to have it for free. Enter your email address below and I'll send a copy your way.

Yes, I'll take a free Python Developer Kit

## Python Conditionals Examples

Suppose we want to apply the skills we’re learned to the motivating example at top. We can store the table above as a list of lists using the following definition:

``````table = [["Mary", "Luxembourg", 64.2, 602005, False],
["Matthew", "Eritrea", 6.856, 4954645, True],
["Marie", None, None, None, None],
["Manuel", "Lesotho", 2.721, 2203821, True],
["Malala", "Poland", 614.190, 38433600, False],
]``````

Now we can use loops and logicals to determine properties of the given information. First we will want to screen out any spurious entries that may cause errors in analysis down the line. Knowing that missing data was represented as `None`, we can easily determine if any of the reports is missing by summing the number of `None` cases.

``````missing_count = 0
for row in table:
if row is None:
missing_count += 1
print(missing_count)
> 1``````

Now suppose we wanted to check the total number of `None` objects within the table. We can use a nested set of `for` loops:

``````none_count = 0
for row in table:
for item in row:
if item is None:
none_count += 1
print(none_count)
> 4``````

Now that we’ve determined that the table has missing data, we can use a loop to create a new cleaned data set:

``````clean_table = []  #Creating an empty list
for row in table:
if None not in row:
clean_table.append(row)
print(clean_table)
> [['Mary', 'Luxembourg', 64.2, 602005, False],
>  ['Matthew', 'Eritrea', 6.856, 4954645, True],
>  ['Manuel', 'Lesotho', 2.721, 2203821, True],
>  ['Malala', 'Poland', 614.19, 38433600, False]]``````

Note that in the above example, we had to create an empty list `[]` before we can append an element to it. If we did not first define the table, then the program would have raised an error that the `clean_table` variable was undefined.

We can count the number of countries within the continent of Africa using the following:

``````country_count = 0
for entry in clean_table:
if entry:  #Checks if the "In Africa?" Boolean is True:
country_count += 1
print(country_count)
> 2``````

We can now quickly determine the mean population and GDP of the cleaned table using list comprehensions:

``````GDP = [row for row in clean_table]
population = [row for row in clean_table]
mean_GDP = sum(GDP)/len(GDP)
mean_pop = sum(population)/len(population)
print([mean_GDP, mean_pop])
> [171.99175000000002, 11548517.75]``````

Remember that the trailing 2 in `mean_GDP` is a result of binary to decimal conversion, and should be disregarded. The `round` function can be used to display only the significant figures of the output.

## Python Logicals & Loops Exercises

1. What is the output of the following code?
``````x = range(5)
y = [2*i for i in x]
z = []
for i in x:
for j in y:
if i > j:
z.append(i)
print(z)``````

Solution
2. Are the following two strings `x` and `y` anagrams? (Hint: use dictionaries)

``````x = "iddujossuupoofapfdaposffoisiuijjdoaasopfhlpfiiuspffoddaufdau"
y = "ojdflsahdfiujofasdjfupofaupoidusfpaoisudfposaidufpoipoasdifu"``````

Solution
3. In our second example on the geography class, we used the following conditional statement to determine if there were any `None` objects within the table:

``if entry is None:``

Could we have used an `==` operator instead of a `is` operator? Why or why not? What is the difference between them?     Solution
4. Use a loop to calculate the sum of all numbers from 1 to 100.     Solution
5. What is the output of the following expression? `x` is an unknown Boolean.

``(True and ((not True or ("True" in "False")) and x)) and x``

## Solutions

1.

``````x = range(5)  # Create a generator for a range [0,4]
y = [2*i for i in x] # double the elements in x: [0, 2, 6, 8]
z = []  # Create an empty list z
for i in x:  #iterate through [0,4]
for j in y: #iterate through [0, 2, 6, 8]
if i > j: # If an element in x is greater than a doubled value in y
z.append(i)  # Add that element to z
print(z)
> [1, 2, 3, 3, 4, 4]``````

2. Dictionaries can be used to tally the number of each unique letter. Comparing the final dictionaries will determine if the strings are anagrams.

``````x = "iddujossuupoofapfdaposffoisiuijjdoaasopfhlpfiiuspffoddaufdau"
y = "ojdflsahdfiujofasdjfupofaupoidusfpaoisudfposaidufpoipoasdifu"
dx = dict()  # Make empty dictionaries
dy = dict()
for c in x:
if c in list(dx):
dx[c] += 1
else:
dx[c] = 1
for c in y:
if c in list(dy):
dy[c] += 1
else:
dy[c] = 1
dx == dy  # Compare dictionaries
> True``````

The two strings are anagrams.

3. In this situation, the functionality of `is` is the same as `==`, as the value of a `None` object will be the same as any `None` object, and the `id` of a `None` object will be the same as any other pointer to the `None` object. The `is` statement compares object id’s, whereas `==` compares object values.

4.

``````s = 0
for i in range(1, 101):
s += i
print(s)
> 5050``````

5. False. Despite not knowing the value of `x`, the `and` shortcut functionality will not evaluate any of the `x` variables.

1. And in Python Version 2 you would be correct. In Python Ver. 2, the `range` function does output a list, while the `xrange` function outputs a generator. In Python Ver. 3, which this tutorial assumes, the `range` function replicates the functionality of the `xrange` function.