在Python中遍历列表或单个元素
我想要遍历一个不知道的函数的输出结果。可惜的是,我不知道这个函数是返回一个单独的值还是一个元组(也就是一组值)。这应该是一个常见的问题,应该有标准的方法来处理这个情况——而我现在的做法看起来很糟糕。
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
8 个回答
也许用 collections.Iterable
来判断输出是否可以被遍历会更好。
import collections
x = UnknownFunction()
if not isinstance(x, collections.Iterable): x = [x]
for ii in x:
#do stuff
如果 x 的类型是以下任意一种 - list
(列表)、tuple
(元组)、dict
(字典)、str
(字符串),或者是从这些类型派生出来的任何类,这个方法就能奏效。
到处都写代码并不是个好主意。我们可以写一个函数来处理这些事情。这里有个我之前想出来的建议,适用于类似的问题。这个函数特别处理字符串(通常是可以迭代的),把它们当作单独的项目来处理,这正是我通常想要的效果。
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
更新 这里有一个生成器版本,使用了比较新的(Python 3.3)yield from
语句。
def iterfy(iterable):
if isinstance(iterable, str):
yield iterable
else:
try:
# need "iter()" here to force TypeError on non-iterable
# as e.g. "yield from 1" doesn't throw until "next()"
yield from iter(iterable)
except TypeError:
yield iterable
解决这个问题的最通用方法是使用 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
不被认为是有害的吗?它不是会让你只能用一种类型吗?用 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