Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

hasattr(obj, '__iter__') vs collections

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.

like image 261
keegan3d Avatar asked Aug 25 '11 21:08

keegan3d


People also ask

What is Hasattr () in Python?

Python hasattr() Function The hasattr() function returns True if the specified object has the specified attribute, otherwise False .

How do you know if a value iterable?

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.

What is Hasattr object name used for?

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.

How can you tell if an object is an iterator?

An object is Iterator if you can use next() to sequentially browse through its elements. For example, map() returns Iterator and list is Iterable .


2 Answers

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.

like image 50
JBernardo Avatar answered Sep 28 '22 08:09

JBernardo


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.

like image 26
Ben Jackson Avatar answered Sep 28 '22 08:09

Ben Jackson