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?
I do this in my testcases.
Untested on generators, I think you are left at the next 'yield' if passed in a generator, which may screw things up downstream. But then again, this is a 'unittest'
The
str
object doesn't have an__iter__
attributeso you can do a check
and this will also raise a nice
AssertionError
for any other non-iterable object too.Edit: As Tim mentions in the comments, this will only work in python 2.x, not 3.x
In python 2 only (not python 3):
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
ortuple
.Python with PHP flavor:
Generally speaking, the fact that a function which iterates over an object works on strings as well as tuples and lists is more feature than bug. You certainly can use
isinstance
or duck typing to check an argument, but why should you?That sounds like a rhetorical question, but it isn't. The answer to "why should I check the argument's type?" is probably going to suggest a solution to the real problem, not the perceived problem. Why is it a bug when a string is passed to the function? Also: if it's a bug when a string is passed to this function, is it also a bug if some other non-list/tuple iterable is passed to it? Why, or why not?
I think that the most common answer to the question is likely to be that developers who write
f("abc")
are expecting the function to behave as though they'd writtenf(["abc"])
. There are probably circumstances where it makes more sense to protect developers from themselves than it does to support the use case of iterating across the characters in a string. But I'd think long and hard about it first.