hasattr(obj, '__iter__') vs collections
我看到一些帖子建议用
len(object)或hasattr(object,uu iter_uuuuuuu)?
python:检查对象是否是序列
起初我很兴奋,因为测试对象是否有
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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 |
下面是我用来生成这个的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | import collections testObjs = [ set(), dict(), list(), 'str', 1 ] print"hasattr(obj, '__iter__')" for obj in testObjs: print ' %r: %r' % (obj, hasattr(obj, '__iter__')) print"isinstance(obj, collections.Iterable)" for obj in testObjs: print ' %r: %r' % (obj, isinstance(obj, collections.Iterable)) print"isinstance(obj, collections.Iterator)" for obj in testObjs: print ' %r: %r' % (obj, isinstance(obj, collections.Iterator)) print"isinstance(obj, collections.Sequence)" for obj in testObjs: print ' %r: %r' % (obj, isinstance(obj, collections.Sequence)) |
号
我是否遗漏了一些东西,或者如果某些东西是不可测的,那么
编辑:我只对检测内置类型感兴趣:
编辑:我应该包括让我研究这个的用例。我有一个函数接受一个可以是单个值或序列的参数。所以我想检测它是什么,把它变成一个序列,如果它是一个单一的值,那么我可以把它作为一个序列来处理。
1 2 3 4 | if hasattr(arg, '__iter__'): arg= set(arg) else: arg= set([arg]) |
解决这个问题的一个方法是,如果对象不能被迭代,就让它抛出一个异常。但这在我的用例中不起作用。另一种解决方案是使用如下内容:
1 2 3 4 5 6 | import collections def issequenceforme(obj): if isinstance(obj, basestring): return False return isinstance(obj, collections.Sequence) |
。
发件人:python:检查对象是否为序列
但这需要定义这个函数,这使我不想使用它。
看来
字符串是一个可Iterable数据类型,但在python2.x上它没有
collections.Iterable 是一个不可迭代的对象,也就是说,某种形式的容器允许您逐个迭代它所包含的对象。字符串包含在其中,因为可以对每个字符进行迭代是一个字符串。collections.Sequence 是一个子集的不可重复的对象,它保证了迭代的顺序。列表和字符串将返回True ,因为同一列表或字符串的迭代顺序始终相同,而集合和字典将返回False ,因为您不知道内部对象将以什么顺序出现。
如果您确定只想检测内置类型(通常被认为是可疑的做法,首选duck类型),那么可以这样做:
1 2 3 4 | if isinstance(arg, (set, list, dict, tuple)): print"I got a built-in iterable." else: print"Hey, this ain't iterable!" |
号
然而,您提出的解决方案是更好的-处理任何特殊情况(如字符串,在您的情况下),然后使用duck类型。这样,其他人就可以使用适合他们需要的容器,并有责任确保它符合您的代码对他们的要求。
您还可以将
Question: I've seen a couple posts recommending isinstance(obj, collections.Sequence) instead of hasattr(obj, '__iter__') to determine if something is a list.
号
为了确定某个东西是否是可迭代的,最可靠的方法是尝试创建一个迭代器。这将决定一个对象是否真的是可重写的:
1 2 3 4 5 6 7 | def is_iterable(obj): try: iter(obj) except TypeError: return False else: return True |
一种稍不可靠但看起来整洁的方法是对抽象基类进行测试。这将测试对象是否具有"iter"方法或是否注册为"iterable"(例如,str的实例没有"iter"方法,但注册为"iterable"):
1 | isinstance(obj, collections.Iterable) |
。
如果您对列表和类似于列表的对象特别感兴趣,那么可以针对可变顺序ABC进行测试:
1 | isinstance(obj, collections.MutableSequence) |
也就是说,如果您依赖的对象具有特定的类似列表的行为,则pythonic方法是假定该方法存在,如果不存在,则捕获异常。这叫鸭子打字。
在和一些同事交谈之后,我得出结论,
1 2 3 4 5 6 7 | if isinstance(arg, basestring): arg= set([arg]) else: try: selection= set(arg) except TypeError: selection= set([arg]) |