When using type hints combined with mypy, I want to define a generic class that allows access to an attribute that is only available for some of the generic classes. I am wondering how to define this in Python type hints.
For instance, let's have the following example:
class SomeObject:
pass
class SomeObjectWithAttr:
def __init__(self, attr):
self.attr = attr
class AppendListWithAttrs:
def __init__(self):
self._list = []
self._attrs = []
def append(self, obj, record_attr=False):
self._list.append(obj)
if record_attr:
self._attrs.append(obj.attr)
l = AppendListWithAttrs()
l.append(SomeObject())
l.append(SomeObjectWithAttr())
l.append(SomeObjectWithAttr(), record_attr=True)
I have attempted annotating this, but mypy can't seem to get happy. This is my best attempt:
from typing import Generic, TypeVar, Protocol, overload, Literal, Union
T = TypeVar("T")
class HasAttr(Protocol):
attr: str
class AppendListWithAttrs(Generic[T]):
def __init__(self):
self._list: list[T] = []
self._attrs: list[str] = []
@overload
def append(self: 'AppendListWithAttrs[HasAttr]', obj: HasAttr, record_attr: Literal[True]): ...
@overload
def append(self, obj: T, record_attr: Literal[False]): ...
def append(self, obj: T, record_attr: bool = False):
self._list.append(obj)
if record_attr:
self._attrs.append(obj.attr)
This is also not quite correct, but I'm effectively looking for a way to tell mypy that T can be anything, but if it is bounded by HasAttr, it may access this attr. Perhaps something like subclassing T with HasAttr, but maybe I'm looking at this wrong.
How would you annotate this?