如何键入一个接受 class 或 class 实例和 returns class 实例的函数?

How to type a function that takes either a class, or an instance of the class, and returns an instance of that class?

我想键入一个函数,该函数可以采用 class 类型或 class 的实例,然后 return 相同 [=17= 的实例].例如:

from typing import Type, TypeVar, Union

DT = TypeVar("DT")

def tmap(dest_type_or_obj: Union[DT, Type[DT]]) -> DT:
    if isinstance(dest_type_or_obj, type):
        dest_obj = dest_type_or_obj()
    else:
        dest_obj = dest_type_or_obj
    return dest_obj

class Dest:
    pass

instance_dest = tmap(Dest())  # Works fine

type_dest = tmap(Dest)  # [arg-type] mypy(error)
# Argument 2 to "map" of "ObjectMapper" has incompatible type "Type[Dest]"; expected "Type[<nothing>]"

您应该将 Dest class 绑定到 TypeVar,以防止出现 Type[<nothing>] 错误:

from typing import Type, TypeVar, Union


class Dest:
    pass


DT = TypeVar("DT", bound=Dest)


def tmap(dest_type_or_obj: Union[DT, Type[DT]]) -> DT:
    if isinstance(dest_type_or_obj, type):
        dest_obj = dest_type_or_obj()
    else:
        dest_obj = dest_type_or_obj
    return dest_obj


instance_dest = tmap(Dest())
print((type(instance_dest)))
type_dest = tmap(Dest) 
print((type(type_dest)))
# output
<class '__main__.Dest'>
<class '__main__.Dest'>

虽然在技术上是等效的,但 MyPy 需要 separate both cases using overload:

@overload
def tmap(dest_type_or_obj: Type[DT]) -> DT:
    ...
@overload
def tmap(dest_type_or_obj: DT) -> DT:
    ...

这使 MyPy 能够在实例和类型情况下正确推断类型变量。

reveal_type(tmap(Dest()))  # note: Revealed type is "__main__.Dest*"

reveal_type(tmap(Dest))    # note: Revealed type is "__main__.Dest*"