Brief introduction to typing in Python

Skip ahead if you know what structural typing, nominal typing and duck typing are.

I think much of the confusion arises from the fact that typing was a provisional module between versions 3.5 and 3.6. And was still subject to change between versions 3.7 and 3.8. This means there has been a lot of flux in how Python has sought to deal with typing through type annotations.

It also doesn't help that python is both duck-typed and nominally typed. That is, when accessing an attribute of an object, Python is duck-typed. The object will only be checked to see if it has an attribute at runtime, and only when immediately requested. However, Python also has nominal typing features. Nominal typing is where one type is declared to be a subclass of another. This can be through inheritance, or with the register() method of ABCMeta.

typing originally introduced its types using the idea of nominal typing. As of 3.8 it is trying to allow for the more pythonic structural typing. Structural typing is related to duck-typing, except that it is taken into consideration at "compile time" rather than runtime. For instance, when a linter is trying to detect possible type errors -- such as if you were to pass a dict to a function that only accepts sequences like tuples or list. With structural typing, a class B should be considered a subtype of A if it implements the all the methods of A, regardless of whether it has been declared to be a subtype of A (as in nominal typing).

Answer

sequences (little s) are a duck type. A sequence is any ordered collection of objects that provides random access to its members. Specifically, if it defines __len__ and __getitem__ and uses integer indices between 0 and n-1 then it is a sequence. A Sequence (big s) is a nominal type. That is, to be a Sequence, a class must be declared as such, either by inheriting from Sequence or being registered as a subclass.

A numpy array is a sequence, but it is not a Sequence as it is not registered as a subclass of Sequence. Nor should it be, as it does not implement the full interface promised by Sequence (things like count() and index() are missing).

It sounds like you want is a structured type for a sequence (small s). As of 3.8 this is possible by using protocols. Protocols define a set of methods which a class must implement to be considered a subclass of the protocol (a la structural typing).

from typing import Protocol
import numpy as np

class MySequence(Protocol):
    def __getitem__(self, index):
        raise NotImplementedError
    def __len__(self):
        raise NotImplementedError
    def __contains__(self, item):
        raise NotImplementedError
    def __iter__(self):
        raise NotImplementedError

def f(s: MySequence):
    for i in range(len(s)):
        print(s[i], end=' ')
    print('end')

f([1, 2, 3, 4]) # should be fine
arr: np.ndarray = np.arange(5)
f(arr) # also fine
f({}) # might be considered fine! Depends on your type checker

Protocols are fairly new, so not all IDEs/type checkers might support them yet. The IDE I use, PyCharm, does. It doesn't like f({}), but it is happy to consider a numpy array a Sequence (big S) though (perhaps not ideal). You can enable runtime checking of protocols by using the runtime_checkable decorator of typing. Be warned, all this does is individually check that each of the Protocols methods can be found on the given object/class. As a result, it can become quite expensive if your protocol has a lot of methods.

Answer from Dunes on Stack Overflow
🌐
Real Python
realpython.com › python-sequences
Python Sequences: A Comprehensive Guide – Real Python
March 18, 2026 - A sequence is a data structure that contains items arranged in order, and you can access each item using an integer index that represents its position in the sequence. You can always find the length of a sequence.
🌐
Python
docs.python.org › 3 › builtins › stdtypes.html
Built-in Types — Python 3.14.7 documentation
If a container object’s __iter__() ... documentation for the yield expression. There are three basic sequence types: lists, tuples, and range objects....
Top answer
1 of 3
18

Brief introduction to typing in Python

Skip ahead if you know what structural typing, nominal typing and duck typing are.

I think much of the confusion arises from the fact that typing was a provisional module between versions 3.5 and 3.6. And was still subject to change between versions 3.7 and 3.8. This means there has been a lot of flux in how Python has sought to deal with typing through type annotations.

It also doesn't help that python is both duck-typed and nominally typed. That is, when accessing an attribute of an object, Python is duck-typed. The object will only be checked to see if it has an attribute at runtime, and only when immediately requested. However, Python also has nominal typing features. Nominal typing is where one type is declared to be a subclass of another. This can be through inheritance, or with the register() method of ABCMeta.

typing originally introduced its types using the idea of nominal typing. As of 3.8 it is trying to allow for the more pythonic structural typing. Structural typing is related to duck-typing, except that it is taken into consideration at "compile time" rather than runtime. For instance, when a linter is trying to detect possible type errors -- such as if you were to pass a dict to a function that only accepts sequences like tuples or list. With structural typing, a class B should be considered a subtype of A if it implements the all the methods of A, regardless of whether it has been declared to be a subtype of A (as in nominal typing).

Answer

sequences (little s) are a duck type. A sequence is any ordered collection of objects that provides random access to its members. Specifically, if it defines __len__ and __getitem__ and uses integer indices between 0 and n-1 then it is a sequence. A Sequence (big s) is a nominal type. That is, to be a Sequence, a class must be declared as such, either by inheriting from Sequence or being registered as a subclass.

A numpy array is a sequence, but it is not a Sequence as it is not registered as a subclass of Sequence. Nor should it be, as it does not implement the full interface promised by Sequence (things like count() and index() are missing).

It sounds like you want is a structured type for a sequence (small s). As of 3.8 this is possible by using protocols. Protocols define a set of methods which a class must implement to be considered a subclass of the protocol (a la structural typing).

from typing import Protocol
import numpy as np

class MySequence(Protocol):
    def __getitem__(self, index):
        raise NotImplementedError
    def __len__(self):
        raise NotImplementedError
    def __contains__(self, item):
        raise NotImplementedError
    def __iter__(self):
        raise NotImplementedError

def f(s: MySequence):
    for i in range(len(s)):
        print(s[i], end=' ')
    print('end')

f([1, 2, 3, 4]) # should be fine
arr: np.ndarray = np.arange(5)
f(arr) # also fine
f({}) # might be considered fine! Depends on your type checker

Protocols are fairly new, so not all IDEs/type checkers might support them yet. The IDE I use, PyCharm, does. It doesn't like f({}), but it is happy to consider a numpy array a Sequence (big S) though (perhaps not ideal). You can enable runtime checking of protocols by using the runtime_checkable decorator of typing. Be warned, all this does is individually check that each of the Protocols methods can be found on the given object/class. As a result, it can become quite expensive if your protocol has a lot of methods.

2 of 3
1

I think the most practical way to define a sequence in Python is 'A container that supports indexing with integers'.

The Wikipedia definition also holds:

a sequence is an enumerated collection of objects in which repetitions are allowed and order does matter.

To validate if an object is a sequence, I would emulate the logic from the Sequence Protocol:

hasattr(test_obj, "__getitem__") and not isinstance(test_obj, collections.abc.Mapping) 
🌐
Python Like You Mean It
pythonlikeyoumeanit.com › Module2_EssentialsOfPython › SequenceTypes.html
Sequence Types — Python Like You Mean It
Although quite distinct from one another in terms of what they can contain, lists and strings are both types of sequences - they store a finite collection of objects whose ordering matters (e.g. "cat" and "tac" should be considered distinct strings). As such, lists, strings, and the other sequence types in Python all share a common interface for allowing users to inspect, retrieve, and summarize their contents.
🌐
Python Tutorial
pythontutorial.net › home › advanced python › python sequences
Python Sequences
March 27, 2025 - A sequence is a positionally ordered collection of items. And you can refer to any item in the sequence by using its index number e.g., s[0] and s[1]. In Python, the sequence index starts at 0, not 1.
🌐
GeeksforGeeks
geeksforgeeks.org › dsa › sequence-and-series-in-python
Sequence and Series in Python - GeeksforGeeks
July 23, 2025 - A Sequence is an ordered list of numbers following a specific pattern, while a series is the sum of the elements of a sequence. This tutorial will cover arithmetic sequences, geometric sequences, and how to work with them in Python.
🌐
Medium
medium.com › @gauravverma.career › sequence-in-python-705f9904313f
Sequence in Python. Sequence is any ordered set in python… | by Gaurav Verma | Medium
December 7, 2025 - Sequence in Python Sequence is any ordered set in python like List, Tuple, String List: List is mutable and can store any type of object. Tuple: Tuple is immutable and can store any type of …
Find elsewhere
🌐
Patrickwalls
patrickwalls.github.io › mathematicalpython › python › sequences
Sequences - Mathematical Python
This is because a range object is an efficient sequence which yields values only when needed. Use the built-in function list() to convert a range object to a list: digits_range = range(0,10) digits_list = list(digits_range) print(digits_list) ... One of the features of a Python sequence is unpacking where we assign all the entries of a sequence to variables in a single operation.
🌐
Real Python
realpython.com › ref › glossary › sequence
sequence | Python Glossary – Real Python
In Python, a sequence is a collection of ordered objects where each object has an associated integer index that defines its position in the sequence. Sequences allow you to store multiple values in a single container object.
🌐
The Python Coding Stack
thepythoncodingstack.com › the python coding stack › sequences in python (data structure categories #2)
Sequences in Python (Data Structure Categories #2)
June 25, 2024 - And you're likely to see common ... the headline difference between the two terms: A Python sequence is an iterable that you can index using an integer....
🌐
Medium
pythonflood.com › python-sequences-weaving-the-story-of-order-and-logic-23dff398f83e
Python Sequences - Weaving the Story of Order and Logic. | by Rinu Gour | PythonFlood
July 11, 2023 - In Python, a sequence is a collection of objects, arranged in a particular order. A sequence can be either a list, a tuple, or a string…
🌐
TechVidvan
techvidvan.com › tutorials › python-sequences
Python Sequences - Types, Operations, and Functions - TechVidvan
January 13, 2020 - In this article, we will focus only on sequences. So, let’s get started. In Python programming, sequences are a generic term for an ordered set which means that the order in which we input the items will be the same when we access them.
🌐
DataFlair
data-flair.training › blogs › python-sequence
Python Sequence and Collections - Operations, Functions, Methods - DataFlair
April 21, 2026 - A sequence in Python is an ordered collection. A sequence is also a collection but ordered. A Collection is a container data type which means a collection of multiple objects. If a collection is ordered then it is referred as a sequence.
🌐
Wikibooks
en.wikibooks.org › wiki › Python_Programming › Sequences
Python Programming/Sequences - Wikibooks, open books for an open world
But in Python, the colon : allows the square brackets to take two numbers. For any sequence which only uses numeric indexes, this will return the portion which is between the specified indexes.
🌐
Compciv
2017.compciv.org › guide › cookbook › basic-sequences.html
Python Sequence Basics
The following snippet will result in a integer, not a tuple, because the Python interprets (1) as a value enclosed in parentheses: >>> mytuple = (1) >>> type(mytuple) int >>> mytuple 1 · tuple, when invoked as a function (i.e. using parentheses) will create a new tuple object. If no arguments are passed in, the result tuple is empty: ... An iterable object is any kind of sequence.
🌐
YouTube
youtube.com › watch
What is a sequence in Python? - YouTube
Sequences are iterables that have a length. Sequences are ordered collections (they maintain the order of their contents). The most common sequences built-in...
Published: July 10, 2023
🌐
TutorialsPoint
tutorialspoint.com › python-sequence-types
Python Sequence Types
December 18, 2024 - In Python programming, sequence types are fundamental data structures that hold an ordered collection of items. The main sequence types include Lists, Strings, Tuples, and Range objects.
🌐
NxtWave
ccbp.in › blog › articles › sequence-in-python
Sequence in Python: Types, Methods & Examples
Seq in Python is an ordered collection of things. Sequences' primary characteristic is their indexed elements, which allow you to recover any item by using a number that indicates where it is in the sequence.
🌐
Python Morsels
pythonmorsels.com › make-a-sequence
How to make a sequence - Python Morsels
April 3, 2023 - Let's make a Fibonacci class which returns the first n numbers in the Fibonacci sequence. ... class Fibonacci: """Python sequence of the first N Fibonacci numbers (default 100).""" def __init__(self, n=100): self.n = n