英文:
Unbound TypeVar variable in overloaded class
问题
我有以下的代码,这是一个简化版本的Python实体组件系统:
from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar, overload
if TYPE_CHECKING:
from collections.abc import Generator
T = TypeVar("T")
T1 = TypeVar("T1")
T2 = TypeVar("T2")
class Registry:
def __init__(self) -> None:
self._next_game_object_id = 0
self._components: dict[type[T], set[int]] = {}
self._game_objects: dict[int, dict[type[T], T]] = {}
@overload
def get_components(
self,
component: type[T],
) -> Generator[tuple[int, T], None, None]:
...
@overload
def get_components(
self,
component: type[T],
component_two: type[T1],
) -> Generator[tuple[int, T, T1], None, None]:
...
@overload
def get_components(
self,
component: type[T],
component_two: type[T1],
component_three: type[T2],
) -> Generator[tuple[int, T, T1, T2], None, None]:
...
def get_components(self, *components: type[T]) -> Generator[tuple[int, tuple[T, ...]], None, None]:
game_object_ids = set.intersection(
*(self._components[component] for component in components),
)
for game_object_id in game_object_ids:
yield game_object_id, tuple(
self._game_objects[game_object_id][component]
for component in components
)
然而,我遇到了一些mypy错误,我无法弄清楚如何解决。其中一个错误说TypeVar T
未绑定,另一个说get_components
不接受所有可能的签名 1、2 和 3 的参数。我该如何修复这些错误?
英文:
I have this following code which is a simplified version of an entity component system in python:
from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar, overload
if TYPE_CHECKING:
from collections.abc import Generator
T = TypeVar("T")
T1 = TypeVar("T1")
T2 = TypeVar("T2")
class Registry:
def __init__(self) -> None:
self._next_game_object_id = 0
self._components: dict[type[T], set[int]] = {}
self._game_objects: dict[int, dict[type[T], T]] = {}
@overload
def get_components(
self,
component: type[T],
) -> Generator[tuple[int, T], None, None]:
...
@overload
def get_components(
self,
component: type[T],
component_two: type[T1],
) -> Generator[tuple[int, T, T1], None, None]:
...
@overload
def get_components(
self,
component: type[T],
component_two: type[T1],
component_three: type[T2],
) -> Generator[tuple[int, T, T1, T2], None, None]:
...
def get_components(self, *components: type[T]) -> Generator[tuple[int, tuple[T, ...]], None, None]:
game_object_ids = set.intersection(
*(self._components[component] for component in components),
)
for game_object_id in game_object_ids:
yield game_object_id, tuple(
self._game_objects[game_object_id][component]
for component in components
)
However, I'm getting some mypy errors which I cannot figure out. One of which says that the TypeVar T
is unbound and another says that get_components
does not accept all possible arguments of signature 1, 2, and 3. How can I fix these errors?
答案1
得分: 1
以下是翻译好的部分:
from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar, overload, Generic
if TYPE_CHECKING:
from collections.abc import Generator
T = TypeVar("T")
T1 = TypeVar("T1")
T2 = TypeVar("T2")
class Registry(Generic[T, T1, T2]):
def __init__(self) -> None:
self._next_game_object_id = 0
self._components: dict[type[T | T1 | T2], set[int]] = {}
self._game_objects: dict[int, dict[type[T | T1 | T2], T | T1 | T2]] = {}
@overload
def get_components(
self,
__component: type[T],
) -> Generator[tuple[int, tuple[T]], None, None]:
...
@overload
def get_components(
self,
__component: type[T],
__component_two: type[T1],
) -> Generator[tuple[int, tuple[T, T1]], None, None]:
...
@overload
def get_components(
self,
__component: type[T],
__component_two: type[T1],
__component_three: type[T2],
) -> Generator[tuple[int, tuple[T, T1, T2]], None, None]:
...
def get_components(
self,
*components: type[T | T1 |T2]
) -> Generator[tuple[int, tuple[T | T1 | T2, ...]], None, None]:
game_object_ids = set.intersection(
*(self._components[component] for component in components),
)
for game_object_id in game_object_ids:
yield game_object_id, tuple(
self._game_objects[game_object_id][component]
for component in components
)
注意:在代码中我替换了HTML实体 "
为普通的双引号 "
以保持代码的正确性。
英文:
Possible solution:
from __future__ import annotations
from typing import TYPE_CHECKING, TypeVar, overload, Generic
if TYPE_CHECKING:
from collections.abc import Generator
T = TypeVar("T")
T1 = TypeVar("T1")
T2 = TypeVar("T2")
class Registry(Generic[T, T1, T2]):
def __init__(self) -> None:
self._next_game_object_id = 0
self._components: dict[type[T | T1 | T2], set[int]] = {}
self._game_objects: dict[int, dict[type[T | T1 | T2], T | T1 | T2]] = {}
@overload
def get_components(
self,
__component: type[T],
) -> Generator[tuple[int, tuple[T]], None, None]:
...
@overload
def get_components(
self,
__component: type[T],
__component_two: type[T1],
) -> Generator[tuple[int, tuple[T, T1]], None, None]:
...
@overload
def get_components(
self,
__component: type[T],
__component_two: type[T1],
__component_three: type[T2],
) -> Generator[tuple[int, tuple[T, T1, T2]], None, None]:
...
def get_components(
self,
*components: type[T | T1 |T2]
) -> Generator[tuple[int, tuple[T | T1 | T2, ...]], None, None]:
game_object_ids = set.intersection(
*(self._components[component] for component in components),
)
for game_object_id in game_object_ids:
yield game_object_id, tuple(
self._game_objects[game_object_id][component]
for component in components
)
Explanations:
- Inheriting from
typing.Generic
binds theTypeVar
s to the class through making it a generic class which depends on thoseTypeVar
s (More on Generics) - Generalizing the method definition of
get_components
is crucial to accept all the different types that can occur through the overloads - wrapping all the
T
,T, T1
andT, T1, T2
inside atuple[...]
as this ensures consistency with the return annotation of the now generalized method definition - Making the components in the
@overload
ed methods positional only. This behaviour of*args
and@overload
seems not very well documented, only through a resolved issue on GitHub
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论