Unsupported operand types in if/else list comprehension
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Fri Apr 10 22:04:11 EDT 2009
On Fri, 10 Apr 2009 17:07:38 -0400, Mike H wrote:
> Hello all, I have a question about the if/else aspect of list
> comprehension:
>
> I would like to go through a list and place quotes around an item if it
> is a string, and keep the item the same if it's anything else:
>
> e.g.['a',9,'8b'] --> ['"a"', 9, '"8b"']
>
> I understand that if/else list comprehension should be generally:
>
> b=[(F,T)[boolean test] for val in X]
That's *one* specific form of a list comprehension. A more general form
is:
alist = [ some-expression for val in sequence if condition ]
In your case, (F, T)[boolean test] counts as one such possible
expression. It's not a "magic" list comprehension syntax, you can use it
anywhere:
>>> t = ("not true", "correct")
>>> t[45 > 15]
'correct'
>>> ("incorrect", "true")[15 > 99]
'incorrect'
The disadvantage of the (F, T)[bool] expression is that both F and T are
evaluated *before* the boolean test. Think about it: you have to create
the tuple (F, T) before you can index into it!
In your case, there are three obvious solutions (untested). In no
particular order:
(1) Use a helper function.
def quote_obj(obj):
"""Return strings quoted, and all other objects unchanged."""
if isinstance(obj, basestring):
return '"%s"' % obj
else:
return obj
b = [quote_obj(x) for x in alist]
(2) Use the ternary if expression:
b = ['"%s"' % obj if isinstance(obj, basestring) else obj for obj in
alist]
(3) Use a regular for loop with an accumulator:
b = []
for obj in alist:
if isinstance(obj, basestring):
obj = '"%s"' % obj
b.append(obj)
The less obvious solution is to rethink your program design. Having
multiple types of object in the one list is often (but not always) a sign
that your design is too complicated and is trying to do to much in too
little code. It is a mild code-smell:
http://www.joelonsoftware.com/articles/Wrong.html
--
Steven
More information about the Python-list
mailing list