subtyping
Subtyping is a relation between data types in which any value of the subtype can be used in any context that expects a value of the related supertype.
The relation, also called subtype polymorphism or inclusion polymorphism, is captured by the principle of safe substitution, popularly known as the Liskov substitution principle: code written for the supertype must keep working when given a subtype instance.
Subtyping is distinct from inheritance, since a class can inherit code without being substitutable, and unrelated classes can become subtypes through their structure alone.
Common forms of subtyping include the following:
- Nominal subtyping, where the relation is declared explicitly through inheritance or interface implementation, as in Java or C++.
- Structural subtyping, where the relation follows from the members a type exposes. Python supports this through Protocol classes in the
typingmodule. - Duck typing, the dynamic counterpart of structural subtyping, where compatibility is checked at call time by attempting the operation.
- Behavioral subtyping, which adds constraints on observable behavior, such as preconditions, postconditions, and invariants. Liskov and Wing formalized this behavioral notion, and it’s stronger than what a type checker can verify.
Subtyping interacts with type constructors through variance: parameter types are contravariant, return types are covariant, and mutable generic containers are invariant. Since Python 3.12, type checkers infer variance from how a generic class uses its type parameters instead of assuming invariance.
Related Resources
Tutorial
Python Protocols: Leveraging Structural Subtyping
In this tutorial, you'll learn about Python's protocols and how they can help you get the most out of using Python's type hint system and static type checkers.
For additional information on related topics, take a look at the following resources:
- Exploring Protocols in Python (Course)
- Duck Typing in Python: Writing Flexible and Decoupled Code (Tutorial)
- Python Type Checking (Guide) (Tutorial)
- Inheritance and Composition: A Python OOP Guide (Tutorial)
- Modeling Polymorphism in Django With Python (Tutorial)
- Implementing Interfaces in Python: ABCs and Protocols (Tutorial)
- Object-Oriented Programming (OOP) in Python (Tutorial)
- Python Protocols: Leveraging Structural Subtyping (Quiz)
- Getting to Know Duck Typing in Python (Course)
- Duck Typing in Python: Writing Flexible and Decoupled Code (Quiz)
- Python Type Checking (Course)
- Python Type Checking (Quiz)
- Inheritance and Composition: A Python OOP Guide (Course)
- Inheritance and Composition: A Python OOP Guide (Quiz)
- Python Interfaces: Object-Oriented Design Principles (Course)
- Implementing Interfaces in Python: ABCs and Protocols (Quiz)
- A Conceptual Primer on OOP in Python (Course)
- Intro to Object-Oriented Programming (OOP) in Python (Course)
- Object-Oriented Programming (OOP) in Python (Quiz)