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.
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)
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.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.
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
Document the argument as needing to be a sequence, and use it as a sequence. Don't check the type.
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')
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.
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. :)
>>> l = []
>>> l.__class__.__name__ in ('list', 'tuple')
True
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__')
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.
if type(x) is list:
print 'a list'
elif type(x) is tuple:
print 'a tuple'
else:
print 'neither a tuple or a list'
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...
Source: Stackoverflow.com