How to Validate Number Types Safely in Python
In Python, robust type checking is essential for ensuring that functions receive appropriate numeric inputs (integers, floats, complex numbers) to avoid runtime errors. While simple type checks can suffice, modern Python development favors flexible strategies like isinstance, try-except blocks for conversion, and type hints with runtime validation.
This guide explores how to validate number types safely and handle edge cases gracefully.
Method 1: Using isinstance() (Runtime Type Check)
The most direct way to check a variable's type is isinstance(). This function supports checking against a tuple of types, making it ideal for accepting multiple numeric formats (e.g., both int and float).
Exmaple of Basic Check:
def validate_numeric(value):
# Check if value is int OR float (excluding bools is often wise)
if isinstance(value, (int, float)) and not isinstance(value, bool):
return True
return False
# Test Cases
print(f"10 valid? {validate_numeric(10)}")
print(f"3.14 valid? {validate_numeric(3.14)}")
print(f"'10' valid? {validate_numeric('10')}") # String is not numeric type
Output:
10 valid? True
3.14 valid? True
'10' valid? False
In Python, bool is a subclass of int. isinstance(True, int) returns True. If your logic strictly requires numbers and not boolean flags, you must explicitly exclude bool.
Method 2: Using try-except (Conversion/Duck Typing)
Sometimes, the specific type doesn't matter as much as the ability to behave like a number. For example, a string "123" might be valid input for a calculator function.
This approach follows the "Easier to Ask for Forgiveness than Permission" (EAFP) principle.
def safe_convert_to_float(value):
try:
return float(value)
except (ValueError, TypeError):
print(f"Error: '{value}' cannot be converted to a number.")
return None
print(f"Convert '42': {safe_convert_to_float('42')}")
print(f"Convert 'abc': {safe_convert_to_float('abc')}")
Output:
Convert '42': 42.0
Error: 'abc' cannot be converted to a number.
Convert 'abc': None
Method 3: Validating Values (Ranges and Properties)
Validating type is often insufficient; you also need to validate the value. For example, an age cannot be negative.
def validate_age(age):
# 1. Type Check
if not isinstance(age, int) or isinstance(age, bool):
raise TypeError("Age must be an integer.")
# 2. Value Check
if not (0 <= age <= 120):
raise ValueError("Age must be between 0 and 120.")
return True
try:
validate_age(150)
except ValueError as e:
print(e)
Output:
Age must be between 0 and 120.
Advanced: Runtime Enforcement with Type Hints
While type hints (x: int) are usually for static analysis, libraries like pydantic or custom decorators can enforce them at runtime.
Example of custom Decorator:
import functools
def enforce_numeric(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
for arg in args:
if not isinstance(arg, (int, float)):
raise TypeError(f"Argument {arg} is not numeric")
return func(*args, **kwargs)
return wrapper
@enforce_numeric
def add(a, b):
return a + b
try:
add(10, "20")
except TypeError as e:
print(e)
Output:
Argument 20 is not numeric
Conclusion
To validate number types safely in Python:
- Use
isinstance(x, (int, float))for strict type checking (remember to excludeboolif necessary). - Use
try-exceptfor flexible input handling where conversion is acceptable. - Combine checks to validate both type and value range for robust data integrity.