具有多个可能输入的类型检查Python方法

问题描述 投票:0回答:4

我有一个函数,它接受五个整数的列表或五个整数作为元组(*argv)。

这是我的函数标题:

def __init__(self, *argv: Union[int, list]) -> None:

稍后在此函数中,我检查该元组的内容,看看它是一个列表还是五个单独的整数。

        if type(argv[0]) == int:
            self._l1 = [argv[0], argv[1], argv[2], argv[3], argv[4]]
        else:
            self._l1 = argv[0]

此时代码中 l1 是一个列表。 self._l1 绝对是一个列表,它不再是一个 int,它是一个列表。

但是稍后在我的代码中运行此行时:

        self._myvar = self._l1.count(1)

我从 MyPy 返回此错误

赋值中的类型不兼容(表达式的类型为“Union[int, List[Any]]”,变量的类型为“List[Union[int, List[Any]]]”)

我是否输入错误,我需要输入什么?我尝试了很多不同的类型,但不断出错。

据我所知,我的输入是一个元组,其中包含一个整数列表或五个整数。我假设它类似于 Union[Tuple[List[int]], Tuple[int, ...]] 或只是 Union[List[int], int] 或 Union[List[int], Tuple[int, . ..]],或类似的东西,但这些都不适合我。

python python-typing mypy
4个回答
1
投票

无法找到您的版本不起作用的原因(因为文档指出它应该适用于

type(...) is
语法,但在我的情况下,将type更改为
if isinstance(argv[0], int):
删除了您的mypy错误。


0
投票

我建议确保

_li
始终为
List[int]
类型。

我还没有测试下面的代码,但是

cast
应该可以工作:

if isinstance(argv[0], int):
    self._l1 = [cast(int, argv[0]), cast(int, argv[1]), cast(int, argv[2]), cast(int, argv[3]), cast(int, argv[4])]
else:
    self._l1 = cast(List[int], argv[0])
print(type(self._li))

以及声明 _li 和 _myvar 的位置:

_li: List[int]
_myvar: List[int]

0
投票

为什么不使用

typing.overload

它看起来像这样:

from __future__ import annotations
from typing import overload

class MyClass:
    @overload
    def __init__(self: MyClass, a: int, b: int, c: int, d: int, e: int) -> None:
        ...

    @overload
    def __init__(self: MyClass, abcde: tuple[int,int,int,int,int]) -> None:
        ...

    def __init__(self, a, *bcde):
        if bcde:
            b, c, d, e = *bcde
            # etc
        else:
            a, b, c, d, e = *a
            # etc  

0
投票

因此,您将

argv
定义为带有
*
的序列,其中可以包含 int 值或 int 值列表。所以你真正想做的是“展平”序列。


def flatten(alist):
    """Flatten a nested set of lists into one list."""
    rv = []
    for val in alist:
        if isinstance(val, (list, tuple)):
            rv.extend(flatten(val))
        else:
            rv.append(val)
    return rv

class MyClass:
    def __init__(self, *argv: Union[int, list]):
        # argv is now a tuple of Union[int, list], or List[Union[int, List]], as the compiler says. 
        self._l1 = flatten(argv)
        # Now, you want to verify they are all ints, and that there are five.
        if len(self._l1) != 5:
            raise ValueError("Need five ints")
        if not all(isinstance(o, int) for o in self._l1):
            raise ValueError("not sequence of ints")
        # Now you have a single list of 5 ints.

© www.soinside.com 2019 - 2024. All rights reserved.