Skip to main content

Optional: Writing Clean Conditionals

Learn how to use and, or, and not operators, combine conditions with parentheses, and apply common validation patterns in Python effectively.

Introduction

You know how to write if statements. You know how to combine conditions. You can check requirements and validate data.

But conditionals can get messy fast.

Nested if statements inside other if statements. Long chains of conditions that are hard to follow. Logic that works but takes mental effort to parse.

This lesson is about writing conditionals that are not just correct, but readable. Code that you (or someone else) can understand six months from now without having to trace through every branch.

These aren't essential skills for basic automation, but they'll make your code easier to maintain as your scripts grow more complex.


Lesson Overview

This section contains a general overview of topics you will learn in this lesson.

  • When nesting is necessary vs unnecessary
  • How to flatten nested conditions
  • Keeping conditions readable
  • Common refactoring patterns
  • Avoiding common pitfalls

Nesting: When It Makes Sense

Sometimes you need to nest conditions because the logic requires it.

Example: Check if something exists before checking its properties

sheet_number = "A-101"
submitted_sheets = ["A-101", "A-102", "A-201"]
sheet_status = {"A-101": "Issued", "A-102": "Draft"}

# Check if sheet is submitted first
if sheet_number in submitted_sheets:
    # Only check status if it exists
    if sheet_number in sheet_status:
        if sheet_status[sheet_number] == "Issued":
            print("Sheet is issued")
        else:
            print("Sheet is not issued")
    else:
        print("Status unknown")
else:
    print("Sheet not submitted")

This nesting makes sense because each check depends on the previous one. You can't check the status if the sheet doesn't exist.


Unnecessary Nesting

Often, conditions that look like they need nesting can be flattened.

Example: Checking multiple independent conditions

# Nested (harder to read)
room_area = 420

if room_area >= 400:
    if room_area < 600:
        category = "Standard"

Flattened (clearer):

room_area = 420

if room_area >= 400 and room_area < 600:
    category = "Standard"

Or even better, use a range check:

if 400 <= room_area < 600:
    category = "Standard"

Flattening with elif

Nested conditions can often be replaced with elif.

Nested version:

sheet_discipline = "A"
sheet_number = 250

if sheet_discipline == "A":
    if sheet_number > 200:
        category = "Elevations/Sections"
    else:
        category = "Plans"
else:
    category = "Other discipline"

Flattened version:

sheet_discipline = "A"
sheet_number = 250

if sheet_discipline == "A" and sheet_number > 200:
    category = "Elevations/Sections"
elif sheet_discipline == "A":
    category = "Plans"
else:
    category = "Other discipline"

The flattened version is easier to scan. Each possibility is at the same indentation level.


Early Returns (In Functions)

When you learn functions (Module 06), you'll use early returns to avoid nesting.

Preview:

# Nested (harder to follow)
def check_room(area, height):
    if area >= 400:
        if height >= 2.7:
            return "Compliant"
        else:
            return "Height insufficient"
    else:
        return "Area insufficient"

# Early returns (clearer)
def check_room(area, height):
    if area < 400:
        return "Area insufficient"

    if height < 2.7:
        return "Height insufficient"

    return "Compliant"

The second version checks failure conditions first and exits early. If the code reaches the end, you know everything passed.

We'll cover this more in Module 06. For now, just know this pattern exists.


Breaking Up Complex Conditions

Long conditions are hard to read. Break them into named variables.

Hard to read:

if room_area >= 400 and ceiling_height >= 2.7 and has_windows and not is_basement and has_egress and fire_rating >= 1:
    print("Habitable")

Easier to read:

area_ok = room_area >= 400
height_ok = ceiling_height >= 2.7
light_ok = has_windows and not is_basement
safety_ok = has_egress and fire_rating >= 1

if area_ok and height_ok and light_ok and safety_ok:
    print("Habitable")

The second version is self-documenting. You can see what each part checks without parsing the entire condition.


Architectural Example: Complex Validation

Before (one long condition):

if room_area >= minimum_area and ceiling_height >= minimum_height and has_windows and not is_basement and has_fire_exit and fire_rating >= required_rating and ventilation_adequate:
    status = "Approved"
else:
    status = "Rejected"

After (broken down):

# Size requirements
meets_size = room_area >= minimum_area and ceiling_height >= minimum_height

# Light and location
meets_location = has_windows and not is_basement

# Safety requirements
meets_safety = has_fire_exit and fire_rating >= required_rating and ventilation_adequate

# Overall check
if meets_size and meets_location and meets_safety:
    status = "Approved"
else:
    status = "Rejected"

This also makes debugging easier. If something fails, you can check each variable individually.


Avoid Deep Nesting

As a rule of thumb, try to avoid more than 2-3 levels of nesting.

Too deep (4 levels):

if discipline == "A":
    if floor > 0:
        if area > 400:
            if has_windows:
                print("Habitable residential space")

Better (flattened):

is_residential = (
    discipline == "A" and
    floor > 0 and
    area > 400 and
    has_windows
)

if is_residential:
    print("Habitable residential space")

When Nesting Is Actually Better

Sometimes nesting is clearer because it shows dependency.

Example: Progressive checks

# Clear dependency: only check status if sheet exists
if sheet_number in submitted_sheets:
    status = sheet_status.get(sheet_number)

    if status == "Issued":
        print("Send to contractor")
    elif status == "Draft":
        print("Continue work")
    else:
        print("Status unknown")
else:
    print("Sheet not submitted")

This nesting makes sense. The status checks only matter if the sheet was submitted.

Flattening this would be awkward:

# Less clear
if sheet_number in submitted_sheets and sheet_status.get(sheet_number) == "Issued":
    print("Send to contractor")
elif sheet_number in submitted_sheets and sheet_status.get(sheet_number) == "Draft":
    print("Continue work")
elif sheet_number in submitted_sheets:
    print("Status unknown")
else:
    print("Sheet not submitted")

The flattened version repeats the existence check. The nested version is actually clearer here.


Positive vs Negative Conditions

Write conditions positively when possible.

Negative (harder to parse):

if not is_not_approved:
    print("Approved")

Positive (clearer):

if is_approved:
    print("Approved")

Another example:

# Negative
if not (area < minimum_area):
    print("Compliant")

# Positive (clearer)
if area >= minimum_area:
    print("Compliant")

Comments for Complex Logic

When conditions are genuinely complex, add comments explaining the business logic.

# Fire safety: Building is compliant if it has EITHER:
# 1. Fire doors on every floor, OR
# 2. Full sprinkler system AND fire alarm
compliant = (
    has_fire_doors_all_floors or
    (has_full_sprinklers and has_fire_alarm)
)

if compliant:
    print("Fire safety requirements met")

The comment explains why the condition exists, not just what it does.


Real Examples: Before and After

Example 1: Room Categorization

Before:

room_area = 450

if room_area >= 400:
    if room_area < 600:
        category = "Standard"
    else:
        if room_area < 800:
            category = "Large"
        else:
            category = "Oversized"
else:
    category = "Too Small"

After:

room_area = 450

if room_area < 400:
    category = "Too Small"
elif room_area < 600:
    category = "Standard"
elif room_area < 800:
    category = "Large"
else:
    category = "Oversized"

Example 2: Sheet Processing

Before:

if sheet_number in submitted_sheets:
    if sheet_discipline == "A":
        if sheet_type == "Plan":
            if sheet_status == "Issued":
                print("Process architectural plan")

After:

is_arch_plan = (
    sheet_number in submitted_sheets and
    sheet_discipline == "A" and
    sheet_type == "Plan" and
    sheet_status == "Issued"
)

if is_arch_plan:
    print("Process architectural plan")

Example 3: Validation with Detailed Feedback

Before:

if area >= 400:
    if height >= 2.7:
        if has_windows:
            print("Compliant")
        else:
            print("Non-compliant: No windows")
    else:
        print("Non-compliant: Insufficient height")
else:
    print("Non-compliant: Insufficient area")

After:

# Check each requirement
issues = []

if area < 400:
    issues.append("Insufficient area")
if height < 2.7:
    issues.append("Insufficient height")
if not has_windows:
    issues.append("No windows")

# Report
if issues:
    print("Non-compliant:")
    for issue in issues:
        print(f"  - {issue}")
else:
    print("Compliant")

The second version reports all issues at once, not just the first one encountered.


Common Pitfalls

Over-nesting

# Too deep
if a:
    if b:
        if c:
            if d:
                print("All true")

Flatten when possible:

if a and b and c and d:
    print("All true")

Repeating Conditions

# Repeated checks
if status == "Issued" and discipline == "A":
    print("Architectural issued")
elif status == "Draft" and discipline == "A":
    print("Architectural draft")
elif status == "Review" and discipline == "A":
    print("Architectural in review")

Better:

if discipline == "A":
    if status == "Issued":
        print("Architectural issued")
    elif status == "Draft":
        print("Architectural draft")
    elif status == "Review":
        print("Architectural in review")

Or extract the check:

is_architectural = discipline == "A"

if is_architectural:
    if status == "Issued":
        print("Architectural issued")
    elif status == "Draft":
        print("Architectural draft")
    elif status == "Review":
        print("Architectural in review")

Assignment

  1. Create a new file called clean_conditionals.py
  2. Refactor this nested condition:
room_area = 450

if room_area >= 400:
    if room_area < 600:
        print("Standard")
  • Flatten it using and
  1. Refactor this nested condition:
if discipline == "A":
    if number > 200:
        category = "Elevations"
    else:
        category = "Plans"
  • Use elif instead
  1. Break up this complex condition:
if area >= 400 and height >= 2.7 and windows and not basement:
    print("Compliant")
  • Create named boolean variables for each check
  • Combine them clearly
  1. Find and fix the over-nesting:
if submitted:
    if reviewed:
        if approved:
            print("Ready")
  • Flatten appropriately
  1. Improve readability:
if not (area < 400):
    print("Compliant")
  • Rewrite positively
  1. Real scenario - Validation with feedback:
    • Check: area >= 400, height >= 2.7, has_windows = True
    • List ALL issues, not just the first
    • Print them clearly

Knowledge Check

The following questions are an opportunity to reflect on key topics in this lesson.

  • <a class="knowledge-check-link" href="#unnecessary-nesting">How can you flatten nested if statements?</a>
  • <a class="knowledge-check-link" href="#flattening-with-elif">When should you use elif instead of nested if?</a>
  • <a class="knowledge-check-link" href="#breaking-up-complex-conditions">Why break complex conditions into named variables?</a>
  • <a class="knowledge-check-link" href="#avoid-deep-nesting">What's a good rule of thumb for nesting depth?</a>
  • <a class="knowledge-check-link" href="#when-nesting-is-actually-better">When is nesting actually clearer than flattening?</a>
  • <a class="knowledge-check-link" href="#positive-vs-negative-conditions">Why write positive conditions instead of negative ones?</a>

Additional Resources

This section contains helpful links to related content. It isn't required, so consider it supplemental.

Updated on Mar 27, 2026