我偶尔会遇到这样的情况:
from typing import Generic, TypeVar
T = TypeVar('T')
class Widget(Generic[T]):
content: T
class Jibbit(Generic[T]):
element: T
class ThingHolder:
thing: Widget | Jibbit
在Python标准库中,这种情况出现在logging.handlers.QueueListener
中,其中QueueListener.queue
属性相当于上面的ThingHolder.thing
。
现在我想转换ThingHolder
,使其由它所持有的thing
的类型参数化,以便我可以区分,例如,ThingHolder[Widget[int]]
和ThingHolder[Jibbit[int]]
。
如何用TypeVar
正确拼写这个?如果我写
Thing = TypeVar('Thing', bound=Widget | Jibbit)
则会得到一个错误,因为我没有为两个参数化类型指定参数。
似乎应该在bound=
本身中参数化类型,而不是尝试参数化新的类型变量:
Thing = TypeVar('Thing', bound=Widget[Any] | Jibbit[Any])
class ThingHolder(Generic[Thing]):
thing: Thing
def __init__(self, thing: Thing) -> None:
self.thing = thing
我最初认为这不会工作,因为"内部"类型参数没有写在定义的任何地方。但它确实有效:
# OK
w_int: Widget[int] = Widget(1)
th_w_int: ThingHolder[Widget[int]] = ThingHolder(w_int)
# OK
w_str: Widget[str] = Widget("hello")
th_w_str: ThingHolder[Widget[str]] = ThingHolder(w_str)
# Errors!
th_w_str = ThingHolder(w_int)
th_w_int = ThingHolder(w_str)
reveal_type(ThingHolder(Jibbit(None)))
# __main__.ThingHolder[__main__.Jibbit[None]]
reveal_type(ThingHolder(Jibbit([1,2,3])))
# __main__.ThingHolder[__main__.Jibbit[builtins.list[builtins.int]]]
我认为它有效,因为像Widget[int]
这样的东西确实是Widget[Any] | Jibbit[Any]
的子类型,而像list[int]
这样的东西不是。显然,Mypy足够聪明,可以跟踪"内部"。类型,即使它们没有显式地写在类定义中。而且,如果您有机会在内部参数中注入自己的类型变量,您可能会因为使用错误的内部参数类型方差而意外地把它搞砸。