interstar
interstar

Reputation: 27186

Test if a variable is a list or tuple

In python, what's the best way to test if a variable contains a list or a tuple? (ie. a collection)

Is isinstance() as evil as suggested here? http://www.canonical.org/~kragen/isinstance/

Update: the most common reason I want to distinguish a list from a string is when I have some indefinitely deep nested tree / data-structure of lists of lists of lists of strings etc. which I'm exploring with a recursive algorithm and I need to know when I've hit the "leaf" nodes.

Upvotes: 325

Views: 431704

Answers (16)

j4hangir
j4hangir

Reputation: 3069

I recommend the only pythonic way:

if isinstance(x, (list, tuple))): pass

Upvotes: 19

Scott Griffiths
Scott Griffiths

Reputation: 21925

There's nothing wrong with using isinstance as long as it's not redundant. If a variable should only be a list/tuple then document the interface and just use it as such. Otherwise a check is perfectly reasonable:

if isinstance(a, collections.abc.Iterable):
    # use as a container
else:
    # not a container!

This type of check does have some good use-cases, such as with the standard string startswith / endswith methods (although to be accurate these are implemented in C in CPython using an explicit check to see if it's a tuple - there's more than one way to solve this problem, as mentioned in the article you link to).

An explicit check is often better than trying to use the object as a container and handling the exception - that can cause all sorts of problems with code being run partially or unnecessarily.

Upvotes: 43

mahdi omidiyan
mahdi omidiyan

Reputation: 51

Another easy way to find out if a variable is either list or tuple or generally check variable type would be :

def islist(obj):
    if ("list" in str(type(obj))):
        return True
    else:
        return False

Upvotes: 5

Saif Faidi
Saif Faidi

Reputation: 529

Another way is to use isinstance with typing.

from typing import List, Tuple
>> isinstance([1,2], Tuple)
False
>> isinstance([1,2], List)
True

Upvotes: 2

Rusca8
Rusca8

Reputation: 612

You know... I may be doing this the stupid way, but I do this:

try:
    len(thing)
except:
    # not a list

Like, if I can know the length of it, it gotta be more than one thing.

Edit: Just realized it won't work if the non-list item is a string (since a string is essentially a list of characters).

Upvotes: 0

Apollo Data
Apollo Data

Reputation: 1426

Not the most elegant, but I do (for Python 3):

if hasattr(instance, '__iter__') and not isinstance(instance, (str, bytes)):
    ...

This allows other iterables (like Django querysets) but excludes strings and bytestrings. I typically use this in functions that accept either a single object ID or a list of object IDs. Sometimes the object IDs can be strings and I don't want to iterate over those character by character. :)

Upvotes: 0

ZXX
ZXX

Reputation: 4762

Has to be more complex test if you really want to handle just about anything as function argument.

type(a) != type('') and hasattr(a, "__iter__")

Although, usually it's enough to just spell out that a function expects iterable and then check only type(a) != type('').

Also it may happen that for a string you have a simple processing path or you are going to be nice and do a split etc., so you don't want to yell at strings and if someone sends you something weird, just let him have an exception.

Upvotes: 4

Xanderite
Xanderite

Reputation: 189

On Python 2.8 type(list) is list returns false
I would suggest comparing the type in this horrible way:

if type(a) == type([]) :
  print "variable a is a list"

(well at least on my system, using anaconda on Mac OS X Yosemite)

Upvotes: 12

Sean DiZazzo
Sean DiZazzo

Reputation: 697

How about: hasattr(a, "__iter__") ?

It tells if the object returned can be iterated over as a generator. By default, tuples and lists can, but not the string types.

Upvotes: 9

jcdyer
jcdyer

Reputation: 19145

Go ahead and use isinstance if you need it. It is somewhat evil, as it excludes custom sequences, iterators, and other things that you might actually need. However, sometimes you need to behave differently if someone, for instance, passes a string. My preference there would be to explicitly check for str or unicode like so:

import types
isinstance(var, types.StringTypes)

N.B. Don't mistake types.StringType for types.StringTypes. The latter incorporates str and unicode objects.

The types module is considered by many to be obsolete in favor of just checking directly against the object's type, so if you'd rather not use the above, you can alternatively check explicitly against str and unicode, like this:

isinstance(var, (str, unicode)):

Edit:

Better still is:

isinstance(var, basestring)

End edit

After either of these, you can fall back to behaving as if you're getting a normal sequence, letting non-sequences raise appropriate exceptions.

See the thing that's "evil" about type checking is not that you might want to behave differently for a certain type of object, it's that you artificially restrict your function from doing the right thing with unexpected object types that would otherwise do the right thing. If you have a final fallback that is not type-checked, you remove this restriction. It should be noted that too much type checking is a code smell that indicates that you might want to do some refactoring, but that doesn't necessarily mean you should avoid it from the getgo.

Upvotes: 126

wall-e
wall-e

Reputation: 7398

if type(x) is list:
    print 'a list'
elif type(x) is tuple:
    print 'a tuple'
else:
    print 'neither a tuple or a list'

Upvotes: 674

tetra5
tetra5

Reputation: 125

>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True

Upvotes: 10

Geoff Reedy
Geoff Reedy

Reputation: 36011

If you just need to know if you can use the foo[123] notation with the variable, you can check for the existence of a __getitem__ attribute (which is what python calls when you access by index) with hasattr(foo, '__getitem__')

Upvotes: 4

Wim
Wim

Reputation: 11242

Python uses "Duck typing", i.e. if a variable kwaks like a duck, it must be a duck. In your case, you probably want it to be iterable, or you want to access the item at a certain index. You should just do this: i.e. use the object in for var: or var[idx] inside a try block, and if you get an exception it wasn't a duck...

Upvotes: 8

Adam Crossland
Adam Crossland

Reputation: 14213

In principle, I agree with Ignacio, above, but you can also use type to check if something is a tuple or a list.

>>> a = (1,)
>>> type(a)
(type 'tuple')
>>> a = [1]
>>> type(a)
(type 'list')

Upvotes: 1

Ignacio Vazquez-Abrams
Ignacio Vazquez-Abrams

Reputation: 798566

Document the argument as needing to be a sequence, and use it as a sequence. Don't check the type.

Upvotes: 11

Related Questions