I have a class Thing that represents some thing and a class ThingCollection that manages a collection of such things. Like this:
class Thing:
def __init__(self, a: int) -> None:
self.a = a
class ThingCollection:
def __init__(self) -> None:
self.things = []
# ...
def load(self, things_to_load) -> None:
# Simplified, would maybe load from a file
self.things = [Thing(**x) for x in things_to_load]
This can be used like this:
coll = ThingCollection()
coll.load([{"a": 12}])
Now, I'd like to have subclasses of Things and manage those with the same ThingCollection. Like this:
class ExtendedThing(Thing):
def __init__(self, a: int, b: int) -> None:
super().__init__(a)
self.b = b
class ThingCollection2:
def __init__(self) -> None:
self.things = []
# ...
def load(self, things_to_load, which_class) -> None:
self.things = [which_class(**x) for x in things_to_load]
This works fine:
coll2 = ThingCollection2()
coll2.load([{"a": 12, "b": 13}], ExtendedThing)
print(coll2.things[0].b)
However, if I want to add type hints, the type checker complains. I.e., changing the signature of load to:
def load(self, things_to_load, which_class: Type[Thing]) -> None:
will lead to a complaint of Cannot access member "b" for type "Thing" Member "b" is unknown for the print statement above.
My questions:
- What are alternative approaches that resolve this problem? One would be to also subclass the
ThingCollectionto, e.g.,ExtendedThingCollection, but that feels clumsy and redundant. - What are pros and cons of the different approaches other than related to the type hint problem above?
- What would be the right terminology to ask the question I'm asking? Are there design patterns that are relevant with regard to this question?