Functions, Loops, and Logic
The core of Python programming is conditional if/else/elif control statements, loops, and functions. These are powerful tools that you must master to solve problems and implement algorithms. Use these materials to practice their syntax. If/else/elif blocks allow your program to make conditional decisions based upon values available at the time the block is executed. Loops allow you to perform a set of operations a set number of times based on a set of conditions. Python has two types of loops: for loops and while loops. For loops work by counting and terminating when the loop has executed the prescribed number of times. While loops work by testing a logical condition, and the loop terminates when the logical condition evaluates to a value of false. Functions are designed to take in a specific set of input values, operate on those values, and then return a set of output results.
Practice
Solutions
Functions
Here's what you should have seen in your REPL:
>>> add_numbers(1, 2)
3
# Let's use the string formatting we learned in the last chapter
>>> print(f"The sum of 1 and 2 is {add_numbers(1, 2)}")
The sum of 1 and 2 is 3
Function Scope
Here's what you should have seen in your REPL:
>>> x = 1
>>> y = 2
>>> def add_numbers(x, y):
... print(f"Inside the function, x = {x} and y = {y}")
... return x + y
...
>>> print(f"Outside the function, x = {x} and y = {y}")
Outside the function, x = 1 and y = 2
>>>
>>> print(f"The sum of 5 and 6 is {add_numbers(5, 6)}")
Inside the function, x = 5 and y = 6
The sum of 5 and 6 is 11
Positional Arguments vs Keyword Arguments
Here's what you should have seen in your REPL:
>>> def calculate_numbers(x, y, operation="add"):
... if operation == "add":
... return x + y
... elif operation == "subtract":
... return x - y
...
# Let's try our new function. Remember, if we don't pass the operation keyword argument, the default is "add"
>>> calculate_numbers(2, 3)
5
# You can pass a keyword argument as a normal positional argument
>>> calculate_numbers(2, 3, "subtract")
-1
# You can also use the argument's keyword. This helps with readability
>>> calculate_numbers(2, 3, operation="subtract")
-1
Boolean Logic
Comparisons
Here's what you should have seen in your REPL:
>>> 10 > 5
True
>>> 5 > 10
False
>>> 10 > 10
False
>>> 10 >= 10
True
>>> 5 < 10
True
>>> 5 < 5
False
>>> 5 <= 5
True
>>> 5 == 5
True
>>> 5 != 10
True
Truthiness
Here's what you should have seen in your REPL:
>>> 5 == True
False
>>> # The number 5 does not equal True, but...
>>> if 5:
... print("The number 5 is truthy!")
...
The number 5 is truthy!
>>> # The number 5 is truthy for an if test!
>>> 1 == True
True
>>> 0 == False
True
Boolean Operators
Here's what you should have seen in your REPL:
>>> a = False
>>> b = False
>>> c = False
>>> a or b or c
False
>>> b = True
>>> a or b or c
True
>>> a and b and c
False
>>> a = True
>>> c = True
>>> a and b and c
True
>>> a = False
>>> b = False
>>> not a
True
>>> a and not b
False
Control statements and looping
if, else, and elif
Here's what you should have seen in your REPL:
>>> def test_number(number):
... if number < 100:
... print("This is a pretty small number")
... elif number == 100:
... print("This number is alright")
... else:
... print("This number is huge!")
...
>>> test_number(5)
This is a pretty small number
>>> test_number(99)
This is a pretty small number
>>> test_number(100)
This number is alright
>>> test_number(8675309)
This number is huge!
>>> def fizzbuzz(number):
... if number % 3 == 0 and number % 5 == 0:
... print("Fizzbuzz!")
...
>>> fizzbuzz(3)
>>> fizzbuzz(5)
>>> fizzbuzz(15)
Fizzbuzz!
>>> def my_func(my_list):
... if my_list:
... for item in my_list:
... if item is None:
... print("Got None!")
... else:
... print(item)
... else:
... print("Got an empty list!")
...
>>> my_func([1, 2, 3])
1
2
3
>>> my_func([2, None, "hello", 42])
2
Got None!
hello
42
>>> my_func([])
Got an empty list!
The for loop, range() and enumerate()
Here's what you should have seen in your REPL:
>>> my_list = [1, 2, 3]
>>> for num in my_list:
... print(f"Next value: {num}")
...
Next value: 0
Next value: 1
Next value: 2
>>> for num in range(0, 3):
... print(f"Next value: {num}")
...
Next value: 0
Next value: 1
Next value: 2
>>> my_list = ["foo", "bar", "baz"]
>>> for index, item in enumerate(my_list):
... print(f"Item {index}: {item}")
...
Item 0: foo
Item 1: bar
Item 2: baz
>>> my_dict = {"foo": "bar", "hello": "world"}
>>> for key in my_dict:
... print(f"Key: {key}")
...
Key: foo
Key: hello
>>> for key in my_dict.keys():
... print(f"Key: {key}")
...
Key: foo
Key: hello
>>> for value in my_dict.values():
... print(f"Value: {value}")
...
Value: bar
Value: world
>>> for key, value in my_dict.items():
... print(f"Item {key} = {value}")
...
Item foo = bar
Item hello = world
return
Here's what you should have seen in your REPL:
>>> def is_number_in_list(number_to_check, list_to_search):
... for num in list_to_search:
... print(f"Checking {num}...")
... if num == number_to_check:
... return True
... return False
...
>>> is_number_in_list(27, my_list)
Checking 1...
Checking 2...
Checking 3...
Checking 4...
Checking 5...
False
>>> is_number_in_list(2, my_list)
Checking 1...
Checking 2...
True
while loop
Here's what you should have seen in your REPL:
>>> counter = 0
>>> while counter < 3:
... print(f"Counter = {counter}")
... counter += 1
...
Counter = 0
Counter = 1
Counter = 2
>>> counter = 0
>>> while True:
... print(f"Counter = {counter}")
... if counter == 3:
... break
... counter += 1
...
Counter = 0
Counter = 1
Counter = 2
Counter = 3
Nested Loops
Here's what you should have seen in your REPL:
>>> for x in range(0, 5):
... for y in range(0, 5):
... print(f"x = {x}, y = {y}")
... if y == 2:
... break
...
x = 0, y = 0
x = 0, y = 1
x = 0, y = 2
x = 1, y = 0
x = 1, y = 1
x = 1, y = 2
x = 2, y = 0
x = 2, y = 1
x = 2, y = 2
x = 3, y = 0
x = 3, y = 1
x = 3, y = 2
x = 4, y = 0
x = 4, y = 1
x = 4, y = 2