views:

212

answers:

4

What is the easiest way to check if something is a list?

A method doSomething has the parameters a and b. In the method, it will loop through the list a and do something. I'd like a way to make sure a is a list, before looping through - thus avoiding an error or the unfortunate circumstance of passing in a string then getting back a letter from each loop.

This question must have been asked before - however my googles failed me. Cheers.

+2  A: 

Usually it's considered not a good style to perform type-check in Python, but try

if isinstance(a, list):
  ...

(I think you may also check if a.__iter__ exists.)

KennyTM
You're right, it isn't good style to typecheck. Checking for an `__iter__` method is just as silly: just do `for item in a`. If you have a reason to suspect `a` isn't iterable (naughty, naughty!), catch the `TypeError`.
Mike Graham
@Mike: `"12345".__iter__` -> AttributeError: 'str' object has no attribute '__iter__', but `for x in "12345": print x` works.
KennyTM
Which should be *discouraging*, not *encouraging*. Checking for `__iter__` only works by implementation detail, not some meaningful difference, and doesn't indicate whether an object is iterable or in any direct method indicate the information you are getting about strings. If an object uses the old iterator protocol (calling sequential indices) or is implemented in C in an ugly way (such that the `__iter__` method is not exposed) like this case, the result seems rather unintuitive.
Mike Graham
+9  A: 

To enable more usecases, but still treat strings as scalars, don't check for a being a list, check that it isn't a string:

if not isinstance(a, basestring):
    ...
Ants Aasma
+1, I like this best because plenty of non-lists are just fine, strings (plain and unicode, whence the `basestring`) are the black sheep and should be the ones singled out.
Alex Martelli
Using this code indicates you're almost certainly doing something wrong. If you provide a consistent API, this should not be necessary. This also can violate user expectations when types are used like they are intended, for example when someone uses an object that is conceptually a string but is an instance of a different class.
Mike Graham
+5  A: 

I'd like a way to make sure a is a list, before looping through

Document the function.

detly
This solution is the most powerful, useful, robust way.
Mike Graham
It has the added benefit where, if someone emails you and says "hey, your function does something strange to strings," you automatically know they're an idiot. No compiler can do that.
detly
But sometimes you already know they're an idiot, can't get rid of them, want them to stop bothering you, and wonder if there's some code you can write to nip it in the bud. It's a vain hope; there are always more creative fools. This is where people get ideas like USB missile launchers.
Mike DeSimone
If you know they're an idiot but can't get rid of them, you are by definition more of an idiot. You therefore cannot pre-empt their idiocy with more of your own. QED. (Seriously though, as you say, there is no upper bound on this kind of thing. Writing more code to avoid it is like trying to write code to handle arbitrarily large integers in C.)
detly
@Mike DeSimone, Making your code worse doesn't usually *actually* help you deal with idiot users better than making your code better.
Mike Graham
@Mike Graham: I know, which is why I don't try. But there is always that temptation. @detly: Umm, thanks... I guess. Any tips for getting rid of idiot customers while still getting paid?
Mike DeSimone
Throw candy in one direction and run in the other? :P (If you get *paid* to deal with idiots then my previous logic is flawed. A fool and his money, etc.)
detly
+5  A: 

Typechecking hurts the generality, simplicity, and maintainability of your code. It is seldom used in good, idiomatic Python programs.

There are two main reasons people want to typecheck:

  1. To issue errors if the caller provides the wrong type.

    This is not worth your time. If the user provides an incompatible type for the operation you are performing, an error will already be raised when the compatibility is hit. It is worrisome that this might not happen immediately, but it typically doesn't take long at all and results in code that is more robust, simple, efficient, and easier to write.

    Oftentimes people insist on this with the hope they can catch all the dumb things a user can do. If a user is willing to do arbitrarily dumb things, there is nothing you can do to stop him. Typechecking mainly has the potential of keeping a user who comes in with his own types that are drop-in replacements for the ones replaced or when the user recognizes that your function should actually be polymorphic and provides something different that can accept the same operation.

    If I had a big system where lots of things made by lots of people should fit together right, I would use a system like zope.interface to make testing that everything fits together right.

  2. To do different things based on the types of the arguments received.

    This makes your code worse because your API is inconsistent. A function or method should do one thing, not fundamentally different things. This ends up being a feature not usually worth supporting.

    One common scenario is to have an argument that can either be a foo or a list of foos. A cleaner solution is simply to accept a list of foos. Your code is simpler and more consistent. If it's an important, common use case only to have one foo, you can consider having another convenience method/function that calls the one that accepts a list of foos and lose nothing. Providing the first API would not only have been more complicated and less consistent, but it would break when the types were not the exact values expected; in Python we distinguish between objects based on their capabilities, not their actual types. It's almost always better to accept an arbitrary iterable or a sequence instead of a list and anything that works like a foo instead of requiring a foo in particular.

As you can tell, I do not think either reason is compelling enough to typecheck under normal circumstances.

Mike Graham