Python • Problem-Solving Patterns

Input Validation — Validate assumptions about input types and ranges

Protect your programs from crashing by checking that every input meets your expectations before you use it.

Code braces with terminal and markup symbols representing Python programming.
Inside this lesson 10 sections 5 questions 7 figures

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

Programmers on batch-processing mainframes discovered that a single mis-typed punch card could crash an entire overnight job. Teams began inserting manual checks at the beginning of every routine to verify data formats.

1988 • Morris Worm Exploits Missing Validation

The Morris Worm spread across the early internet by exploiting a buffer overflow — a failure to validate the length of input. It infected roughly 6,000 machines and showed the world how dangerous unchecked input could be.

1991 • Python Introduces Duck Typing

Guido van Rossum released Python, a dynamically typed language where variables can hold any type. This flexibility made input validation even more important, since the interpreter won't catch type mismatches at compile time.

2004 • OWASP Top 10 Highlights Injection Attacks

The OWASP Foundation ranked injection attacks as the number-one web security risk. The root cause in nearly every case was insufficient input validation, driving the modern principle of "never trust user input."

2020s • Validation as Standard Practice

Modern Python frameworks like Django, Flask, and Pydantic build input validation into their core APIs, making it a first-class part of software development rather than an afterthought.

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.

1

Never Trust External Data

Any data that comes from outside your function — user input, files, network requests, or even another function's return value — should be treated as potentially wrong until proven otherwise.
2

Validate Type First, Then Range

Check that the data is the correct type (e.g., an integer, not a string) before checking whether it falls within an acceptable range. A range check on a non-numeric value will itself cause an error.
3

Fail Early and Clearly

When invalid data is detected, stop processing immediately and report the problem with a clear, helpful message. Don't let bad data travel deeper into the program where it becomes harder to diagnose.
4

Use a Whitelist, Not a Blacklist

Define what IS allowed rather than listing everything that is NOT allowed. For example, accept only digits for an age field rather than trying to block every non-digit character.
5

Re-prompt or Provide Defaults

Good programs give the user another chance to enter valid data rather than crashing. Alternatively, your code can use sensible default values when optional inputs are missing.
✦

KEY TAKEAWAY

Think of input validation like airport security. Every passenger (piece of data) must go through a checkpoint before boarding the plane (entering your program's core logic). You check their ID (type), verify they have a valid ticket (range), and scan for prohibited items (dangerous values). If anything is wrong, they are stopped at the gate — not halfway through the flight.

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.

Input Validation PipelineRawInputGate 1PresenceIs input empty?PASSGate 2Type CheckIs it the right type?PASSGate 3Range CheckWithin bounds?PASSCoreLogicFAILFAILFAIL"Input required""Must be a number""Out of range"Each gate checks one property. Data must pass ALL gates to reach core logic.Re-prompt user
The validation pipeline: raw input flows through Gate 1 (presence), Gate 2 (type), and Gate 3 (range). Failures redirect to clear error messages and can loop back to re-prompt the user.

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

try:value=int(rawinput)exceptValueError:print("Notavalidinteger")try: value = int(raw_input) except ValueError: print("Not a valid integer")

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

if lower_bound <= value <= upper_bound: # valid — proceed else: print(f"Value must be between {lower_bound} and {upper_bound}")

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

whileTrue:raw=input(prompt)try:value=int(raw)exceptValueError:print("Pleaseenterawholenumber.")continueifminval<=value<=maxval:breakprint(f"Mustbebetweenminvalandmaxval.")while True: raw = input(prompt) try: value = int(raw) except ValueError: print("Please enter a whole number.") continue if min_val <= value <= max_val: break print(f"Must be between {min_val} and {max_val}.")

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.

Validation Techniques ClassificationInput ValidationPresence CheckType CheckRange / Format CheckIs the input empty or None?if not raw_input: print("Required!")Can it convert to the expected type?try: n = int(raw_input)except ValueError: print("Not an int")Is the value within bounds?if 1 <= n <= 100: # valid— or for strings —if len(name) <= 50:Additional ChecksMembership Checkif val in ["A","B","C"]:Pattern / Regexre.match(r"^\d{3}$", s)isinstance() Checkisinstance(val, int)
Validation techniques fall into three main categories: presence checks, type checks, and range/format checks. Additional specialized checks include membership tests, regex patterns, and isinstance() calls.

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. 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 use float() for the conversion.
    Requirements: non-empty, numeric, 0 ≤ score ≤ 100
  2. 2

    Step 2 — Write the validation loop

    We use a while True loop that asks for input, attempts a float() conversion inside a try/except, and checks the range. If all checks pass, break exits 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. 3

    Step 3 — Map the score to a letter grade

    After the loop, the variable score is 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. 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

Notice how we used 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.

AspectStrengthsLimitations
Crash PreventionCatches 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.
SecurityBlocks 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 ExperienceGives 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 ComplexityValidation 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.
DebuggingWhen 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

Input validation is like wearing a seatbelt — it does not prevent every possible accident, but it dramatically reduces the severity of problems when things go wrong. And just like seatbelts, it is best to build the habit early so it becomes automatic in every program you write.

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 NowWhat Comes Next
Manual try/except type conversionType hints and static type checkers like mypy that catch type errors before the code even runs
if/elif range checksSchema validation libraries like Pydantic that define allowed ranges in data models
while True re-prompt loopsWeb form validators (Django Forms, WTForms) that validate on the server and display errors in the browser
Printing error messagesRaising custom exceptions with raise ValueError("...") for library and API code
Hardcoded validation rulesDesign 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

Explain why you should check the type of an input before checking its range. What would happen if you did the range check first on the string "hello"?
Show answer
You must check type before range because range comparisons require numeric values. If you tried to evaluate 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

Write a Python snippet that asks the user for their age and validates that the input is (a) an integer and (b) between 0 and 120. If the input is invalid, print an appropriate error message and re-prompt.
Show answer
A correct solution uses a 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

A temperature converter asks for a temperature in Fahrenheit. Valid inputs are floats between −459.67 (absolute zero) and 10000. The user can also type "quit" to exit. Write a validation loop that handles all three cases: quit command, valid temperature, and invalid input.
Show answer
This problem requires checking the quit command before attempting numeric conversion. First, read 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

You are writing a pizza ordering system. The user must choose a size from the list ["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
The function needs two separate validation loops — one for the size (a membership check) and one for the quantity (type + range check). For size: 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

A classmate argues that input validation is unnecessary because Python's error messages already tell the user what went wrong when a crash occurs. Write a paragraph-length response explaining at least three reasons why this reasoning is flawed, using examples from real-world scenarios.
Show answer
First, Python's default error messages (tracebacks) are designed for developers, not end users — a message like 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.

Varsity Tutors • Python • Input Validation — Validate assumptions about input types and ranges