当内部函数返回可能为“无"的“联合"时,如何避免类型错误? [英] How do I avoid type errors when internal function returns 'Union' that could be 'None'?
问题描述
我在 python 中遇到了联合(当然还有可选)的一些奇怪之处 - 即静态类型检查器似乎针对联合的所有成员测试属性,而不是联合的成员(即它似乎过于严格?).例如,请考虑以下内容:
I've been running into a bit of weirdness with Unions (and Optionals, of course) in python - namely it seems that the static type checker tests properties against all member of a union, and not a member of the union (i.e. it seems overly strict?). As an example, consider the following:
import pandas as pd
def test_dummy() -> pd.DataFrame:
df = pd.DataFrame()
df = df.fillna(df)
return df
这会创建一个类型警告,如 pd.fillna(..., inplace: Bool = False, ...) ->可选[pd.DataFrame]
(如果inplace=True
,则返回None
).我怀疑理论上静态类型检查器应该根据参数实现函数的返回变化(因为在编写代码时应该知道),但这有点过分.
This creates a type warning, as pd.fillna(..., inplace: Bool = False, ...) -> Optional[pd.DataFrame]
(it is a None
return if inplace=True
). I suspect that in theory the static type checker should realize the return of the function changes depending on the arguments (as that should be known when code is written), but that's a bit beyond the point.
我有以下问题:
解决此问题的最佳方法是什么?我能想到两个解决方案:
What is the best way to resolve this? I can think of two solutions:
i) 什么都不做——这会在我的代码中产生丑陋的波浪线
i) do nothing -- which creates ugly squiggles in my code
ii) cast
fillna
到 pd.DataFrame
的返回;我的理解是,这是静态类型检查器的信息性步骤,因此不应引起任何顾虑或问题?
ii) cast
the return of fillna
to a pd.DataFrame
; my understanding is this is a informative step to the static type checker so should not cause any concerns or issues?
让我们考虑一下我正在编写一个函数 f
,与此类似,它的返回类型因函数调用输入而异,并且这应该在运行时之前确定.为避免日后发生此类错误;编写此函数的最佳方法是什么?做类似 @typing.overload
的事情会更好吗?
Let us consider that I'm writing a function f
which, similarly to this, has its return types vary depending on the function call inputs, and this should be determinable before runtime. In order to avoid such errors in the future; what is the best way to go about writing this function? Would it be better to do something like a @typing.overload
?
谢谢!
推荐答案
底层函数确实应该定义为一个重载——我建议可能给 Pandas 一个补丁
The underlying function should really be defined as an overload -- I'd suggest a patch to pandas probably
这是:
Here's what the type looks like right now:
def fillna(
self: FrameOrSeries,
value=None,
method=None,
axis=None,
inplace: bool_t = False,
limit=None,
downcast=None,
) -> Optional[FrameOrSeries]: ...
实际上,更好的表示方法是使用 @overload
—— 当 inplace = True
时,函数返回 None
:
in reality, a better way to represent this is to use an @overload
-- the function returns None
when inplace = True
:
@overload
def fillna(
self: FrameOrSeries,
value=None,
method=None,
axis=None,
inplace: Literal[True] = False,
limit=None,
downcast=None,
) -> None: ...
@overload
def fillna(
self: FrameOrSeries,
value=None,
method=None,
axis=None,
inplace: Literal[False] = False,
limit=None,
downcast=None,
) -> FrameOrSeries: ...
def fillna(
self: FrameOrSeries,
value=None,
method=None,
axis=None,
inplace: bool_t = False,
limit=None,
downcast=None,
) -> Optional[FrameOrSeries]:
# actual implementation
但假设您无法更改基础库,您可以通过多种方法来解压联合.我专门为 re.match
制作了视频,但我会在这里重申因为它基本上是相同的问题 (Optional[T]
)
but assuming you can't change the underlying library you have several approaches to unpacking the union. I made a video about this specifically for re.match
but I'll reiterate here since it's basically the same problem (Optional[T]
)
断言告诉类型检查器一些它不知道的东西:类型比它知道的要窄.mypy 将信任此断言,并且类型将被假定为 pd.DataFrame
the assert tells the type checker something it doesn't know: that the type is narrower than it knows about. mypy will trust this assertion and the type will be assumed to be pd.DataFrame
def test_dummy() -> pd.DataFrame:
df = pd.DataFrame()
ret = df.fillna(df)
assert ret is not None
return ret
选项 2:投射
明确告诉类型检查器该类型是您所期望的,抛弃"None
-ness
from typing import cast
def test_dummy() -> pd.DataFrame:
df = pd.DataFrame()
ret = cast(pd.DataFrame, df.fillna(df))
return ret
类型:忽略
(imo) hacky 解决方案是告诉类型检查器忽略不兼容性,我不建议使用这种方法,但它作为快速修复可能会有所帮助
type: ignore
the (imo) hacky solution is to tell the type checker to ignore the incompatibility, I would not suggest this approach but it can be helpful as a quick fix
def test_dummy() -> pd.DataFrame:
df = pd.DataFrame()
ret = df.fillna(df)
return ret # type: ignore
这篇关于当内部函数返回可能为“无"的“联合"时,如何避免类型错误?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!