graph TD A((Start)) --> IN[/Score/] IN --> B{"Is<br>90 <= Score <= 100?"} B -- Yes --> C[/A/] B -- No --> D{"Is<br>Score >= 80?"} D -- Yes --> E[/B/] D -- No --> F{"Is<br>Score >= 70?"} F -- Yes --> G[/C/] F -- No --> H[/D/] C --> I((End)) E --> I G --> I H --> I
14 Conditionals
“The best thing about a boolean is even if you are wrong, you are only off by a bit.” — Anonymous.
In programming, conditionals are used to make decisions based on certain conditions. They allow you to control the flow of your program by executing different blocks of code based on whether a condition is True
or False
. The “off by a bit” reference in the quote above is a nod to the binary nature of boolean values, which can only be True
(1) or False
(0).
Conditional statements allow control flow in a program, enabling it to perform different actions or execute specific blocks of code based on the evaluation of a condition.
14.1 Rule-Based Decision Making
In real-world scenarios, decision-making often involves a series of rules or conditions that guide the process. For example, consider a grading system based on the score of a student. The decision tree in Figure 14.1 shows how a student’s score can be used to determine their grade.
Notice that the decision tree branches based on the score of the student. If the score is greater than or equal to 90
and less than or equal to 100
, the student receives an "A"
. If the score is between 80
and 89
, the student receives a "B"
, and so on. The decision tree represents a rule-based system that maps input (the student’s score) to an output (the grade).
Rule-based systems is a common approach in programming to represent domain-specific knowledge or logic. The rules are typically expressed as conditional statements that guide the program’s behavior. It is often referred to as the first level of artificial intelligence (AI) and is used in expert systems, chatbots, and other applications.
14.2 Conditional Statements in Python
In Python, conditionals are expressed using:
if
statementsif
…else
statementsif
…elif
…else
statementsmatch
statements (introduced in Python 3.10)
Statements are pieces of code that are executed whereas expressions are pieces of code that are evaluated to produce a value. Therefore, statements will perform an action (e.g., assigning a value to a variable, checking a condition, looping, or defining a function) and will often comprise multiple expressions.
14.3 if
Statements
An if
statement is used to conditionally execute a block of code. The code block is executed only if the condition specified in the if
statement is True
. The syntax of an if
statement is as follows:
The code block inside the if
statement is indented to indicate that it is part of the if
block. If the condition is True
, the code block is executed; otherwise, it is skipped.
For example:
In this example, the code inside the if
block will only execute if the condition x > 5
is True
.
Example - Letter Grade (if). In Listing 14.1, we define a function that returns "A"
, "B"
, "C"
, or "D"
if a score falls within the following numerical ranges:
- If score is between 90 and 100, return
"A"
. - If score is between 80 and 89, return
"B"
. - If score is between 70 and 79, return
"C"
. - If score is between 0 and 69, return
"D"
.
if
statement to convert a score to a letter grade. In Listing 14.1 (a), we use the and
operator to check multiple conditions. In Listing 14.1 (b), we use chain comparisons to simplify the code. Chain comparisons are a concise way to check if a variable is within a range.
How could we test the function letter_grade
? In Listing 14.1, we define a test function that checks if the function returns the correct grade for a given score. We are particularly interested in the boundaries between grades.
letter_grade
function to check if it returns the correct grade for a given score. The boundaries (i.e., the points where the grade changes) are typically the most critical points to test because they are more likely to contain bugs.
def test_letter_grade():
assert letter_grade(90) == "A"
assert letter_grade(91) == "A"
assert letter_grade(89) == "B"
assert letter_grade(81) == "B"
assert letter_grade(80) == "B"
assert letter_grade(79) == "C"
assert letter_grade(71) == "C"
assert letter_grade(70) == "C"
assert letter_grade(69) == "D"
assert letter_grade(0) == "D"
🤔 The
letter_grade
in Listing 14.1 is not perfect. What happens if the score is negative?
14.4 if-else
Statement (Two-Way if
)
An if-else
statement allows us to handle two cases based on a condition. If the condition is True
, one block of code is executed; otherwise, another. The syntax of an if-else
statement is as follows:
if condition:
# Code block to execute if condition is True
else:
# Code block to execute if condition is False
# Code block outside the if-else statement
Example - Greater or Not. In Listing 14.3, we define a function that prints a message based on the value of x
and y
. If x
is greater than y
, the message "{x} is greater than {y}"
will be printed. Otherwise, the message "{x} is not greater than {y}"
will be printed.
if-else
statement.
def x_greater_than_y(x, y):
# Only one block within the conditions will trigger
if x > y:
print(f"{x} is greater than {y}")
return True
else:
print(f"{x} is not greater than {y}")
return False
# Test the function
assert x_greater_than_y(5, 3) == True
assert x_greater_than_y(3, 5) == False
5 is greater than 3
3 is not greater than 5
Example - Even or Odd. In Listing 14.4, we define a function that returns "Even"
if the number is even and "Odd"
if it’s odd.
if-else
statement. Only one block within the conditions will trigger.
Sometimes, the else
block can be omitted in the function body. In Listing 14.5, we define a function that checks if a number is even or odd using an if
statement without the else
block. If the condition is True
, the return
statement is executed, and the function exits. If the condition is False
, the function continues to the next statement after the if
block.
if-else
statement without the else
block. Only one block within the conditions will trigger.
In Listing 14.6, we review the letter_grade
function and add a condition to handle invalid grades (i.e., scores less than 0
or greater than 100
). We return None
for invalid grades.
if-else
statement. The function returns None
for invalid grades.
14.5 Nested if
Statements
Nested if
statements allow us to check multiple conditions by nesting one if
within another. It provides a way to handle more complex decision trees. The syntax of a nested if
statement is as follows:
if condition1:
if condition2:
# Block 1 (condition1 and condition2 are True)
else:
# Block 2 (condition1 is True and condition2 is False)
else:
if condition2:
# Block 3 (condition1 is False and condition2 is True)
else:
# Block 4 (condition1 and condition2 are False)
# Code block outside the nested if statement
Notice that the same structure could be alternatively represented as:
if condition1 and condition2:
# Block 1 (condition1 and condition2 are True)
if condition1 and not condition2:
# Block 2 (condition1 is True and condition2 is False)
if not condition1 and condition2:
# Block 3 (condition1 is False and condition2 is True)
if not condition1 and not condition2:
# Block 4 (condition1 and condition2 are False)
# Code block outside the nested if statement
Example - Interval Formatting. In Listing 14.7, we define a function that formats an interval based on the start and end values and whether the interval is inclusive or exclusive. The function returns the formatted interval as a string.
if
statements.
def format_interval(
start_value,
end_value,
is_start_inclusive=True,
is_end_inclusive=True
):
if start_value > end_value:
return "Error: Invalid Range"
if is_start_inclusive:
if is_end_inclusive:
return f"[{start_value}, {end_value}]"
else:
return f"[{start_value}, {end_value})"
else:
if is_end_inclusive:
return f"({start_value}, {end_value}]"
else:
return f"({start_value}, {end_value})"
# Assertions for validation
assert format_interval(1, 5) == "[1, 5]"
assert format_interval(1, 5, is_start_inclusive=False) == "(1, 5]"
assert format_interval(1, 5, is_end_inclusive=False) == "[1, 5)"
assert format_interval(
1, 5,
is_start_inclusive=False,
is_end_inclusive=False
) == "(1, 5)"
assert format_interval(5, 1) == "Error: Invalid Range"
14.6 if-elif-else
Statement (Multi-Way if
)
The if-elif-else
statement allows us to check multiple conditions sequentially and execute the first one that evaluates to True
. It’s useful for handling multiple cases. The elif
stands for “else if.”
The syntax of an if-elif-else
statement is as follows:
if condition1:
# Code block to execute if condition1 is True
elif condition2:
# Code block to execute if condition2 is True
elif condition3:
# Code block to execute if condition3 is True
else:
# Code block to execute if none of the conditions are True
# Code block outside the if-elif-else statement
Example - Letter Grade (if-elif-else). In Listing 14.8, we review the letter_grade
function and rewrite it using an if-elif-else
statement.
if-elif-else
statement. Only one block within the conditions will trigger.
def letter_grade(score):
if score < 0 or score > 100:
return "Invalid Grade"
elif score >= 90:
return "A"
elif score >= 80:
return "B"
elif score >= 70:
return "C"
else:
return "D"
assert letter_grade(95) == "A"
assert letter_grade(85) == "B"
assert letter_grade(75) == "C"
assert letter_grade(65) == "D"
assert letter_grade(-5) == "Invalid Grade"
assert letter_grade(105) == "Invalid Grade"
14.7 match
Statement
Python 3.10 introduced the match
statement, which can be used to perform pattern matching. It allows you to match a value against a series of patterns and execute the corresponding block of code. Sometimes, it can be more concise and readable than using if-elif-else
statements. The syntax is shown in Listing 14.9.
match
statement in Python. The case _:
is the default case that executes when no other pattern matches. Only one block within the conditions will trigger. The cases are evaluated in order, and the first matching case is executed.
A pattern
can be:
- A literal value (e.g.,
1
,"apple"
) - A variable (e.g.,
x
,name
) - A wildcard (
_
) to match any value - A sequence of patterns (e.g.,
(1, 2)
) - A combination of literals (e.g.,
1 | 2
)
See the Python documentation for more details on the match
statement.
Example - Week Day. In Listing 14.10, we define a function that returns the name of the day of the week based on the day number.
match
statement. Only one block within the conditions will trigger.
def week_day(day):
match day:
case 1: return "Monday"
case 2: return "Tuesday"
case 3: return "Wednesday"
case 4: return "Thursday"
case 5: return "Friday"
case 6: return "Saturday"
case 7: return "Sunday"
case _: return "Invalid Day"
# Validation
assert week_day(1) == "Monday"
assert week_day(4) == "Thursday"
assert week_day(7) == "Sunday"
assert week_day(0) == "Invalid Day"
Example - Categorizing Cars. In Listing 14.11, we define a function that categorizes a car into one of four categories based on whether it’s electric and sporty. The function takes two Boolean parameters, is_electric
and is_sporty
, and returns the car category:
"Electric Sportscar"
:is_electric
isTrue
andis_sporty
isTrue
"Electric Car"
:is_electric
isTrue
andis_sporty
isFalse
"Sportscar"
:is_electric
isFalse
andis_sporty
isTrue
"Regular Car"
:is_electric
isFalse
andis_sporty
isFalse
match
statement.
def categorize_car(is_electric, is_sporty):
match (is_electric, is_sporty):
case (True, True): return "Electric Sportscar"
case (True, False): return "Electric Car"
case (False, True): return "Sportscar"
case (False, False): return "Regular Car"
case _: return "Invalid Input"
# Validation
assert categorize_car(True, True) == "Electric Sportscar"
assert categorize_car(True, False) == "Electric Car"
assert categorize_car(False, True) == "Sportscar"
assert categorize_car(False, False) == "Regular Car"
Example - Month to Quarter. In Listing 14.12, we define a function that converts a month number to the corresponding quarter of the year. We use |
(named “pipe”) to combine multiple values in a pattern. The pipe operator in programming is usually used to denote a logical OR operation.
match
statement.
def month_to_quarter(month):
match month:
case 1 | 2 | 3: return "Q1"
case 4 | 5 | 6: return "Q2"
case 7 | 8 | 9: return "Q3"
case 10 | 11 | 12: return "Q4"
case _: return "Invalid Month"
# Validation
assert month_to_quarter(1) == "Q1"
assert month_to_quarter(4) == "Q2"
assert month_to_quarter(7) == "Q3"
assert month_to_quarter(10) == "Q4"
assert month_to_quarter(13) == "Invalid Month"
14.8 Truthy and Falsy Values
In Python, values can be evaluated in a boolean context. This means that they can be used as conditions in if
statements.
Truthy Values. Values that evaluate to True
in a boolean context are called truthy values. For example:
True
- Any non-zero number
- Any non-empty string
- Any non-empty collection (list, tuple, dictionary, set)
Falsy Values. Values that evaluate to False
in a boolean context are called falsy values. For example:
False
None
0
,0.0
,0j
(zero as an integer, float, or complex number)""
(empty string)[]
,()
,{}
,set()
(empty list, tuple, dictionary, set)
Example - Checking if a List is Empty. In Listing 14.13, we define a function that checks if a list is empty using the list itself in an if
statement.
if
statement.
Example - Checking if a String is Empty. In Listing 14.14, we define a function that checks if a string is empty using the string itself in an if
statement.
if
statement.
Example - Checking if a Number is Non-Zero. In Listing 14.15, we define a function that checks if a number is non-zero using the number itself in an if
statement.
if
statement.
Notice that throughot Listing 14.13, Listing 14.14, and Listing 14.15, the if
statement evaluates the value in a boolean context, without the need to compare it to True
or False
. Comparing a value to True
or False
is redundant and not Pythonic as illustrated in Figure 14.2.

True
or False
in an if
statement. Python evaluates the value in a boolean context.
14.9 Conditional Expressions (Ternary Operator)
Python supports a concise way to write conditional expressions using the ternary operator (also known as a conditional expression). The syntax of a ternary operator is as follows:
The ternary operator is a one-liner that allows you to evaluate a condition and return one of two values based on the result. It’s a compact way to write simple if-else
statements.
Example - Absolute Value. In Listing 14.16, we define a function that calculates the absolute value of a number using the ternary operator.
Example - Maximum of Two Numbers. In Listing 14.17, we define a function that returns the maximum of two numbers using the ternary operator.
14.10 Short-Circuit Evaluation
In Python, logical operators (and
, or
) use short-circuit evaluation. This means that the evaluation of the expression stops as soon as the result is determined (see the docs).
14.10.1 Short-Circuiting with and
When using the and
operator:
- If the first expression is
False
, the result isFalse
, and the second, third, etc., expressions are not evaluated. - If the first expression is
True
, the result depends on the second expression. If the second expression isTrue
, the result depends on the third expression, and so on.
Example - Short-Circuiting with and
. In Listing 14.18, we define a function that calls another function only if the input is not None
.
and
operator. The is_valid
function is only called if the password is not None
.
def is_valid(password: str) -> bool:
"""Check if the password is valid.
A valid password must:
- Be at least 8 characters long
- Not be all lowercase or all uppercase
Parameters:
----------
password (str): The password to check.
Returns:
-------
bool: True if the password is valid, False otherwise.
"""
print(f"Checking password {password}. ", end="")
return (
len(password) >= 8
and password.lower() != password
and password.upper() != password
)
def check_password(password):
if password and is_valid(password):
print("Password is valid!")
else:
print("Invalid password!")
# Test the function
check_password("Password123")
check_password("password")
check_password(None)
check_password("")
Checking password Password123. Password is valid!
Checking password password. Invalid password!
Invalid password!
Invalid password!
14.10.2 Short-Circuiting with or
When using the or
operator:
- If the first expression is
True
, the result isTrue
, and the second, third, etc., expressions are not evaluated. - If the first expression is
False
, the result depends on the second expression. If the second expression isFalse
, the result depends on the third expression, and so on.
Example - Short-Circuiting with or
. In Listing 14.19, we define a function that evaluated the results of three expensive functions and returns True
if any of them is True
.
or
operator. The functions f1
, f2
, and f3
are only evaluated as needed, that is, until the first True
result is found.
from time import sleep, time
def f1(num):
print("Evaluating f1.")
sleep(1)
return num % 2 == 0
def f2(num):
print("Evaluating f2.")
sleep(1)
return num % 2 == 0
def f3(num):
print("Evaluating f3.")
sleep(1)
return num % 2 == 0
def check_any_condition(n1, n2, n3):
return f1(n1) or f2(n2) or f3(n3)
# Measure the time taken to evaluate the function
print("Only the first function should be evaluated.")
start_time = time()
check_any_condition(2, 2, 1)
end_time = time()
print(f"Time taken: {end_time - start_time:.2f} seconds")
print("Only the first two functions should be evaluated.")
start_time = time()
check_any_condition(1, 2, 2)
end_time = time()
print(f"Time taken: {end_time - start_time:.2f} seconds")
print("All functions should be evaluated.")
start_time = time()
check_any_condition(1, 1, 1)
end_time = time()
print(f"Time taken: {end_time - start_time:.2f} seconds")
Only the first function should be evaluated.
Evaluating f1.
Time taken: 1.00 seconds
Only the first two functions should be evaluated.
Evaluating f1.
Evaluating f2.
Time taken: 2.00 seconds
All functions should be evaluated.
Evaluating f1.
Evaluating f2.
Evaluating f3.
Time taken: 3.00 seconds
🤔 What are the states of the call stack when executing Listing 14.19?
14.11 Conditional Statements for Error Handling?
In Python, conditional statements can be used for error handling. For example, you can check if a file exists before reading it, or if a value is None
before using it. However, Python provides a more robust way to handle errors using exceptions. Exceptions are a way to handle errors that occur during the execution of a program. They allow you to gracefully handle errors and exceptions that may arise during the execution of your code.
In Listing 14.20, we compare two ways to handle a division by zero error. The first function uses an if
statement to check if the denominator is zero before performing the division. The second function uses a try-except
block to catch the ZeroDivisionError
exception that occurs when dividing by zero.
if
statement and a try-except
block.
if
statement to check if the denominator is zero before performing the division.
ZeroDivisionError
exception using a try-except
block. When an exception occurs, the code inside the except
block is executed.
In general, it’s recommended to use exceptions for error handling in Python since they provide a more robust and flexible way to handle errors. Exceptions allow you to separate error-handling code from the normal flow of your program, making your code cleaner and easier to read. In Listing 14.20, the try-except
block can be further extended to handle other exceptions that may occur during the division operation, for example, TypeError
if the input is not a number. For example, in Listing 14.21, we extend the divide_v2
function to handle both ZeroDivisionError
and TypeError
exceptions.
divide_v2
function to handle both ZeroDivisionError
and TypeError
exceptions using a try-except
block.
def divide_v2(
numerator,
denominator
):
try:
return numerator / denominator
except ZeroDivisionError:
print("Cannot divide by zero.")
return None
except TypeError:
print("Invalid input type.")
return None
except ValueError:
print("Invalid value.")
return None
# Test the function
assert divide_v2(10, 2) == 5
assert divide_v2(10, 0) == None
assert divide_v2(10, "2") == None
# Test division by infinity
import math
assert divide_v2(10, math.inf) == 0
# Test division by very small number (close to zero)
assert divide_v2(10, 1e-1000) == None
Cannot divide by zero.
Invalid input type.
Cannot divide by zero.
14.12 Isn’t AI Just a Bunch of if-else
Statements?
On the surface, artificial intelligence (AI) may seem like a series of nested if-else
statements: given input data, an AI model will output a certain prediction or decision. The big diffence is on how the output is generated. In the case of if-else
statements, the logic is explicitly defined by the programmer. The domain knowledge is encoded in the form of conditions and rules, and the program follows these rules to make decisions.
As for AI models, they can handle more complex logic by learning the conditions from large amounts of data. This is done through a process called machine learning, where the model learns patterns and relationships in the data to make predictions or decisions. It would be extremely difficult, for example, creating a decision tree for driving autonomous cars using nested if-else
statements due to the complexity and large scope of the rules. Using AI, the model can learn from examples of driving behavior and road conditions to make decisions in real-time.

14.13 Exercises
14.13.1 Is Even
Write a Python function that takes an integer as input and returns True
if the number is even and False
otherwise. Use only if
statements.
14.13.2 Categorize Number
Write a Python function that takes an integer as input and returns:
"Positive"
if it’s positive,"Negative"
if it’s negative, and"Zero"
if it’s zero,
using only if
statements.
14.13.3 Determining Quadrant
Write a function that takes two numbers (x
and y
) as input representing coordinates on a 2D plane. The function should return the quadrant in which the point lies ("Quadrant I"
, "Quadrant II"
, "Quadrant III"
, or "Quadrant IV"
) or "Origin"
if the point is at the origin (0, 0)
. Use only if
statements without else
.
def determine_quadrant(x, y):
pass # Add code here!
def test_determine_quadrant():
assert determine_quadrant(3, 4) == "Quadrant I"
assert determine_quadrant(-3, 4) == "Quadrant II"
assert determine_quadrant(-3, -4) == "Quadrant III"
assert determine_quadrant(3, -4) == "Quadrant IV"
assert determine_quadrant(0, 0) == "Origin"
14.13.4 Vowel or Consonant
Write a function that takes a single character (a letter) as input and returns "Vowel"
if it’s a vowel, namely, "a"
, "e"
, "i"
, "o"
, or "u"
, or "Consonant"
otherwise. Create a version of the function using all Python’s conditional statements:
if
if-else
if-elif-else
match
- Ternary operator
14.13.5 Checking Divisibility
Write a Python function that takes two integers as input and returns "Divisible"
if the first number is divisible by the second number, and "Not Divisible"
otherwise.
14.13.6 Checking Age Eligibility
Write a Python function that takes an age as input and returns "Eligible"
if the age is 18 or older, and "Not Eligible"
otherwise.
14.13.7 Checking Valid Username
Write a Python function that takes a username as input and returns "Valid"
if the username contains at least 6 characters and does not contain spaces, and "Invalid"
otherwise.
14.13.8 Categorizing BMI
Create a function that categorizes a person’s Body Mass Index (BMI) into "Underweight"
, "Normal"
, "Overweight"
, or "Obese"
. The criteria is as follows:
- Underweight: BMI < 18.5
- Normal: 18.5 <= BMI <= 24.9
- Overweight: 25 <= BMI <= 29.9
- Obese: BMI >= 30
- Invalid BMI: BMI < 0
def categorize_bmi(bmi):
pass # Add code here!
def test_categorize_bmi():
assert categorize_bmi(22.5) == "Normal"
assert categorize_bmi(29) == "Overweight"
assert categorize_bmi(31.7) == "Obese"
assert categorize_bmi(-5) == "Invalid BMI"
def categorize_bmi(bmi:float) -> str:
"""Categorize BMI:
Criteria:
--------
- Underweight: BMI < 18.5
- Normal: 18.5 <= BMI <= 24.9
- Overweight: 25 <= BMI <= 29.9
- Obese: BMI >= 30
- Invalid BMI: BMI < 0
Parameters:
----------
- bmi: int
Value of BMI
Return:
-------
- Category: str
Category of the BMI
"""
if bmi < 0:
return "Invalid BMI"
if bmi < 18.5:
return "Underweight"
if bmi <= 24.9:
return "Normal"
if bmi <= 29.9:
return "Overweight"
if bmi >= 30:
return "Obese"
# If one triggers, the flow jumps to here
return response
assert categorize_bmi(22.5) == "Normal"
assert categorize_bmi(29) == "Overweight"
assert categorize_bmi(31.7) == "Obese"
assert categorize_bmi(-5) == "Invalid BMI"
14.13.9 Number Sign
Write a function that takes two integers as input and returns "Positive"
if both are positive, "Negative"
if both are negative, and "Mixed"
otherwise.
14.13.10 Increasing / Decreasing Order
Write a function that takes three numbers as input and returns "Increasing"
if they are in increasing order, "Decreasing"
if they are in decreasing order, and "Neither"
otherwise.
14.13.11 Triangle Type
Write a function that takes three integers as input representing the sides of a triangle and returns "Equilateral"
if all sides are equal, "Isosceles"
if two sides are equal, and "Scalene"
if all sides are different.
14.13.12 Checking Leap Year
Write a function that takes a year as input and returns "Leap Year"
if it’s a leap year and "Not a Leap Year"
if it’s not.
14.13.13 Checking Validity of a Date
Write a function that takes three integers as input representing a date (day, month, year) and returns
"Valid"
if the date is valid, or"Invalid"
, otherwise.
Make sure you consider leap years!
def check_date_validity(day, month, year):
# Check if year is valid
# Check if month is valid
# If month has 30 days, check if day <= 30
# If month has 31 days, check if day <= 31
# If month is Feb and the year is a leap year, day <=29
# If month is Feb and the year is not a leap year, day <=28
def test_check_date_validity():
assert check_date_validity(31, 12, 2023) == "Valid"
assert check_date_validity(29, 2, 2024) == "Valid"
assert check_date_validity(30, 2, 2024) == "Invalid"
# Add more edge cases here!
14.13.14 Multiple Conditions with Strings
Write a function that takes two strings as input and returns "Equal"
if they are the same, "Different"
if they are different, and "CaseSensitive"
if they are different considering case.
14.13.15 Checking Password Validity
Write a function that takes a password as input and returns "Valid"
if the password meets the following criteria:
- Contains at least one uppercase letter.
- Contains at least one lowercase letter.
- Contains at least one numeric digit.
- Contains at least one special character
(!@#$%^&*()_+[]{}|;:'",.<>?).
- Has a minimum length of 8 characters.
Return "Invalid"
if any of these criteria are not met.
def check_password_validity(password):
pass # Add code here!
def test_check_password_validity():
assert check_password_validity("Password123!") == "Valid"
assert check_password_validity("WeakPass") == "Invalid"
assert check_password_validity("SecurePass123") == "Invalid"
assert check_password_validity("Complex@Pswd123") == "Valid"
def check_password_validity(password:str)->str:
"""Check is password is valid.
Criteria
--------
- Contains at least one uppercase letter.
- Contains at least one lowercase letter.
- Has a minimum length of 8 characters.
- Contains at least one special character (!@#$%^&*()_+[]{}|;:'",.<>?).
- Contains at least one numeric digit.
Parameters
----------
password : str
_description_
Returns
-------
str
Valid if password satisfies the criteria, Invalid otherwise
"""
# input: 2wWE
# output: 2WRAWE (upper)
if password.upper() == password:
return "Invalid"
# only upper letters
# Check if password has at least one uppercase letter
if password.islower():
return "Invalid"
if password.isupper():
return "Invalid"
if len(password) < 8:
return "Invalid"
if password.isalnum():
return "Invalid"
has_number = False
for s in password:
if s in "1234567890":
has_number = True
if not has_number:
return "Invalid"
has_letter = False
for s in password:
if s in "abcdefghijklmnopqrstuwxyz":
has_letter = True
if not has_letter:
return "Invalid"
return "Valid"
assert check_password_validity("password@#$3432") == "Invalid"
assert check_password_validity("PASSWORD@#$3432") == "Invalid"
assert check_password_validity("PASswORD@#$3432") == "Valid"
# Minimum 8
assert check_password_validity("123sS%") == "Invalid"
assert check_password_validity("123sS%78") == "Valid"
assert check_password_validity("123sS%789") == "Valid"
assert check_password_validity("123sS%7") == "Invalid"
assert check_password_validity("Password123!") == "Valid"
assert check_password_validity("SecurePass123") == "Invalid"
assert check_password_validity("Complex@Pswd123") == "Valid"
assert check_password_validity("WeakPass") == "Invalid"
assert check_password_validity("112312312313") == "Invalid"
assert check_password_validity("11231231231%$%3") == "Invalid"
14.13.16 Checking Password Validity (Using Subfunctions)
Redo the function check_password_validity
using the following subfunctions to test the criteria:
has_uppercase(password)
has_lowercase(password)
has_digit(password)
has_special_char(password)
has_min_length(password, min_length)
Also, write a test function with the edge cases for each subfunction and a test function for check_password_validity_clean
.
def has_uppercase(password):
pass # Add code here!
def has_lowercase(password):
pass # Add code here!
def has_digit(password):
pass # Add code here!
def has_special_char(password):
pass # Add code here!
def has_min_length(password, min_length):
pass # Add code here!
def check_password_validity_clean(password):
pass # Add code here!
def test_subfunctions():
# Add test cases for each subfunction
def test_check_password_validity_clean():
# Add test cases for check_password_validity_clean
14.13.17 Convert Letter Grade
Write a Python function that takes a numeric grade (0 to 100) as input and returns the corresponding letter grade ("A"
, "B"
, "C"
, "D"
, or "F"
) using if-elif-else
statements.
The grading scale is as follows:
- If the grade is between 90 and 100, return
"A"
. - If the grade is between 80 and 89.9, return
"B"
. - If the grade is between 70 and 79.9, return
"C"
. - If the grade is between 60 and 69.9, return
"D"
. - If the grade is less than 60, return
"F"
.
If the grade is outside the range 0 to 100, return "Invalid Grade"
.
14.13.18 Categorizing Blood Pressure
Write a function that takes systolic and diastolic blood pressure readings as input and returns a category ("Normal"
, "Prehypertension"
, "Hypertension Stage 1"
, "Hypertension Stage 2"
, or "Hypertensive Crisis"
) using if-elif-else
statements.
Blood Pressure Categories:
Blood Pressure Category | Systolic Range | Diastolic Range |
---|---|---|
Normal | Below 120 | Below 80 |
Prehypertension | 120–129 | Below 80 |
Hypertension Stage 1 | 130–139 | 80–89 |
Hypertension Stage 2 | 140 and above | 90 and above |
Hypertensive Crisis | Above 180 | Above 120 |
def categorize_blood_pressure(systolic, diastolic):
pass # Add code here!
def test_categorize_blood_pressure():
assert categorize_blood_pressure(110, 70) == "Normal"
assert categorize_blood_pressure(125, 85) == "Invalid Blood Pressure"
assert categorize_blood_pressure(150, 95) == "Hypertension Stage 2"
assert categorize_blood_pressure(190, 130) == "Hypertensive Crisis"
assert categorize_blood_pressure(134, 85) == "Hypertension Stage 1"