Reputation: 26090
Trying to implement nodes and trees inheritance hierarchy that respects mypy
, I have next classes:
from __future__ import annotations
import dataclasses
from typing import Generic, TypeVar, Optional
GenericNodeValue = TypeVar('GenericNodeValue')
@dataclasses.dataclass
class BaseNode(Generic[GenericNodeValue]):
value: GenericNodeValue
parent: Optional[BaseNode] = None
left: Optional[BaseNode] = None
right: Optional[BaseNode] = None
@property
def dummy(self) -> BaseNode:
return self
GenericNode = TypeVar('GenericNode', bound=BaseNode)
class BaseTree(Generic[GenericNode]):
def __init__(self):
self.root: Optional[GenericNode] = None
def get_dummy(self, node: GenericNode) -> GenericNode:
return node.dummy
@dataclasses.dataclass
class RedBlackTreeNode(BaseNode[int]):
red: bool = False
class RedBlackTree(BaseTree[RedBlackTreeNode]):
def get_dummy2(self, node: RedBlackTreeNode) -> RedBlackTreeNode:
return node.dummy
But mypy
returns error:
test.py:29: error: Incompatible return value type (got "BaseNode[Any]", expected "GenericNode")
test.py:39: error: Incompatible return value type (got "BaseNode[Any]", expected "RedBlackTreeNode")
Is there any way I can implement my logic using python typing?
Upvotes: 1
Views: 1134
Reputation: 10477
The trick is to add an annotation to the self
argument. For example:
T = TypeVar('T')
V = TypeVar('V', bound='BaseNode')
@dataclasses.dataclass
class BaseNode(Generic[T]):
value: T
parent: Optional[BaseNode[T]] = None
left: Optional[BaseNode[T]] = None
right: Optional[BaseNode[T]] = None
@property
def dummy(self: V) -> V:
return self
@property
def dummy_parent(self: V) -> V:
assert isinstance(self.parent, type(self))
return self.parent
By the way, you should add the type argument to the optional properties so they don't become BaseNode[Any]
, losing the benefit of generics!
Upvotes: 2