如何在代码中检查类型提示是否与 Iterable 兼容?

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

我想要一个函数

isiterable(t: type) -> bool
,如果我传递的类型是可迭代的,它将返回 true,否则返回 false。

assert isiterable(int) == False
assert isiterable(str) == False
assert isiterable(Iterable[int]) == True

我使用类型提示来装饰函数已经有一段时间了。但是,我现在正在编写一些需要类型提示感知的代码。我对此知之甚少。我的目标是 python 3.7,如果这有什么区别的话。所以这个问题可能有一个明显的答案。

我可以通过蛮力来构造它 - 检查类型类的名称是否为

_GenericAlias
,然后检查
_name
是否为
Iterator
- 但由于多种原因,这感觉不稳健或面向未来!

编辑:我的问题似乎写得不清楚。我想我所追求的叫做类型内省。我在下面得到了一个可行的答案,但几乎可以肯定至少不是Pythonic。我正在尝试支持 3.7 和 3.8,如果有什么区别的话 - 不过支持 3.6 会很好。

python-3.x type-hinting
3个回答
0
投票

检查文档https://docs.python.org/3/library/collections.abc.html?highlight=iterable#collections.abc.Iterable

如果你写了类似的内容:

from collections.abc import Iterable

def isiterable(obj):
    return isinstance(obj, Iterable)

它只会检查它是否是

Iterable
的子类或者是否具有
__iter__
方法。这不准确。

任何具有

__iter__
__getitem__
的对象都是可迭代的。所以你可以使用这两种方法来编写一个Iterable

# with __iter__ and __next__
class Foo:
    def __init__(self, x):
        self.x = x

    def __iter__(self):
        self.n = 0
        return self

    def __next__(self):
        if self.n <= self.x:
            self.n += 1
            return 1
        else:
            raise StopIteration

# with __setitem__ and __getitem__
class Bar(object):
    def __init__(self, x):
        self.x = [None] * x

    def __setitem__(self, index, data):
        self.x[index] = data

    def __getitem__(self, index):
        return self.x[index]

判断对象是否可迭代的唯一可靠方法是调用iter(obj)

def isiterable(obj):
    try:
        print(iter(obj))
    except:
        return False
    else:
        return True


print(isiterable(Foo(1)))
print(isiterable(Bar(1)))

# <__main__.Foo object at 0x7f3fe2703bb0>
# True
# iterator object at 0x7f3fe269f400>
# True


0
投票

这是可行的 - 但感觉它取决于实现细节而不是类型系统的公共 API。我暂时将此标记为答案,直到我或其他人发布更正确的内容:

from typing import Type
def is_iterable(t: Type) -> bool:
        if type(i_type).__name__ != '_GenericAlias':
            return False

        import collections
        if i_type.__origin__ != collections.abc.Iterable:
            return False

        return True

如果您还想知道

X
中的
Iterable[X]
是什么,您可以通过
i_type.__args__[0]
获取。


0
投票
import typing
from collections import abc

def is_iterable(type_hint: type) -> bool:
    return (hasattr(type_hint, '__origin__') 
            and type_hint.__origin__ in  {abc.Iterable, typing.Iterable})
© www.soinside.com 2019 - 2024. All rights reserved.