Self Typing
August 15, 2025 • 6 min read
Understanding Python's Self type hint for better type safety and method
chaining. Learn how to properly annotate methods that return the current
instance.
Imagine you are writing a class that returns the current object in python such as when you want to allow for method-chaining in a sequence of calls, or using a setter-like method. For the type annotations here, two common ways other devs write this is:
# String forward reference
class MyBuilder:
def __init__(self): self.name = ""
def set_name(self, name: str) -> "MyBuilder":
self.name = name
return self
# Bare class name
class MyBuilder:
def __init__(self): self.name = ""
def set_name(self, name: str) -> MyBuilder:
self.name = name
return self
However, this causes two major problems where:
- Refactoring: The return type of either the string 'MyBuilder' or class name MyBuilder will make refactoring difficult.
- Subclassing: If you subclass, the return type is incorrect.
Instead, you can import Self as the type annotation as such:
from typing import Self # Python 3.11+ else 'from typing_extensions import Self'
class MyBuilder:
def __init__(self): self.name = ""
def set_name(self, name: str) -> Self:
self.name = name
return self
Advantages of This Approach
- Refactoring: No hardcoded class, which means it is resilient to class renaming.
- Easier Subclassing:
Selfis covariant and dynamically binds to self at runtime. Chain methods will now return the correct subclass type. - Readability:
Selfclearly communicates to readers that we are using the same type as the instance.
Questions or feedback? Feel free to reach out!