将类型指定为数字列表(整数和/或浮点数)? - python

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

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

num = Union[int, float]

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

但是,mypy不喜欢这样:

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

是否有包含int和float的Type?

参考方案

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

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

考虑以下代码:

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]的任何代码现在都会中断。

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

如果我们可以接受这种行为(我们可以通过quick_sort决定将任意int或float注入到输入数组中),解决方法是使用foo手动注释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后错误地使用列表,从而完全避免了该问题。

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

如果我们对这种行为不满意,并希望quick_sort保留列表中最初包含的任何类型,那么有两种解决方案:

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

from typing import Union, Sequence

Num = Union[int, float]

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

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

第二种解决方案是更精确地键入数组,并坚持必须包含所有int或所有浮点数,不允许两者混合使用。我们可以使用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)

这也将防止我们像上面那样意外地“混合”类型。

我建议使用第二种方法-更为精确,这样可以防止您在通过quicksort函数传递列表时丢失有关列表所包含的确切类型的信息。

如何在Linux上安装2个Anacondas(Python 2.7和3.5)? - python

我想使用Python 2和3版本。我已经读过有关conda环境的用法,但是不断向终端source (de)activate py27写入内容似乎不方便。如picture所示,如何使用命令选择内核版本? 参考方案 您在该图像中寻找的是Jupyter Notebook。您需要使用Jupyter和所需的python版本创建环境:conda create -n py…

为什么在for循环中将单词从复数形式转换为单数形式会花费这么长时间(Python 3)? - python

这是我的代码,用于从CSV文件读取文本并将一列中的所有单词从复数形式转换为单数形式:import pandas as pd from textblob import TextBlob as tb data = pd.read_csv(r'path\to\data.csv') for i in range(len(data)): blob …

如何在“后台”中运行脚本的一部分(单个函数)? - python

我在具有以下基本结构(伪代码)的服务器上运行python脚本:for data_item in data_items: processed_result=process_data(data_item); #this takes time T0 upload_result_to_site(processed_result) #this takes time T…

为什么在Python中根据@staticmethod选择模块级别的函数(根据Google样式指南)? - python

根据《 Google Python样式指南》,绝对不应(几乎)使用静态方法: 除非为了与 在现有库中定义的API。编写模块级功能 代替该建议背后的原因是什么?这是否仅适用于Google?还是在Python中使用静态方法还有其他(更一般的)缺点?尤其是,如果我想在将由该类的其他公共成员函数调用的类中实现实用程序功能,则最佳实践是什么?class Foo: ..…

将package_dir设置为..? - python

我有一个克隆到myproject的Git存储库,该存储库的根目录中有一个__init__.py,使整个东西成为可导入的Python包。我正在尝试为该软件包编写setuptools setup.py,它也将位于存储库的根目录中,在__init__.py文件旁边。我希望setup.py将其作为软件包安装在目录中。如果setup.py本身作为安装的一部分出现,那很…