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
but forget that, that's not my question. My question is:
Is there anything 'wrong' with x = x if x else y
besides the fact it's a ternary? Specifically, is it ok to have a ternary self-assign like that.
NOTE
My qustion is not is x = x if C else y
ok. I know it is.
Many thanks
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.
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)
2 0 LOAD_FAST 0 (x)
3 POP_JUMP_IF_FALSE 12
6 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.
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.
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).