当内部函数返回可能为“无"的“联合"时,如何避免类型错误? [英] How do I avoid type errors when internal function returns 'Union' that could be 'None'?

查看:42
本文介绍了当内部函数返回可能为“无"的“联合"时,如何避免类型错误?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在 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.

我有以下问题:

  1. 解决此问题的最佳方法是什么?我能想到两个解决方案:

  1. 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 fillnapd.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屋!

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