将类型指定为数字列表(整数和/或浮点数)? [英] Specifying a type to be a List of numbers (ints and/or floats)?

查看:39
本文介绍了将类型指定为数字列表(整数和/或浮点数)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何指定一个函数可以采用整数或浮点数的数字列表?

How do I specific a function can take a list of numbers which can be ints or floats?

我尝试使用 Union 制作一个新类型,如下所示:

I tried making a new type using Union like so:

num = Union[int, float]

def quick_sort(arr: List[num]) -> List[num]:
    ...

然而,mypy 不喜欢这样:

However, mypy didn't like this:

 quickSortLomutoFirst.py:32: error: Argument 1 to "quickSortOuter" has
 incompatible type List[int]; expected List[Union[int, float]]  

是否有包含整数和浮点数的类型?

Is there a Type that encompasses ints and floats?

推荐答案

对您的问题的简短回答是您应该使用 TypeVars 或 Sequence -- using List[Union[int, float]]实际上可能会在您的代码中引入错误!

The short answer to your question is you should use either TypeVars or Sequence -- using List[Union[int, float]] would actually potentially introduce a bug into your code!

简而言之,问题在于根据 PEP 484 类型系统(以及许多其他类型系统——例如 Java、C#...),列表是不变的.您正在尝试使用该列表,就好像它是 covariant 一样.您可以在此处了解有关协方差和不变性的更多信息和 此处,但也许是您的代码原因的示例可能是非类型安全的可能有用.

In short, the problem is that Lists are invariant according to the PEP 484 type system (and in many other typesystems -- e.g. Java, C#...). You're attempting to use that list as if it were covariant instead. You can learn more about covariance and invariance here and here, but perhaps an example of why your code is potentially un-typesafe might be useful.

考虑以下代码:

from typing import Union, List

Num = Union[int, float]

def quick_sort(arr: List[Num]) -> List[Num]:
    arr.append(3.14)  # We deliberately append a float
    return arr

foo = [1, 2, 3, 4]  # type: List[int]

quick_sort(foo)

# Danger!!!
# Previously, `foo` was of type List[int], but now
# it contains a float!? 

如果允许此代码进行类型检查,我们就破坏了我们的代码!任何依赖于 foo 完全是 List[int] 类型的代码现在都会中断.

If this code were permitted to typecheck, we just broke our code! Any code that relies on foo being of exactly type List[int] would now break.

或者更准确地说,即使 intUnion[int, float] 的合法子类型,也并不意味着 List[int]List[Union[int, float]] 的子类型,反之亦然.

Or more precisely, even though int is a legitimate subtype of Union[int, float], that doesn't mean that List[int] is a subtype of List[Union[int, float]], or vice versa.

如果我们可以接受这种行为(我们可以接受 quick_sort 决定向输入数组中注入任意整数或浮点数),修复方法是手动注释 fooList[Union[int, float]]:

If we're ok with this behavior (we're ok with quick_sort deciding to inject arbitrary ints or floats into the input array), the fix is to manually annotate foo with List[Union[int, float]]:

foo = [1, 2, 3, 4]  # type: List[Union[int, float]]

# Or, in Python 3.6+
foo: List[Union[int, float]] = [1, 2, 3, 4]

也就是说,预先声明 foo 尽管只包含整数,但也意味着包含浮点数.这可以防止我们在调用 quick_sort 后错误地使用列表,完全回避问题.

That is, declare up-front that foo, despite only containing ints, is also meant to contain floats as well. This prevents us from incorrectly using the list after quick_sort is called, sidestepping the issue altogether.

在某些情况下,这可能是您想要做的.不过对于这种方法,可能不是.

In some contexts, this may be what you want to do. For this method though, probably not.

如果我们对这种行为感到满意,并且希望 quick_sort 保留列表中最初的任何类型,则可以想到两种解决方案:

If we're not ok with this behavior, and want quick_sort to preserve whatever types were originally in the list, two solutions come to mind:

第一个是使用协变类型而不是列表——例如,Sequence:

The first is to use a covariant type instead of list -- for example, Sequence:

from typing import Union, Sequence

Num = Union[int, float]

def quick_sort(arr: Sequence[Num]) -> Sequence[Num]:
    return arr

事实证明 Sequence 或多或少类似于 List,除了它是不可变的(或者更准确地说,Sequence 的 API 不包含任何让您改变列表的方法).这让我们可以安全地避开上面的错误.

It turns out Sequence is more or less like List, except that it's immutable (or more precisely, Sequence's API doesn't contain any way of letting you mutate the list). This lets us safely sidestep the bug we had up above.

第二种解决方案是更精确地键入数组,并坚持它必须包含所有整数或所有浮点数,不允许将两者混合.我们可以使用带有值限制的TypeVars:

The second solution is to type your array more precisely, and insist that it must contain either all ints or all floats, disallowing a mixture of the two. We can do so using TypeVars with value restrictions:

from typing import Union, List, TypeVar 

# Note: The informal convention is to prefix all typevars with
# either 'T' or '_T' -- so 'TNum' or '_TNum'.
TNum = TypeVar('TNum', int, float)

def quick_sort(arr: List[TNum]) -> List[TNum]:
    return arr

foo = [1, 2, 3, 4]  # type: List[int]
quick_sort(foo)

bar = [1.0, 2.0, 3.0, 4.0]  # type: List[float]
quick_sort(foo)

这也将防止我们像上面那样意外地混合"类型.

This will also prevent us from accidentally "mixing" types like we had up above.

我建议使用第二种方法——它更精确一点,并且可以防止您在通过快速排序函数传递列表时丢失有关列表包含的确切类型的信息.

I would recommend using the second approach -- it's a bit more precise, and will prevent you from losing information about the exact type a list contains as you pass it through your quicksort function.

这篇关于将类型指定为数字列表(整数和/或浮点数)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆