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.
Python hasattr() Function The hasattr() function returns True if the specified object has the specified attribute, otherwise False .
Check If a JavaScript Value is Iterable In order to be iterable, an object must implement the @@iterator method. You can also reference the @@iterator method using the Symbol. iterator constant. It points JavaScript to the same method.
Definition. Python hasattr() function is used to return value TRUE after checking whether the object has the given attribute, else return FALSE. The Python hasattr() built-in function is used to check if the specified object has the named attribute present within a class or not.
An object is Iterator if you can use next() to sequentially browse through its elements. For example, map() returns Iterator and list is Iterable .
The collections.Iterable
will guarantee the object is iterable or not (like using for 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.
You can also add __iter__
to your own classes, so any test short of hasattr(obj, '__iter__')
would not be guaranteed to detect those. You didn't specify in the question that you only care about builtin collections.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With