hasattr(obj, '__iter__') 与集合
我看到有几篇文章推荐使用 isinstance(obj, collections.Sequence)
而不是 hasattr(obj, '__iter__')
来确定某物是否是列表。
len(object) 或 hasattr(object, __iter__)?
起初我很兴奋,因为测试一个对象是否有__iter__
对我来说总是显得肮脏。但经过进一步审查,这似乎仍然是最好的解决方案,因为对 collection
的 isinstance
测试都没有产生相同的结果。 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
。( >编辑:这是愚蠢的:))
编辑:我应该包含让我研究这个的用例。我有一个函数,它接受一个参数,该参数可以是单个值或序列。因此,我想检测它是什么,如果它是单个值,则将其转换为序列,以便之后我可以将其作为序列处理。
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)
From: Python:检查对象是否是一个序列
但这需要定义这个函数,这让我不想使用它。
看起来 hasattr(arg, '__iter__')
仍然是最好的选择。
I've seen a couple posts recommending isinstance(obj, collections.Sequence)
instead of hasattr(obj, '__iter__')
to determine if something is a list.
len(object) or hasattr(object, __iter__)?
Python: check if an object is a sequence
At first I was excited because testing if an object has __iter__
always seemed dirty to me. But after further review this still seems to be the best solution because none of the isinstance
tests on collection
yield the same results. collections.Sequence
is close but it returns True
for strings.
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
Here is the code I used to generate this:
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
Am I missing something or is hasattr(obj, '__iter__')
still the best option for testing if something is iterable?
EDIT: I am only interested in detecting the builtin types: dict
, list
, and set
.(EDIT: this is foolish :))
EDIT: I should have included the use case that got me looking into this. I have a function that takes an arg that can be a single value or a sequence. So I want to detect what it is and turn it into a sequence if it's a single value so I can deal with it as a sequence after that.
if hasattr(arg, '__iter__'):
arg= set(arg)
else:
arg= set([arg])
One solution to this is just to let it throw an exception if the object cannot be iterated. But that doesn't work in my use case. Another solution is to use something like:
import collections
def issequenceforme(obj):
if isinstance(obj, basestring):
return False
return isinstance(obj, collections.Sequence)
From: Python: check if an object is a sequence
But this requires this function to be defined which makes me not want to use it.
It looks like hasattr(arg, '__iter__')
is still the best option.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
Collections.Iterable 将保证对象是否可迭代(例如使用 for x in obj ),但检查 __iter__ 则不会。
字符串是一种可迭代的数据类型,但在 Python2.x 上它没有 __iter__ 方法。
The
collections.Iterable
will guarantee the object is iterable or not (like usingfor x in obj
) but checking__iter__
will not.A string is a iterable datatype but on Python2.x it doesn't have a
__iter__
method.您还可以将 __iter__ 添加到您自己的类中,因此任何缺少
hasattr(obj, '__iter__')
的测试都不能保证检测到这些。您没有在问题中指定您只关心内置集合。You can also add
__iter__
to your own classes, so any test short ofhasattr(obj, '__iter__')
would not be guaranteed to detect those. You didn't specify in the question that you only care about builtin collections.collections.Sequence
很接近,但对于字符串返回 True。collections.Iterable
用于可迭代对象,即某种形式的容器,允许您一一迭代它包含的对象。字符串包含在其中,因为您可以迭代字符串中的每个字符。collections.Sequence
是可迭代对象的子集,它保证迭代的顺序。列表和字符串将返回True
,因为同一列表或字符串的迭代顺序始终相同,而集合和字典将返回False
,因为您不知道什么内部对象的出现顺序。如果您确定只想检测内置类型(通常被认为是可疑的做法,鸭子打字是首选),那么你可以这样做:
但是,你想出的解决方案更好 - 处理任何特殊情况(例如字符串,在你的情况下),然后使用鸭子打字。然后,其他人就可以使用适合他们需求的任何容器,并让他们有责任确保它符合您的代码的要求。
collections.Sequence
is close but it returns True for strings.collections.Iterable
is for an iterable object, that is, some form of container which allows you to iterate over the objects it contains, one by one. Strings are included in this since you can iterate over each character is a string.collections.Sequence
is for a sub-set of iterable objects which guarantee the order of iteration. Lists and strings will returnTrue
as the order of iteration is always the same for the same list or string, while sets and dictionaries will returnFalse
since you don't know what order the internal objects will come out in.If you are sure you only want to detect the built-in types (often considered a suspect practice, with duck typing being preferred), then you can do so:
However, the solution you came up with is better - handle any special cases (such as strings, in your case) and then use duck typing. This then lets others use whatever container fits their needs, and puts the responsibility of making sure it fits with what your code requires on them.
要确定某物是否可迭代,最可靠的方法是尝试创建一个迭代器。这将确定一个对象是否实际上是可迭代的:
一种稍微不太可靠但看起来干净的方法是针对 抽象基类。这将测试一个对象是否具有 __iter__() 方法或者它是否注册为 Iterable (例如,str 的实例没有 __iter__()方法,但它被注册为可迭代):
如果您对列表和类似列表的对象特别感兴趣,您可以针对 MutableSequence 进行测试 ABC:
也就是说,如果您依赖于一个对象有一个特定的类似列表的行为,Pythonic 方法是假设该方法存在,如果不存在则捕获异常。这称为鸭子打字。
To determine whether something is iterable, the most reliable method is to attempt to create an iterator. That will determine whether an object is actually iterable:
A slightly less reliable, but clean looking approach is to test against the abstract base class. That will test whether an object has the __iter__() method or whether it is registered as an Iterable (for example, an instance of str doesn't have an __iter__() method but it is registered as an iterable):
If you're specifically interested in lists and list-like objects, you could test against the MutableSequence ABC:
That said, if you're relying on an object having a particular list-like behavior, the Pythonic way is to assume the method is present and catch the exception if it is not. This is called duck typing.
在与一些同事交谈后,我得出的结论是
hasattr(arg, '__iter__')
可能是一个不错的衬里,但它远非完美,正如你们也指出的那样。这就是我最终得到的结果:After talking to some colleagues I concluded that
hasattr(arg, '__iter__')
may be a nice one liner but it is far from perfect, as you guys have also pointed out. This is what I ended up with: