Skip to main content

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
warning

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:

  1. Use isinstance(x, (int, float)) for strict type checking (remember to exclude bool if necessary).
  2. Use try-except for flexible input handling where conversion is acceptable.
  3. Combine checks to validate both type and value range for robust data integrity.