在python中迭代列表或单个元素

问题描述 投票:18回答:7

我想迭代未知函数的输出。不幸的是,我不知道该函数是返回单个项还是元组。这必须是一个标准问题,必须有一个标准的方法来解决这个问题 - 我现在拥有的是非常难看的。

x = UnknownFunction()
if islist(x):
    iterator = x
else:
    iterator = [x]

def islist(s):
    try:
        len(s)
        return True
    except TypeError:
        return False

for ii in iterator:
    #do stuff
python
7个回答
24
投票

这个问题最常见的解决方案是使用isinstance和抽象基类collections.Iterable

import collections

def get_iterable(x):
    if isinstance(x, collections.Iterable):
        return x
    else:
        return (x,)

你可能也想测试basestring,正如Kindall所暗示的那样。

    if isinstance(x, collections.Iterable) and not isinstance(x, basestring):

现在有些人可能会想,就像我曾经做过的那样,“不是isinstance considered harmful?它不会锁定你使用某种类型吗?不会使用hasattr(x, '__iter__')更好吗?”

答案是:不是涉及抽象基类。实际上,您可以使用__iter__方法定义自己的类,并且它将被识别为collections.Iterable的实例,即使您没有子类collections.Iterable。这是有效的,因为collections.Iterable定义了一个__subclasshook__,它确定传递给它的类型是否是它实现的任何定义的Iterable。

>>> class MyIter(object):
...     def __iter__(self):
...         return iter(range(10))
... 
>>> i = MyIter()
>>> isinstance(i, collections.Iterable)
True
>>> collections.Iterable.__subclasshook__(type(i))
True

5
投票

将代码包含在您需要的任何地方并不是特别优雅。所以写一个做按摩的功能。以下是我提出的类似上一个问题的建议。它是特殊情况的字符串(通常可以迭代)作为单个项目,这是我通常想要的。

def iterfy(iterable):
    if isinstance(iterable, basestring):
        iterable = [iterable]
    try:
        iter(iterable)
    except TypeError:
        iterable = [iterable]
    return iterable

用法:

for item in iterfy(unknownfunction()):
     # do something

2
投票

您需要执行以下操作:

iterator = (x,) if not isinstance(x, (tuple, list)) else x

然后

for i in iterator:
    #do stuff

1
投票

也许最好使用collections.Iterable来确定输出是否是可迭代的。

import collections

x = UnknownFunction()
if not isinstance(x, collections.Iterable): x = [x]

for ii in x:
    #do stuff

如果x的类型是这些中的任何一个 - listtupledictstr,任何来自这些的类,这将起作用。


0
投票

您也可以尝试使用operator.isSequenceType函数

import operator
x = unknown_function()
if not operator.isSequenceType(x) and not isinstance(x, basestring):
    x = (x,)
for item in x:
    do_something(item)

0
投票

您可以定义一个函数,确保返回值支持迭代(strdicttuple等 - 包括不直接从这些类继承的用户定义的序列类型),而不是直接检查它是否是tuplelist

def ensure_iterable(x):
    return (x,) if not hasattr(x, '__iter__') else x

x = ensure_iterable(UnknownFunction())
for i in x:
    do_something(i)

0
投票

如果使用生成器,您可能会获得更好的性能。这应该适用于python 3.3及更高版本。

from collections import Iterable

def iterrify(obj):
    """
    Generator yielding the passed object if it's a single element or
    yield all elements in the object if the object is an iterable.

    :param obj: Single element or iterable.
    """
    if isinstance(obj, (str, bytes)):  # Add any iterables you want to threat as single elements here
        yield obj
    elif isinstance(obj, Iterable):  # Yield from the iterables.
        yield from obj
    else:  # yield single elements as is.
        yield obj
© www.soinside.com 2019 - 2024. All rights reserved.