Skip to content

How to Validate Sequence Types (Ordered Collections) in Python

Learn how to properly validate Python sequences (lists, tuples, strings, ranges) using isinstance(), collections.abc.Sequence, and duck typing for robust type checking.

In Python, a "sequence" is a generic term for ordered collections like lists, tuples, strings, and ranges. Often, a function is designed to work with any sequence but fails if passed a non-sequence object (like an integer or a dictionary).

This guide explores how to validate sequence types robustly using isinstance, Abstract Base Classes (ABCs), and duck typing.

Method 1: Using isinstance() (Standard Check)

The most direct way to check if an object is a sequence is to verify if it is an instance of list, tuple, str, or range.

def validate_sequence(data):
    if isinstance(data, (list, tuple, str, range)):
        return True
    return False

print(f"List valid? {validate_sequence([1, 2])}")
print(f"Int valid?  {validate_sequence(42)}")

Output:

List valid? True
Int valid?  False

Method 2: Using collections.abc.Sequence (Robust Check)

The standard library provides Abstract Base Classes (ABCs) that define what a sequence is (supports indexing, length, iteration). Checking against Sequence is the most "correct" way to support lists, tuples, strings, and custom sequence-like objects.

from collections.abc import Sequence

def is_sequence(obj):
    return isinstance(obj, Sequence)

print(f"Tuple: {is_sequence((1, 2))}")
print(f"String: {is_sequence('Hello')}")
print(f"Dict:  {is_sequence({'a': 1})}") # Dict is Mapping, not Sequence

Output:

Tuple: True
String: True
Dict:  False

Method 3: Duck Typing (Behavioral Check)

"If it walks like a duck and quacks like a duck, it's a duck." Instead of checking types, you check if the object behaves like a sequence (i.e., has __iter__, __len__, and __getitem__).

def is_sequence_duck(obj):
    try:
        _ = len(obj)
        _ = obj[0] # Try indexing
        iter(obj)
        return True
    except (TypeError, IndexError, KeyError):
        return False

print(f"List: {is_sequence_duck([1, 2])}")
print(f"Int:  {is_sequence_duck(10)}")

Output:

List: True
Int:  False

Advanced: Using Validation Decorators

To keep your code DRY (Don't Repeat Yourself), you can create a decorator that enforces sequence validation on function arguments.

from collections.abc import Sequence
import functools

def require_sequence(func):
    @functools.wraps(func)
    def wrapper(arg, *args, **kwargs):
        if not isinstance(arg, Sequence):
            raise TypeError(f"Argument must be a sequence, got {type(arg).__name__}")
        return func(arg, *args, **kwargs)
    return wrapper

@require_sequence
def process_data(data):
    print(f"Processing {len(data)} items...")

process_data([1, 2, 3])

try:
    process_data(100)
except TypeError as e:
    print(e)

Output:

Processing 3 items...
Argument must be a sequence, got int

Conclusion

To validate sequence types in Python:

  1. Use isinstance(obj, (list, tuple)) for quick, simple scripts.
  2. Use isinstance(obj, collections.abc.Sequence) for robust, professional code that supports all sequence types (including custom ones).
  3. Use Duck Typing if you prefer validating behavior over type definitions.
Navigation