7

我正在尝试创建一个只接受可迭代参数的方法,例如list,或.tuplesetdict

这是我的代码:

class MjmMenuControl(MjmBaseMenu):
    def __init__(self, items=None):
        iterables = (dict, list, set, tuple)
        for iterable in iterables:
            if isinstance(items, iterable):
                ...
                break

但是,我想知道是否有更简单的方法,例如if isinstance(items, <iterable_base_class>):但我找不到任何东西。

我已经尝试为list等找到基类,但它们似乎都来自object

>>> inspect.getmro(list)
(<class 'list'>, <class 'object'>)
>>> inspect.getmro(tuple)
(<class 'tuple'>, <class 'object'>)

这是可能的还是我必须坚持可怕的for循环?

4

2 回答 2

18

是的,使用collections.abc.Iterable

>>> from collections import abc
>>> isinstance(set(), abc.Iterable)
True
>>> isinstance((), abc.Iterable)
True
>>> isinstance([], abc.Iterable)
True
>>> isinstance('', abc.Iterable)
True
>>> isinstance({}, abc.Iterable)
True
>>> isinstance(0, abc.Iterable)
False

但是,我只是让方法假设它传递了一个可迭代对象,调用者有责任确保传入正确的类型。

collections.abc模块是 Python 3.3 中的新模块;它的内容以前存在于collections模块中,尽管即使在 Python 3.3 及更高版本中,这些名称仍然可以在旧位置使用。

于 2013-04-13T12:19:46.810 回答
5

该选项的一个弱点collections.abc.Iterable是它无法处理像这样的自定义可迭代类......

from collections.abc import Iterable

class MyIterable(object):
    def __getitem__(self, index):
        if index >= 10:
            raise IndexError
        return index

>>> myiter = MyIterable()
>>> isinstance(myiter, Iterable)
False
>>> [i for i in myiter]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

人们经常声称这样做的“Pythonic”方式是使用鸭子类型,即尝试将对象视为可迭代对象,并在失败时处理异常。例如...

class MjmMenuControl(MjmBaseMenu):
    def __init__(self, items=None):
        try:
            for item in items:
                do_something_with(item)
        except TypeError:
            # If we get here, 'items' is not iterable
            do_something_else()

...但是,这两种方法都具有将字符串视为与列表相同的弱点,这通常不是您想要的。通常你想测试一个可迭代的容器,它略有不同,所以通常会看到将字符串视为特殊情况的代码......

class MjmMenuControl(MjmBaseMenu):
    def __init__(self, items=None):
        if isinstance(items, (str, bytes)):
            do_something_else()
        else:
            try:
                for item in items:
                    do_something_with(item)
            except TypeError:
                # If we get here, 'items' is not iterable
                do_something_else()

...这有点乱,但可以完成工作。

于 2013-04-13T13:11:33.030 回答