我看过几篇帖子推荐isinstance(obj, collections.Sequence)
而不是hasattr(obj, '__iter__')
,以确定某些内容是否属于列表。
len(object) or hasattr(object, __iter__)?
Python: check if an object is a sequence
起初我很兴奋,因为测试对象是否__iter__
对我来说总是很脏。但经过进一步审核后,这仍然是最佳解决方案,因为isinstance
上的collection
测试都没有产生相同的结果。 collections.Sequence
已关闭,但会为字符串返回True
。
hasattr(obj, '__iter__')
set([]): True
{}: True
[]: True
'str': False
1: False
isinstance(obj, collections.Iterable)
set([]): True
{}: True
[]: True
'str': True
1: False
isinstance(obj, collections.Iterator)
set([]): False
{}: False
[]: False
'str': False
1: False
isinstance(obj, collections.Sequence)
set([]): False
{}: False
[]: True
'str': True
1: False
以下是我用来生成此代码的代码:
import collections
testObjs = [
set(),
dict(),
list(),
'str',
1
]
print "hasattr(obj, '__iter__')"
for obj in testObjs:
print ' %r: %r' % (obj, hasattr(obj, '__iter__'))
print
print "isinstance(obj, collections.Iterable)"
for obj in testObjs:
print ' %r: %r' % (obj, isinstance(obj, collections.Iterable))
print
print "isinstance(obj, collections.Iterator)"
for obj in testObjs:
print ' %r: %r' % (obj, isinstance(obj, collections.Iterator))
print
print "isinstance(obj, collections.Sequence)"
for obj in testObjs:
print ' %r: %r' % (obj, isinstance(obj, collections.Sequence))
print
我是否遗漏了某些内容,或hasattr(obj, '__iter__')
仍然是测试某些内容是否可迭代的最佳选择?
编辑:我只对检测内置类型感兴趣:dict
,list
和set
。(编辑:这是愚蠢的:))
编辑:我应该包含让我对此进行调查的用例。我有一个函数,它接受一个可以是单个值或序列的arg。所以我想检测它是什么,如果它是单个值就把它变成一个序列,所以我可以把它作为一个序列来处理。
if hasattr(arg, '__iter__'):
arg= set(arg)
else:
arg= set([arg])
对此的一个解决方案是,如果无法迭代对象,则抛出异常。但这在我的用例中不起作用。另一种解决方案是使用类似的东西:
import collections
def issequenceforme(obj):
if isinstance(obj, basestring):
return False
return isinstance(obj, collections.Sequence)
来自: Python: check if an object is a sequence
但是这需要定义这个函数,这使我不想使用它。
看起来hasattr(arg, '__iter__')
仍然是最佳选择。
答案 0 :(得分:5)
collections.Iterable
将保证对象是否可迭代(例如使用for x in obj
),但不会检查__iter__
。
字符串是一种可迭代的数据类型,但在Python2.x上它没有__iter__
方法。
答案 1 :(得分:2)
您还可以将__iter__
添加到自己的类中,因此无法保证hasattr(obj, '__iter__')
之外的任何测试都无法检测到这些。您没有在问题中指明您只关心内置集合。
答案 2 :(得分:2)
collections.Sequence
已关闭但对字符串返回True。
collections.Iterable
用于可迭代对象,即某种形式的容器,允许您逐个迭代它包含的对象。字符串包含在此中,因为您可以迭代每个字符是一个字符串。collections.Sequence
用于可迭代对象的子集,它保证迭代的顺序。列表和字符串将返回True
,因为相同列表或字符串的迭代顺序始终相同,而集合和字典将返回False
,因为您不知道内部对象将以什么顺序出现out in。如果您确定只想检测内置类型(通常被认为是可疑行为,首选duck typing),那么您可以这样做:
if isinstance(arg, (set, list, dict, tuple)):
print "I got a built-in iterable."
else:
print "Hey, this ain't iterable!"
但是,您提出的解决方案更好 - 处理任何特殊情况(例如字符串,在您的情况下)然后使用duck typing。然后,这允许其他人使用适合他们需要的任何容器,并负责确保它符合您的代码对它们的要求。
答案 3 :(得分:1)
在与一些同事交谈之后,我得出结论,hasattr(arg, '__iter__')
可能是一个不错的单线,但它远非完美,正如你们也指出的那样。这就是我最终的结果:
if isinstance(arg, basestring):
arg= set([arg])
else:
try:
selection= set(arg)
except TypeError:
selection= set([arg])
答案 4 :(得分:1)
问题:我已经看到一些帖子推荐isinstance(obj,collections.Sequence)而不是hasattr(obj,'__ user__')以确定某些内容是否为列表。
要确定某些内容是否为iterable,最可靠的方法是尝试创建iterator。这将决定对象是否实际可迭代:
def is_iterable(obj):
try:
iter(obj)
except TypeError:
return False
else:
return True
稍微不那么可靠,但看起来干净的方法是针对abstract base class进行测试。这将测试一个对象是否具有__iter __()方法,或者它是否被注册为 Iterable (例如, str 的实例没有__iter __()方法,但它被注册为可迭代的):
isinstance(obj, collections.Iterable)
如果您对列表和类似列表的对象特别感兴趣,可以针对 MutableSequence ABC进行测试:
isinstance(obj, collections.MutableSequence)
也就是说,如果你依赖的是一个具有特定列表行为的对象,那么Pythonic方法就是假设该方法存在并且如果不存在则捕获异常。这称为duck typing。