SECTION 1
Historical Context & Motivation
Whenever you write a program, you make assumptions. You might assume a user will type a number when you ask for their age, or that a file will contain properly formatted data. But what happens when those assumptions are wrong? The program crashes, produces garbage output, or — in the worst case — opens a security hole. Input validation is the practice of explicitly checking every piece of incoming data before your code relies on it. This idea is as old as professional software engineering itself, and its importance has only grown as programs interact with more users and more unpredictable data sources.
1960s • Early Mainframe Era
1988 • Morris Worm Exploits Missing Validation
1991 • Python Introduces Duck Typing
2004 • OWASP Top 10 Highlights Injection Attacks
2020s • Validation as Standard Practice
The central question this lesson addresses is straightforward: How do you make sure the data entering your program is the right type, within the right range, and safe to use — before it can cause problems?
SECTION 2
Core Principles of Input Validation
Input validation is guided by a small set of principles that apply to every program, whether it is a five-line script or a million-line application. Understanding these principles will help you decide what checks to write and where to place them in your code.
Never Trust External Data
Validate Type First, Then Range
Fail Early and Clearly
Use a Whitelist, Not a Blacklist
Re-prompt or Provide Defaults
KEY TAKEAWAY
SECTION 3
Visual Explanation — The Validation Pipeline
The diagram below shows the typical flow of data through an input validation pipeline. Raw input enters from the left and must pass through three gates — presence, type, and range — before reaching your program's core logic on the right. If a check fails, the flow loops back to request new input or raises an error.
Notice how the pipeline is ordered intentionally. You cannot check whether a number is between 1 and 100 if the user typed "hello" — the type check must come first. Similarly, there is no point checking the type of something that is empty. This layered approach is sometimes called defense in depth, because each gate catches a different category of bad data.
SECTION 4
How Input Validation Works in Python
Python provides several built-in tools for validating input. The most common pattern uses a while loop combined with try/except blocks and conditional statements. Let's break down each mechanism.
Type Checking with try/except
Python's input() function always returns a string. To validate that a user has entered an integer, you attempt to convert the string using int() inside a try block. If the conversion fails, Python raises a ValueError, which you catch in the except block and use to display a helpful error message.
TYPE VALIDATION PATTERN
This pattern catches any input that cannot be converted to the target type. Replace int() with float() for decimal numbers.
Range Checking with Conditionals
Once you know the data is the correct type, you can use if statements to verify that the value falls within an acceptable range. Python supports chained comparisons, which makes range checks very readable.
RANGE VALIDATION PATTERN
The chained comparison lower_bound <= value <= upper_bound is equivalent to (lower_bound <= value) and (value <= upper_bound) but more concise.
The Complete Validation Loop
FULL INPUT VALIDATION LOOP
The while True loop keeps running until valid input is received. continue skips back to the top of the loop. break exits the loop when validation passes.
SECTION 5
Validation Techniques & Classification
Different situations call for different validation strategies. The diagram below classifies the most common validation techniques by what they check and provides Python code snippets for each one.
A presence check ensures the user actually provided something — an empty string or a None value should never slip through. A type check confirms the data can be treated as the expected type, typically by attempting a conversion. A range check verifies that a numeric value sits between defined bounds, or that a string meets length constraints. More advanced programs may also use membership checks (is the value in a known set?) and regular expressions (does the value match a pattern, like an email address?).
SECTION 6
Worked Example — Building a Grade Calculator
Let's build a function that asks the user for a test score (0–100) and returns the corresponding letter grade. We will apply every validation principle from the lesson.
Validated Grade Calculator
- 1
Step 1 — Define the validation requirements
Before writing code, list every assumption you are making about the input. The test score must be (1) not empty, (2) convertible to a number, and (3) between 0 and 100 inclusive. We will allow decimals like 87.5, so we usefloat()for the conversion.Requirements: non-empty, numeric, 0 ≤ score ≤ 100 - 2
Step 2 — Write the validation loop
We use awhile Trueloop that asks for input, attempts afloat()conversion inside a try/except, and checks the range. If all checks pass,breakexits the loop.while True: raw = input("Enter test score (0-100): ") if not raw.strip(): print("Error: Input cannot be empty.") continue try: score = float(raw) except ValueError: print("Error: Please enter a number.") continue if 0 <= score <= 100: break print("Error: Score must be between 0 and 100.") - 3
Step 3 — Map the score to a letter grade
After the loop, the variablescoreis guaranteed to be a float between 0 and 100. We can safely use it without further checks.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"Your grade: {grade}") - 4
Step 4 — Test with bad inputs
Good developers test validation by trying every category of bad input. Enter an empty string, a word like "hello", a negative number like −5, and a number over 100 like 150. Each should produce the correct error message and re-prompt.All four categories of bad input are handled: empty → "Input cannot be empty", non-numeric → "Please enter a number", out of range → "Score must be between 0 and 100".
Pro Tip
raw.strip() to check for empty input. The strip() method removes leading and trailing whitespace, so even " " (just spaces) is caught as empty. This is a best practice because users often hit the space bar accidentally.SECTION 7
Strengths, Limitations & Comparisons
Input validation is not a silver bullet, but it is one of the most effective tools in a programmer's toolbox. Understanding its strengths and limitations helps you decide how much validation is appropriate in different situations.
| Aspect | Strengths | Limitations |
|---|---|---|
| Crash Prevention | Catches bad data before it causes runtime errors, making programs more robust and user-friendly. | Cannot prevent all crashes — logic errors inside the core code are a separate issue. |
| Security | Blocks common attacks like SQL injection and buffer overflows by rejecting malicious input at the boundary. | Input validation alone is not sufficient security — you also need output encoding, authentication, and encryption. |
| User Experience | Gives users clear, immediate feedback about what went wrong and how to fix it. | Overly strict validation can frustrate users (e.g., rejecting valid phone number formats). |
| Code Complexity | Validation logic can be abstracted into reusable helper functions, keeping main code clean. | Thorough validation adds lines of code. In very small scripts, it can feel disproportionate. |
| Debugging | When validation is in place, bugs are almost always in the core logic, not in bad input — this narrows the search. | Validation code itself can have bugs — always test your validators too. |
Strengths and limitations of input validation
KEY TAKEAWAY
SECTION 8
Connection to Advanced Concepts
The manual input validation you are learning here is the foundation for more powerful systems used in professional software development. As you grow as a programmer, you will encounter frameworks and language features that automate much of this work — but they all follow the same principles.
| What You Learn Now | What Comes Next |
|---|---|
| Manual try/except type conversion | Type hints and static type checkers like mypy that catch type errors before the code even runs |
| if/elif range checks | Schema validation libraries like Pydantic that define allowed ranges in data models |
| while True re-prompt loops | Web form validators (Django Forms, WTForms) that validate on the server and display errors in the browser |
| Printing error messages | Raising custom exceptions with raise ValueError("...") for library and API code |
| Hardcoded validation rules | Design by Contract (assertions, preconditions, postconditions) that formally specify what a function expects |
From beginner validation to professional patterns
The key insight is that the thinking process behind validation never changes, even as the tools get more sophisticated. You always ask the same questions: What type should this be? What range is acceptable? What happens if the input is missing? Mastering this mindset now prepares you for every programming paradigm you will encounter.
SECTION 9
Practice Problems
Question 1: CONCEPTUAL
"hello"?Show answer
1 <= "hello" <= 100, Python would raise a TypeError because you cannot compare a string to integers using <=. By converting the string to a number first (inside a try/except), you either get a valid number to compare, or you catch the error gracefully and skip the range check entirely.Question 2: BASIC CALCULATION
Show answer
while True loop with try/except ValueError for the type check and an if 0 <= age <= 120 for the range check: while True:
try:
age = int(input("Enter your age: "))
except ValueError:
print("Please enter a whole number.")
continue
if 0 <= age <= 120:
break
print("Age must be between 0 and 120.") The continue keyword skips the range check when the type conversion fails, and break exits the loop when both checks pass.Question 3: INTERMEDIATE
"quit" to exit. Write a validation loop that handles all three cases: quit command, valid temperature, and invalid input.Show answer
raw = input("Enter temp in °F (or 'quit'): "). Then check if raw.strip().lower() == "quit": break. Next, wrap temp = float(raw) in a try/except. Finally, verify -459.67 <= temp <= 10000. The key decision is the order: the quit command must be handled as a string before the float conversion, otherwise "quit" would trigger the ValueError handler instead of exiting cleanly.Question 4: APPLIED
["small", "medium", "large"] and then enter a quantity between 1 and 20. Write a function get_order() that returns a tuple (size, quantity) only after both inputs are validated. The function should handle case-insensitive size input (e.g., "LARGE" should be accepted).Show answer
while True:
size = input("Size (small/medium/large): ").strip().lower()
if size in ["small", "medium", "large"]:
break
print("Invalid size.") For quantity: while True:
try:
qty = int(input("Quantity (1-20): "))
except ValueError:
print("Enter a whole number.")
continue
if 1 <= qty <= 20:
break
print("Quantity must be 1-20.") Finally, return (size, qty). The .strip().lower() call normalizes the input so "LARGE", " Large ", and "large" all pass.Question 5: CRITICAL THINKING
Show answer
ValueError: invalid literal for int() with base 10: 'abc' is confusing to someone ordering a pizza. Good validation provides friendly, context-specific messages. Second, a crash interrupts the entire program. If a web server crashes because one user typed bad data, every other user loses access — validation keeps the program running for everyone. Third, some invalid inputs don't crash the program but produce silently wrong results. For instance, if a user enters −5 as a test score and the program calculates an average without validation, the result is mathematically valid but logically meaningless. Without a range check, the error goes undetected. Finally, in security-sensitive contexts, letting unvalidated input reach the core logic can enable attacks like code injection, which is far worse than a simple crash.SUMMARY
Lesson Summary
Summary
Input validation is the practice of checking every piece of incoming data for correct presence, type, and range before your program uses it. In Python, the core pattern combines a while True loop with try/except blocks for type conversion and chained comparisons for range checking. The guiding principle is never trust external data — always verify before you rely on it.
Beyond preventing crashes, validation improves user experience by providing clear error messages, strengthens security by blocking malicious input at the boundary, and simplifies debugging by ensuring that once data enters your core logic, it is guaranteed to be correct. This pattern — validate at the boundary, trust inside — is the foundation of defensive programming and scales from simple scripts to professional applications.