2.3 Advanced Flow Control
Controlling Python’s Flow
If statements and boolean operations are foundational to controlling Python software, but their overuse can lead to complex and hard-to-maintain code. In this section, we will explore advanced flow control techniques that help manage the complexity of your code while maintaining clarity and readability.
Organizing If Statements
When in nested if statements, functions, or loops, (see later chapters on functions and loops) we frequently place the desired code in an if statement followed by elif or else blocks to handle different conditions. However, this can lead to deeply nested structures that are hard to read and maintain. To avoid this, we can handle validation using early returns or continue statements to simplify our code and make it more readable. Remember, good codes is readable code.
Take the following example. Let’s say we have a string that we want to ensure is a valid string before processing it. Beginner programmers might write something like this:
example_string = "Hello, World!"
if type(example_string) is str:
example_string = example_string.lower()
else:
print("Error: Not a valid string")This code checks if example_string is a string and then converts it to lowercase. However, if example_string is not a string, it prints an error message. This approach can lead to unnecessary complexity, especially if we have multiple conditions to check.
Instead, we can handle the validation first, getting it out of the way, and then proceed with the main logic of our code, which in this case is converting the string to lowercase. This way, we avoid nesting and keep our code clean and straightforward:
example_string = "Hello, World!"
if type(example_string) is not str:
try:
example_string = str(example_string)
except Exception as e:
print(f"Error, example_string is not a string and cannot converting to string: {e}")
exit(1)
example_string = example_string.lower()This code first checks if example_string is not a string. If it isn’t, it attempts to convert it to a string and handles any exceptions that may arise and exits the program if the conversion fails. After the validation, it proceeds to convert the string to lowercase. This approach keeps the main logic of our code clear and easy to follow.
Granted, this is a simple example, but the same principles can be applied to more complex scenarios. By handling validation early and clearly separating it from the main logic, we can create code that is easier to read, understand, and maintain.
Using Hashmaps for Flow Control
Hashmaps, or dictionaries in Python, are powerful data structures that can be used to control the flow of your program. They allow you to map keys to values, enabling efficient lookups and conditional logic without the need for complex if-else statements. Essentially, they provide an ability to create a data structure that associates the existing items (the key) with the value you want it to be (the value). When you call the key, you will receive the value. This process can clean up your code significantly, especially when dealing with multiple conditions or options.
For instance, let’s imagine we have a simple program where the user can get more information about a specific animal. If we use multiple if-else statements, it can quickly become unwieldy:
animal_options = ["dog", "cat", "bird"]
animal = input(f"Enter an animal ({', '.join(animal_options)}): ").lower()
if animal == "dog":
print("Dogs are loyal and friendly.")
elif animal == "cat":
print("Cats are independent and curious.")
elif animal == "bird":
print("Birds can fly and sing.")
else:
print("Unknown animal.")This code works, but it can be cumbersome to maintain as the number of animals increases. Instead, we can use a dictionary to map animal names to their descriptions:
animal_descriptions = {
"dog": "Dogs are loyal and friendly.",
"cat": "Cats are independent and curious.",
"bird": "Birds can fly and sing."
}
animal = input(f"Enter an animal ({', '.join(animal_descriptions.keys())}): ").lower()
print(animal_descriptions.get(animal, "Unknown animal"))In this version, we define a dictionary called animal_descriptions that maps animal names to their descriptions. Then we use the keys of this dictionary to prompt the user for input. When the user inputs an animal, we simply look it up in the dictionary using the get method, which returns a default value (“Unknown animal”) if the key is not found. This approach is much cleaner and easier to maintain, especially as we add more animals.