给出:
from typing import Callable, Generic, TypeVar
T = TypeVar("T")
class Factory(Generic[T]):
def __call__(self) -> T:
...
class TruthyFactory(Factory[bool]):
def __call__(self) -> bool:
return True
def falsey_factory() -> bool:
return False
def class_consumer(factory: type[Factory[T]]) -> T:
...
def function_consumer(factory: Callable[[], T]) -> T:
...
# type hint for cls_ret is `bool`
cls_ret = class_consumer(TruthyFactory)
# type hint for fn_ret is `bool`
fn_ret = function_consumer(falsey_factory)
对于一个同时使用两种参数类型的函数,签名(类型提示)是什么样子的?
也就是说,函数签名为:def either_consumer(factory: ???) -> T: ...
我尝试使用type[Factory[T]] | Callable[[], T]
,但它不适用于子类Factory[T]
的类型。返回类型提示成为类的类型。我相信这是因为类匹配Callable规范-这是否具有更高的亲和力,是否有方法修改这种行为?
def either_consumer(factory: type[Factory[T]] | Callable[[], T]) -> T:
# needs more stringent boolean logic
if isinstance(factory, type):
return factory()()
return factory()
# type hint for cls_ret is wrongly `TruthyFactory`
cls_ret = either_consumer(TruthyFactory)
# type hint for fn_ret is correctly `bool`
fn_ret = either_consumer(falsey_factory)
2条答案
按热度按时间vuktfyat1#
我不确定我是否真的建议这样做,但是考虑到
Factory
是一个不带参数的可调用对象,它返回一个不带参数的可调用对象,并返回一个T
。参数类型。一个小的类型代数可以让你重构为
当你调用
factory
时,你要么得到了想要的boolean值,要么得到了一个可调用对象,然后再次调用它来得到一个boolean值。我更倾向于让
consumer
严格地接受Callable[[], T]
,并让 caller 负责示例化一个工厂类,以获得一个类型为Callable[[], T]
的对象。hujrc8aj2#
好吧,我找到了一个答案(至少在vscode中使用了pyright)。
将参数类型设置为
Callable[[], T] | type[Factory[T]]
可以工作,但type[Factory[T]] | Callable[[], T]
不能。type[Callable[[], T] | Factory[T]]
也可以。我更喜欢第二种选择,但我不知道这是否完全正确,或者它只是碰巧起作用的未定义行为。我不能规范地说为什么......也许函数引用的“类型”是根据类型系统的 * 签名 *?这些参数的顺序很重要,我还假设类型系统匹配联合中的最后一个匹配类型?
第一个选项只适用于
pyright
。第二个选项适用于pyright
和jetbrains'
。我没有测试过mypy
。完整示例:
重新排列@chepner的答案也有效,但不受限制
Callable[[], T | Callable[[], T]]
在更多的实验中,这似乎完全不一致。