我想使用类型提示来实现以下内容:
def fo() -> pd.Series[np.float64]:
return pd.Series(np.float64[0])
这样不行
从这个答案:How to specify the type of pandas series elements in type hints?
我知道我可以使用:
def fo() -> "pd.Series[np.float64]":
return pd.Series(np.float64[0])
或者:
from typing import (
TypeVar
)
SeriesFloat64 = TypeVar('pd.Series[np.float64]')
def fo() -> SeriesFloat64:
return pd.Series(np.float64[0])
为什么我更喜欢其中一个?
2条答案
按热度按时间6uxekuva1#
您引用的两个“解决方案”都是错误的
我从第二个开始:
这个类型变量 * 技术上 * 是有效的注解吗?是的。它指定了泛型
pd.Series
吗?不是。首先,正如@jonrsharpe所指出的,这打破了用
name
参数初始化类型变量的惯例,该参数对应于变量的实际名称。更重要的是,既没有指定bound
也没有指定constraints
,这意味着你还不如这样写:这至少解决了名称问题,但它不会指定任何关于
fo()
的返回类型。实际上,mypy
将正确指出以下内容:这已经给出了关于
pd.Series
规范我们能做什么和不能做什么的提示,这将我们引向第二个“解决方案”:这是等价的,顺便说一下:(不需要引号)
这是错误的,因为泛型
Series
的类型参数不接受np.float64
。mypy
再次指出了这一点:如果我们查看
core.series.Series
的pandas-stubs
源代码(截至目前),我们会看到Series
继承自typing.Generic[S1]
。当我们转到_typing.S1
的定义时,我们可以看到该类型变量的约束。numpy float不在其中,但我们确实找到了内置的float
。这意味着什么?我们知道
np.float64
确实继承自常规的float
,但它也继承自np.floating
,这就是问题所在。类型约束导致推断的类型 * 恰好 * 是约束类型[.]之一
这意味着你 * 不 * 允许使用
np.float64
代替前面提到的S1
来指定Series
类型。更好的方式
在我看来,输入hint函数的“最正确”方法是这样做:
这正确地使用了
Series
泛型,提供了一个类型变量,该变量既符合定义的类型约束**,又表示函数返回的系列的元素类型,该类型尽可能接近实际类型,因为np.float64
* 确实 * 继承自float
。它还通过了严格的
mypy
检查。添加有用信息
需要注意的是,这样会丢失series * 实际上 * 包含64位浮点数的信息。如果你想让函数的签名/文档反映这种细微差别,你可以简单地设置一个自定义类型别名:
现在调用
help(fo)
得到:但重要的是要注意,这只是为了 * 你的 * 利益,对静态类型检查器绝对没有任何作用。
pd.Series
类型限制另一件值得一提的事情是,到目前为止,
pd.Series
的许多返回单个元素的方法上都没有有用的注解,例如通过方括号[]
访问的__getitem__
方法。假设我这样做:输出是
0.0 <class 'numpy.float64'>
,但是类型检查器不知道x
是np.float64
还是任何float
。(事实上,我的PyCharm在y = int(x)
上抱怨,因为它认为x
是一个时间戳,不管出于什么原因。)这只是为了说明,到目前为止,在处理
pd.Series
时,您可能不会得到任何有用的自动建议,即使您或多或少正确地注解了类型。希望这能帮上忙。
lymgl2op2#
我不能说float 64是否会在pandas
Series
中工作-从2.0开始,Arrow现在在下面而不是numpy。然而,简单的做法是使用typing.TypeVar
: