Definitely the latter.
If you use the former, and someone edits just one of the literal values, now it's broken:
lambda pixel: (0,0,0) if pixel == (0,0,8) else (255,255,255),
I introduced a bug in the above. I edited the tuple used in the condition, but didn't edit the first tuple. This is hard to spot by casual inspection.
Consider this:
big_long_expression if something == big_long_expression else whatever
The reader has to mentally evaluate big_long_expression
each time, and compare whether they are actually the same or not. If you instead use the latter form, now it's clear: you either return the expression unchanged, or in the else case you return something else.
It's the same reason I prefer the +=
operator:
my_class.a.b[i+3] = my_class.a.b[i+3] + 2
compare with:
my_class.a.b[i+3] += 2
Both do the same thing, but the second one is so much easier to understand.
I always prefer the syntax that expresses your intentions more clearly. I think your second format makes it most clear: check a condition, and when it's true leave the value alone, else return a special value.
EDIT: in comments directly under the question, @DSM made an excellent point. The first expression also has a subtle property: it always returns a tuple, even when the expression being compared wasn't a tuple. As long as pixel
is any class that can be compared to a tuple, either expression will work. But if you want your lambda to consistently return a tuple from either case of the ternary, then the first form is preferable.
Here are two rewrites of your code, for your consideration.
The first:
ORIGIN = (0, 0, 0)
lambda pixel: ORIGIN if pixel == ORIGIN else (255,255,255),
Now at least there is a single point to edit to change the origin. This is the way I'd recommend if you do want to always return a tuple.
The second:
lambda pixel: pixel if pixel == (0, 0, 0) else type(pixel)((255, 255, 255))
This gets the type of pixel
, then calls that type to construct a new object. This assumes that the pixel
is of a class that is not only comparable to a tuple, but that if you pass a tuple to the class it will use that to build a new instance of the class based on the tuple.
An example of this in use:
f = lambda pixel: pixel if pixel == (0, 0, 0) else type(pixel)((255, 255, 255))
class T(tuple):
"""
Make a class that acts exactly like a tuple.
"""
pass
x = T((1,2,3))
assert type(x) == T
assert type(x) == type(f(x))
x = (1, 2, 3)
assert type(x) == tuple
assert type(x) == type(f(x))