I am trying to create a base class for a 2 dimensional linked list. The code below is already working fine from a functionality point of view. The problem is, when I subclass LinkedList2D to create a more specific version all my attributes (up, down, before, after) and my generator functions still resolve the type hints to LinkedList2D and not to the more specific subclass, which is necessary because I want to access the additional attributes and methods of it.
I have a feeling, that I need to use bound generics somehow but I can't seem to wrap my head around it.
class LinkedList2D:
up: Optional[LinkedList2D]
down: Optional[LinkedList2D]
before: Optional[LinkedList2D]
after: Optional[LinkedList2D]
def __init__(self) -> None:
self.up = None
self.down = None
self.before = None
self.after = None
def iterate_children(self) -> Generator[LinkedList2D, None, None]:
link = self.down
while link:
yield link
link = link.after
def iterate_tree(self) -> Generator[LinkedList2D, None, None]:
for child in self.iterate_children():
if child:
yield child
yield from child.iterate_children()
def get_children(self) -> List[LinkedList2D]:
return list(self.iterate_children())
def insert_under(self, op: LinkedList2D) -> bool:
if op:
if op.down:
self.insert_before(op.down)
op.down = self
self.up = op
return True
def insert_under_last(self, op: LinkedList2D) -> bool:
self.up = op
if op:
if op.down:
last = self.get_children()[-1]
self.insert_after(last)
else:
op.down = self
return True
def insert_after(self, obj: LinkedList2D) -> bool:
if obj:
if obj.after:
obj.after.before = self
obj.after = self
self.after = obj.after
self.up = obj.up
self.before = obj
return True
def insert_before(self, obj: LinkedList2D) -> bool:
if obj:
if obj.before:
obj.before.after = self
obj.before = self
self.up = obj.up
self.before = obj.before
self.after = obj
return True
The generic version would look like this, I think. I used bound to make sure the potential instances are subclasses of LinkedList2D and implement the necessary functions and attributes.
T = TypeVar("T", bound="LinkedList2D")
class LinkedList2D(Generic[T]):
up: Optional[T]
down: Optional[T]
before: Optional[T]
after: Optional[T]
def __init__(self) -> None:
...
def iterate_children(self) -> Generator[T, None, None]:
...
def iterate_tree(self) -> Generator[T, None, None]:
...
def get_children(self) -> List[T]:
...
def insert_under(self, op: T) -> bool:
if op:
if op.down:
self.insert_before(op.down)
op.down = self
self.up = op
return True
def insert_under_last(self, op: T) -> bool:
...
def insert_before(self, obj: T) -> bool:
...
The Problem is, that now pylance is complaining about the line op.down = self in the insert_under method:
Cannot assign member "down" for type "LinkedList2D[T@LinkedList2D]"
Expression of type "LinkedList2D[T@LinkedList2D]" cannot be assigned to member "down" of class "LinkedList2D[T@LinkedList2D]"
Type "LinkedList2D[T@LinkedList2D]" cannot be assigned to type "T@LinkedList2D | None"
Type "LinkedList2D[T@LinkedList2D]" cannot be assigned to type "T@LinkedList2D"
Cannot assign to "None"PylancereportGeneralTypeIssues
Any ideas and hints are greatly appreciated. Thanks