[英]Python 3.6 type hinting for a function accepting generic class type and instance type of the same generic type
我有一个带有以下签名的 function:
def wait_for_namespaced_objects_condition(
obj_type: Type[NamespacedAPIObject],
obj_condition_fun: Callable[[NamespacedAPIObject], bool],
) -> List[NamespacedAPIObject]:
...
这里的重要部分是NamespacedAPIObject
参数。 此 function 将obj_type
作为类型规范,然后创建该类型(类)的对象(实例)。 然后将该类型的一些其他对象添加到列表中,然后使用obj_condition_fun
过滤并作为List[NamespacedAPIObject]. This works fine and also evaluates OK with
List[NamespacedAPIObject]. This works fine and also evaluates OK with
。
现在,我想让这个 function 通用,以便可以使用它的任何子类型来代替NamespacedAPIObject
。 我的尝试是这样做:
T = TypeVar("T", bound=NamespacedAPIObject)
def wait_for_namespaced_objects_condition(
obj_type: Type[T],
obj_condition_fun: Callable[[T], bool],
) -> List[T]:
但是Type[T]
是TypeVar
,所以它不是 go 的方式。 问题是: obj_type
参数的类型应该是什么才能使这项工作? 我尝试了Generic[T]
,这对我来说似乎是最合理的,但它不起作用。 如果我把obj_type: T
放在那里, mypy
评估结果还可以,但对我来说似乎是错误的。 在我看来,这意味着obj_type
是 class 的一个实例,它是NamespacedAPIObject
的子类型,而我想说的是“T 是代表NamespacedAPIObject
子类型的 class 变量。如何解决这个问题?
[编辑] 更好地解释一下(见下面的评论)为什么Type[T]
对我不起作用:在我的情况下, T 的所有子类型都实现 class 方法objects()
,但是当我尝试像这样编写我的代码时:
obj_type.objects()
mypy
返回:
pytest_helm_charts/utils.py:36: error: "Type[T]" has no attribute "objects"
但是 Type[T] 是 TypeVar,所以它不是 go 的方式。
不,你在正确的轨道上 - TypeVar
绝对是通往 go 的方式。 这里的问题在于pykube.objects.APIObject
class 被包装在mypy
无法处理的装饰器中。 为pykube.objects
添加类型存根将解决该问题。 创建一个目录_typeshed/pykube
并为pykube
添加最小类型存根:
_typeshed/pykube/__init__.pyi
:
from typing import Any def __getattr__(name: str) -> Any: ... # incomplete
_typeshed/pykube/objects.pyi
:
from typing import Any, ClassVar, Optional from pykube.query import Query def __getattr__(name: str) -> Any: ... # incomplete class ObjectManager: def __getattr__(self, name: str) -> Any: ... # incomplete def __call__(self, api: Any, namespace: Optional[Any] = None) -> Query: ... class APIObject: objects: ClassVar[ObjectManager] def __getattr__(self, name: str) -> Any: ... # incomplete class NamespacedAPIObject(APIObject): ...
现在运行
$ MYPYPATH=_typeshed mypy pytest_helm_charts/
正确解析obj_type.objects
:
T = TypeVar('T', bound=NamespacedAPIObject)
def wait_for_namespaced_objects_condition(obj_type: Type[T]) -> List[T]:
reveal_type(obj_type.objects)
Output:
pytest_helm_charts/utils.py:29: note: Revealed type is 'pykube.objects.ObjectManager'
为什么Type[T]
不是 go 的方式? 在我看来,它与其中一个示例非常相似:
然而,使用 Type[] 和具有上限的类型变量,我们可以做得更好:
U = TypeVar('U', bound=User)
def new_user(user_class: Type[U]) -> U:
...
现在,当我们使用 User 的特定子类调用 new_user() 时,类型检查器将推断结果的正确类型:
joe = new_user(BasicUser) # Inferred type is BasicUser
如果使用classmethod
:
from typing import Callable, Type, List, TypeVar
T = TypeVar('T', bound=Base)
class Base:
@classmethod
def objects(cls: Type[T]) -> List[T]:
...
def run(self):
...
class Derived(Base):
def run(self):
...
def foo(d: Derived) -> bool:
return True
def wait_for_namespaced_objects_condition(
obj_type: Type[T],
obj_condition_fun: Callable[[T], bool],
) -> List[T]:
a = obj_type.objects()
return a
wait_for_namespaced_objects_condition(Derived, foo)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.