Python Full Tutorial -- Part 4: If-Else & Decision Making

By Suraj Ahir 2025-12-13 11 min read

← Part 3Python Tutorial · Part 4 of 12Part 5 →
Python Full Tutorial -- Part 4: If-Else & Decision Making

Decision making is at the heart of every useful program. Should this menu item be shown? Is the user authorised? Did the API call succeed? Python handles all of this with if, elif, and else -- and its syntax is clean enough that the code often reads like a plain English description of the logic.

Basic if-elif-else

Grade calculator
score = 78

if score >= 90:
    grade = "A"
elif score >= 80:
    grade = "B"
elif score >= 70:
    grade = "C"
elif score >= 60:
    grade = "D"
else:
    grade = "F"

print(f"Score: {score}, Grade: {grade}")

Truthy and Falsy Values

Boolean context in Python
# Falsy values
if 0:     print("not printed")
if "":    print("not printed")
if []:    print("not printed")
if None:  print("not printed")

# Pythonic checks (use these)
my_list = [1, 2, 3]
if my_list:               # instead of: if len(my_list) > 0:
    print("List has items")

name = ""
display_name = name or "Anonymous"  # "Anonymous"

Logical Operators in Conditions

and, or, not
age = 25
has_ticket = True

if age >= 18 and has_ticket:
    print("Enter")

if age >= 65 or has_ticket:
    print("Eligible for discount")

if not has_ticket:
    print("Purchase a ticket first")

# in operator for membership
allowed = ["suraj", "raj", "priya"]
user = "suraj"
if user in allowed:
    print("Access granted")

The Ternary Operator

One-line conditional expression
# Regular if-else
if score >= 50:
    result = "Pass"
else:
    result = "Fail"

# Ternary (same result, one line)
result = "Pass" if score >= 50 else "Fail"

# In list comprehension
numbers = [-3, -1, 0, 2, 5]
abs_vals = [n if n >= 0 else -n for n in numbers]
print(abs_vals)  # [3, 1, 0, 2, 5]

Nested Conditions

Multi-level logic
def check_access(username, role, resource):
    if username not in ["suraj", "raj"]:
        return "Unknown user"
    
    if role == "admin":
        return "Full access"
    elif role == "editor":
        if resource in ["posts", "pages"]:
            return "Access granted"
        else:
            return "Access denied for this resource"
    else:
        return "Read only"

print(check_access("suraj", "admin", "settings"))

match/case -- Python 3.10+

Pattern matching
status = 404

match status:
    case 200:
        print("OK")
    case 201:
        print("Created")
    case 404:
        print("Not Found")
    case 500:
        print("Server Error")
    case _:
        print(f"Unknown: {status}")

# match with guard conditions
score = 85
match score:
    case s if s >= 90:
        print("Excellent")
    case s if s >= 70:
        print("Good")
    case _:
        print("Needs improvement")

Practical: Login Validator

Multi-condition validation
def validate_login(username, password):
    valid_users = {
        "suraj": "secure123",
        "raj": "pass456"
    }
    
    if not username or not password:
        return "Username and password required"
    
    if username not in valid_users:
        return "User not found"
    
    if valid_users[username] != password:
        return "Wrong password"
    
    return "Login successful"

print(validate_login("suraj", "secure123"))  # Login successful
print(validate_login("suraj", "wrong"))       # Wrong password

Frequently Asked Questions

How does if-else work in Python?

if evaluates a condition. If True, its indented block runs. elif checks the next condition if the previous was False. else runs if nothing matched. Python uses 4-space indentation, not curly braces.

What is the ternary operator?

"value_if_true if condition else value_if_false". Example: result = "Pass" if score >= 50 else "Fail". Use for simple one-liners. Use regular if-else for anything complex.

What values are falsy in Python?

False, None, 0, 0.0, empty string, empty list, empty dict, empty tuple, empty set. Everything else is truthy. Lets you write: if my_list: instead of if len(my_list) > 0:

How do I check multiple conditions at once?

Use and for all-must-be-true: if age >= 18 and has_id: Use or for any-must-be-true. Chain comparisons: if 18 <= age <= 65: Use in for membership: if username in allowed_users:

What is match/case in Python?

Added in Python 3.10 -- like switch/case in other languages. Matches a value against patterns. Supports guards (if conditions), type matching, and structural patterns. More powerful than traditional switch.

In Part 5, we cover loops -- the feature that lets your programs process any number of items with the same code.

Key takeaways

Continue reading
Part 5 — Lists, Dicts, Sets, Tuples
Pick the right collection.
Suraj Ahir — author of SRJahir Tech

Written by

Suraj Ahir

Cloud & DevOps engineer running four live production services on my own AWS infrastructure. I write everything on this site myself — no ghostwriters, no AI filler.

← Part 3Python Tutorial · Part 4 of 12Part 5 →
← Back to Blog
Disclaimer: Educational content only. No guarantees of outcome.

Complex Conditional Logic Patterns

Real-world decision making
def calculate_shipping(weight, destination, is_member, order_total):
    """Calculate shipping cost based on multiple conditions."""
    if order_total >= 2000 and is_member:
        return 0  # Free shipping for members on large orders
    
    base_rate = {"domestic": 50, "regional": 120, "international": 350}
    rate = base_rate.get(destination, 350)
    
    if weight <= 0.5:
        weight_charge = 0
    elif weight <= 2:
        weight_charge = 30
    elif weight <= 5:
        weight_charge = 80
    else:
        weight_charge = 80 + (weight - 5) * 20  # Rs. 20 per kg over 5kg
    
    total = rate + weight_charge
    if is_member:
        total *= 0.85  # 15% member discount
    
    return round(total, 2)

print(calculate_shipping(1.5, "domestic", True, 500))   # 68.0
print(calculate_shipping(3, "regional", False, 1500))   # 200.0

Guard Clauses for Cleaner Code

Fail fast with early returns
def process_user_payment(user, amount, card_number):
    # Guard clauses - handle invalid inputs first
    if not user:
        return {"error": "User required"}
    if not user.is_active:
        return {"error": "User account is inactive"}
    if amount <= 0:
        return {"error": "Amount must be positive"}
    if amount > 100000:
        return {"error": "Amount exceeds daily limit"}
    if not card_number or len(card_number) != 16:
        return {"error": "Invalid card number"}
    
    # Main logic is clean when guard clauses handle edge cases
    return process_charge(user, amount, card_number)

Pattern Matching for DevOps Configuration

Practical match/case examples
def handle_http_status(status_code: int, path: str) -> dict:
    match status_code:
        case 200 | 201 | 204:
            return {"action": "success", "log": False}
        
        case 400:
            return {"action": "reject", "log": True,
                    "error": f"Bad request for: {path}"}
        
        case 401 | 403:
            return {"action": "deny", "log": True,
                    "alert": "Possible unauthorized access attempt"}
        
        case 404:
            return {"action": "not_found", "log": False}
        
        case status if 500 <= status <= 599:
            return {"action": "alert", "log": True,
                    "alert": f"Server error {status} at {path}"}
        
        case _:
            return {"action": "unknown", "log": True}

print(handle_http_status(403, "/admin/dashboard"))
print(handle_http_status(502, "/api/users"))

Structural Pattern Matching

Match data structures, not just values
def process_event(event: dict) -> str:
    match event:
        case {"type": "user_login", "user_id": int(uid), "ip": str(ip)}:
            return f"Login: user {uid} from {ip}"
        
        case {"type": "payment", "amount": float(amt)} if amt > 10000:
            return f"High-value payment: Rs.{amt:.2f} -- flagged"
        
        case {"type": "payment", "amount": float(amt)}:
            return f"Payment: Rs.{amt:.2f}"
        
        case {"type": "error", "code": int(code), "message": str(msg)}:
            return f"Error {code}: {msg}"
        
        case _:
            return "Unknown event type"

print(process_event({"type": "user_login", "user_id": 42, "ip": "10.0.1.5"}))