Skip to content Skip to sidebar Skip to footer

Self-referencing Ternary

I've been doing this for a while: x = x if x else y In all sorts of contexts where x might be None, False, 0, '', [], or {}. I know the purists would rather I: if not x: x = y

Solution 1:

Nope, nothing wrong with it. It's very pythonic in fact. I recall reading that that's the preferred (by Guido himself) ternary-equivalent. I'll see if I can dig up the reference. Personally, I find the other way more readable, but you didn't ask for my personal opinon. ;)

UPDATE: Here's the citation. Core Python Programming, 2nd ed.; Wesley J. Hun; Prentice Hall 2007

If you are coming from the C/C++ or Java world, it is difficult to ignore or get over the fact that Python has not had a conditional or ternary operator (C ? X : Y) for the longest time. [...] Guido has resisted adding such a feature to Python because of his belief in keeping code simple and not giving programmers easy ways to obfuscate their code. However, after more than a decade, he has given in, mostly because of the error-prone ways in which people have tried to simulate it using and and or - many times incorrectly. According to the FAQ, the one way of getting it right is (C and [X] or [Y])[0]. The only problem was that the community could not agree on the syntax. (You really have to take a look at PEP 308 to see all the different proposals.) This is one of the areas of Python in which people have expressed strong feelings. The final decision came down to Guido choosing the most favored (and his most favorite) of all the choices, then applying it to various modules in the standard library. According to the PEP, "this review approximates a sampling of real-world use cases, across a variety of applications, written by a number of programmers with diverse backgrounds." And this is the syntax that was finally chosen for integration into Python 2.5: X if C else Y.

Solution 2:

I hesitate to do this, because here's my real opinion:

Don't micro-optimize. Use what you are comfortable with; use what makes your code most readable. The ternary statement is perfectly fine if that is what you feel is most readable.

That said,

ben@nixbox:~$ python3 -m timeit 'x = 1; x=x if x else 2'10000000 loops, best of 3: 0.0345 usec per loop
ben@nixbox:~$ python3 -m timeit '''
> x=1
> if not x:
>     x=2
> '''10000000 loops, best of 3: 0.0239 usec per loop

There is some small overhead in assigning x back onto itself.

dis.dis(f)
  20 LOAD_FAST                0 (x) 
              3 POP_JUMP_IF_FALSE       126 LOAD_FAST                0 (x) #this is the extra instruction
              9 JUMP_FORWARD             3 (to 15) 
        >>   12 LOAD_CONST               1 (1) 
        >>   15 STORE_FAST               0 (x) 
             18 LOAD_CONST               0 (None) 
             21 RETURN_VALUE

Back to my main point: don't worry about it. Use what you're comfortable with.

Solution 3:

There is nothing wrong with using ternary for x = x if c else y, however, in the case of x = x if x else y the logic really does just reduce to

x = x or y

This is because in Python x or y evaluates to 'if x is false, then y, else x'

So x if x else y == y if not x else x == x or y

Obviously, x or y is the clearest and should be used.

Solution 4:

From a language design point of view, nothing is wrong. As another poster mentioned, it's even the preferred way. I would even ask you why do you imply that being a ternary is wrong?

From a readability/maintainability point of view, things are a bit more databable. On one hand, if you are going to have a lot of casual, non-Python readers/maintainers, this construct (as opposed to if not x: x= C) could be much less readable. On the other hand, your program will most probably contain many other (and much deeper) Pythonisms. You have a right to expect a minimum of knowledge from your "readers".

From a performance point of view, x being a variable both forms are optimizable (if not effectively optimized) by the different implementations into the same code. Meaning no difference in these terms.

UPDATE:

I didn't know Guido's opinions on the subject cited by @Edward. I'm glad he agrees with me. Or I with him. But he was absolutely right about introducing the ternary operator, as it is much clearer than alternatives like x= (x,C)[not x] or x= x or C, which had been used (and promoted) by many early Python programmers with a C background (and perhaps also as a "cool", differentiating thing). BTW, both are generally correct (depending of the exact semantics intended).

Post a Comment for "Self-referencing Ternary"