Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to check if an object is a list or tuple (but not string)?

This is what I normally do in order to ascertain that the input is a list/tuple - but not a str. Because many times I stumbled upon bugs where a function passes a str object by mistake, and the target function does for x in lst assuming that lst is actually a list or tuple.

assert isinstance(lst, (list, tuple)) 

My question is: is there a better way of achieving this?

like image 750
Sridhar Ratnakumar Avatar asked Dec 02 '09 18:12

Sridhar Ratnakumar


People also ask

How do you check if an object is a string or list in Python?

The best way to checks if the object is a string is by using the isinstance() method in Python. This function returns True if the given object is an instance of class classified or any subclass of class info, otherwise returns False.

How do I check if a variable is a list or a string?

Check if Variable is a List with type() Now, to alter code flow programatically, based on the results of this function: a_list = [1, 2, 3, 4, 5] # Checks if the variable "a_list" is a list if type(a_list) == list: print("Variable is a list.") else: print("Variable is not a list.")

How do you check if an object is a tuple in Python?

Method #1 : Using type() This inbuilt function can be used as shorthand to perform this task. It checks for the type of variable and can be employed to check tuple as well.

How do you check if an object is a list?

Given an object, the task is to check whether the object is list or not. if isinstance (ini_list1, list ): print ( "your object is a list !" )


2 Answers

In python 2 only (not python 3):

assert not isinstance(lst, basestring) 

Is actually what you want, otherwise you'll miss out on a lot of things which act like lists, but aren't subclasses of list or tuple.

like image 172
Nick Craig-Wood Avatar answered Sep 22 '22 09:09

Nick Craig-Wood


Remember that in Python we want to use "duck typing". So, anything that acts like a list can be treated as a list. So, don't check for the type of a list, just see if it acts like a list.

But strings act like a list too, and often that is not what we want. There are times when it is even a problem! So, check explicitly for a string, but then use duck typing.

Here is a function I wrote for fun. It is a special version of repr() that prints any sequence in angle brackets ('<', '>').

def srepr(arg):     if isinstance(arg, basestring): # Python 3: isinstance(arg, str)         return repr(arg)     try:         return '<' + ", ".join(srepr(x) for x in arg) + '>'     except TypeError: # catch when for loop fails         return repr(arg) # not a sequence so just return repr 

This is clean and elegant, overall. But what's that isinstance() check doing there? That's kind of a hack. But it is essential.

This function calls itself recursively on anything that acts like a list. If we didn't handle the string specially, then it would be treated like a list, and split up one character at a time. But then the recursive call would try to treat each character as a list -- and it would work! Even a one-character string works as a list! The function would keep on calling itself recursively until stack overflow.

Functions like this one, that depend on each recursive call breaking down the work to be done, have to special-case strings--because you can't break down a string below the level of a one-character string, and even a one-character string acts like a list.

Note: the try/except is the cleanest way to express our intentions. But if this code were somehow time-critical, we might want to replace it with some sort of test to see if arg is a sequence. Rather than testing the type, we should probably test behaviors. If it has a .strip() method, it's a string, so don't consider it a sequence; otherwise, if it is indexable or iterable, it's a sequence:

def is_sequence(arg):     return (not hasattr(arg, "strip") and             hasattr(arg, "__getitem__") or             hasattr(arg, "__iter__"))  def srepr(arg):     if is_sequence(arg):         return '<' + ", ".join(srepr(x) for x in arg) + '>'     return repr(arg) 

EDIT: I originally wrote the above with a check for __getslice__() but I noticed that in the collections module documentation, the interesting method is __getitem__(); this makes sense, that's how you index an object. That seems more fundamental than __getslice__() so I changed the above.

like image 35
steveha Avatar answered Sep 22 '22 09:09

steveha