Unsupported operand types in if/else list comprehension

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sat Apr 11 04:04:11 CEST 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 

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 

>>> t = ("not true", "correct")
>>> t[45 > 15]
>>> ("incorrect", "true")[15 > 99]

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
        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 

(3) Use a regular for loop with an accumulator:

b = []
for obj in alist:
    if isinstance(obj, basestring):
        obj = '"%s"' % 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:



More information about the Python-list mailing list