How to Validate Input Types in Python
Validating list inputs is essential for preventing runtime errors and ensuring data integrity in Python applications. Since Python is dynamically typed, a function expecting a list of integers might receive a list of strings, or not a list at all, causing crashes downstream.
This guide explores robust techniques to validate that an input is a list, verify its length, and ensure its elements match expected data types.
Basic Type Validation
The first step in validation is ensuring the input is actually a list.
Using isinstance()
The built-in isinstance() function is the standard way to check variable types.
def process_data(input_list):
# ⛔️ Incorrect: No check leads to crashes on invalid input
# return [x * 2 for x in input_list]
# ✅ Correct: Validate that input is a list
if not isinstance(input_list, list):
raise TypeError(f"Expected a list, got {type(input_list).__name__}")
return [x * 2 for x in input_list]
# Examples
# process_data("hello") # -> TypeError: Expected a list, got str
# process_data([1, 2]) # -> [2, 4]
Validating Element Types
Confirming the container is a list is often insufficient; you must also ensure the contents are valid. For example, ensuring a list contains only integers.
Iterative Type Checking
You can iterate through the list and check every element.
def sum_integers(numbers):
if not isinstance(numbers, list):
raise TypeError("Input must be a list")
# ✅ Correct: Validate every element is an integer
for index, item in enumerate(numbers):
if not isinstance(item, int):
raise TypeError(f"Item at index {index} is not an int")
return sum(numbers)
try:
print(sum_integers([1, 2, "3"]))
except TypeError as e:
print(f"Error: {e}")
Output:
Error: Item at index 2 is not an int
Using all() (More Pythonic)
For a cleaner approach, use the all() function with a generator expression.
def validate_homogeneous_list(data, expected_type):
# ✅ Correct: Returns True only if ALL elements match the type
return all(isinstance(x, expected_type) for x in data)
data = [1.5, 2.0, 3.14]
if validate_homogeneous_list(data, float):
print("Valid float list")
else:
print("Invalid list content")
Output:
Valid float list
Validating List Properties (Length/Content)
Beyond types, business logic often requires validation of list length or specific content constraints.
Length Checks
def process_batch(batch):
# ✅ Correct: Validate minimum and maximum constraints
if not isinstance(batch, list):
raise TypeError("Input must be a list")
if len(batch) == 0:
raise ValueError("List cannot be empty")
if len(batch) > 100:
raise ValueError("Batch size exceeds limit of 100")
print(f"Processing {len(batch)} items...")
try:
process_batch([])
except ValueError as e:
print(e)
Output:
List cannot be empty
Using Type Hints for Static Analysis
While Python runtime checks are necessary for dynamic input, using Type Hints allows static analysis tools (like mypy) and IDEs to catch errors before code execution.
from typing import List, Union
# ✅ Correct: Explicitly state input requirements
def calculate_average(scores: List[Union[int, float]]) -> float:
return sum(scores) / len(scores)
# This won't stop execution, but tools will flag this error:
calculate_average(["a", "b"])
Conclusion
To validate list inputs effectively in Python:
- Check Container Type: Always use
isinstance(obj, list)first. - Check Contents: Use
all(isinstance(x, type) for x in list)to ensure homogeneity. - Check Constraints: Verify length (
len()) and value ranges based on your application logic. - Handle Errors: Raise specific exceptions (
TypeError,ValueError) to inform the caller exactly why the input failed validation.