Restricting Inheritance in Python using final decorator
Using typing module to prevent accidental overriding of critical methods
Why would you ever need to prevent a user from subclassing a specific method or even an entire class?
Imagine a case where you have a central library data_science_tools that is used across multiple Machine Learning projects. It contains, among other things, a module with a class to serialize trained ML models and store them in AWS S3.
We want to ensure that all models will be stored in a central model storage bucket instead of individual project buckets, so we define the path in upload_to_s3 method.
The Problem: Changed Behavior in the Subclass
In this example, it’s possible to change the behavior of the method by subclassing ModelSaver class and overriding upload_to_s3 method:
Now the models from this project will be stored in another bucket - exactly wanted we wanted to avoid. So how to go around it?
Solution: Introducing the final decorator
Python’s typing module contains a decorator called final, which restricts inheritance and method overriding via type checking. If a user has a properly configured environment with type checking hints (for example, with mypy), the type checker will raise an error when reading this block
since upload_by_s3 is now protected from overriding in any subclass of ModelSaver.
When to Use
Use it for preventing accidental method overrides when you're working with teams where developers are expected to use static type checkers (like MyPy). It can help catch unintentional mistakes during development but does not prevent overriding at runtime.
When Not to Use
Avoid it when strict runtime enforcement is required for consistent behavior. If you need to prevent method overriding completely, especially at runtime, the
finaldecorator is not sufficient, as it can be bypassed easily without a type checker.
Another Way To Restrict Inheritance
While the final decorator helps with static checks, it can be easily bypassed at runtime. For stronger enforcement of method and inheritance restrictions, there is a better alternative
Using a Metaclass
The
NoOverrideMetametaclass checks whether the methodupload_to_s3is defined in the class (dctrefers to the class dictionary containing all its attributes and methods).If the
upload_to_s3method is found in the class, aTypeErroris raised, ensuring that no subclass can override it.Subclasses can still inherit from
ModelSaver, but they cannot override theupload_to_s3method. Any attempt to do so will result in aTypeError.
What Are Metaclasses? 🛠️
In Python, a metaclass is a class for classes. Essentially, it defines how a class behaves. While regular classes define how instances of a class behave, metaclasses define how the class itself behaves, including how it's created, initialized, and modified.
You can think of a metaclass as the blueprint for a class—it controls the class's creation, structure, and behavior. In most cases, metaclasses aren't something you need to deal with directly, but they become extremely powerful when you need to customize class creation or restrict certain behaviors (like overriding methods) in subclasses.
Conclusion
To prevent method overriding while allowing subclassing, here are several techniques:
finaldecorator: Prevents overriding at the static analysis level (using type checking tools like MyPy).Metaclasses: Stronger approach that prevents overriding at runtime.
These techniques provide flexibility for subclassing while ensuring critical methods are not overridden.







