简体   繁体   English

如何键入提示其联合类型在 Python 中变窄的变量?

[英]How can I type hint a variable whose Union type gets narrowed in Python?

I have a few helper functions that get passed a type converter and a value.我有一些辅助函数可以传递一个类型转换器和一个值。 Based on checks that happen later, I decide which helper function to call.根据稍后发生的检查,我决定调用哪个助手 function。

How can I correctly annotate the types to narrow the foo variable's type below so that it can pass a mypy check?如何正确注释类型以缩小下面的foo变量的类型,以便它可以通过mypy检查?

from typing import Type, Union


def do_something(
        typ: Type[Union[float, int]],
        bar: Union[float, int]
) -> Union[float, int]:
    return bar


foo: Type[Union[float, int, str]] = float

assert foo is float or foo is int

do_something(foo, 4.4)

Bonus points if the solution can ensure that typ is a converter to the type of bar !如果解决方案可以确保typbar类型的转换器,则加分!

Well, here's something that works, but maybe there's a better way without a cast:好吧,这里有一些可行的方法,但也许没有演员表有更好的方法:

from typing import Type, Union, cast


def do_something(
        typ: Type[Union[float, int]],
        bar: Union[float, int]
) -> Union[float, int]:
    return bar


foo: Type[Union[float, int, str]] = float

assert foo is float or foo is int

do_something(cast(Type[float], foo), 4.4)

The tool you want here is a TypeVar .您在这里需要的工具是TypeVar

Essentially, a TypeVar let's you say "I don't know quite what type this is (although I may have some ideas), but it'll be the same one throughout its use in this function."本质上,TypeVar 让你说“我不太清楚这是什么类型(尽管我可能有一些想法),但在 function 中的整个使用过程中,它都是同一个类型。” (or in some cases throughout its use in a class) (或者在某些情况下,它在一个类中的整个使用过程中)

For example, this ensures that each thing you had a Union for gets the same value on any given call to the function.例如,这可确保您拥有 Union 的每个事物在对 function 的任何给定调用中都获得相同的值。

from typing import Type, TypeVar

# Define a type variable
# and list the things it is allowed to represent
NumberType = TypeVar("NumberType", int, float) 

def do_something(
        typ: Type[NumberType],
        bar: NumberType
) -> NumberType:
    return bar

This can be legally called with do_something(float, 2.5) in which case it will return a float, or it can be called with do_something(int, 2) in which case it will return an int.这可以合法地用do_something(float, 2.5)调用,在这种情况下它将返回一个浮点数,或者它可以用do_something(int, 2)调用,在这种情况下它将返回一个 int。 That is, it makes sure that all the things match.也就是说,它确保所有的东西都匹配。

Because you called it a type converter, I suspect that you may not actually want all the types to match.因为您将其称为类型转换器,所以我怀疑您实际上可能并不希望所有类型都匹配。 If you need to constrain on more than one Type Variable, you can do so with something more like如果您需要约束多个类型变量,则可以使用类似

from typing import Callable, TypeVar

# Define a type variable
# and list the things it is allowed to represent
NumberTypeIn = TypeVar("NumberTypeIn", int, float)
NumberTypeOut = TypeVar("NumberTypeOut", int, float) 

def do_something(
        converter: Callable[[NumberTypeIn], NumberTypeOut],
        bar: NumberTypeIn
) -> NumberTypeOut:
    return type_(bar)

As to the original question of narrowing unions of Type[] s, as you've noticed is doesn't work.至于缩小Type[]的联合的原始问题,正如您所注意到的那样is行不通的。 Instead you can use issubclass , as in相反,您可以使用issubclass ,如

assert not issubclass(foo, str)

or或者

assert issubclass(foo, int) or issubclass(foo, float) 

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM