I came across an interesting expression in Ruby:
a ||= "new"
It means that if a is not defined, the "new" value will be assigned to a; otherwise, a will be the same as it is. It is useful when doing some DB query. If the value is set, I don't want to fire another DB query.
So I tried the similar mindset in Python:
a = a if a is not None else "new"
It failed. I think that it because you cannot do "a = a" in Python, if a is not defined.
So the solutions that I can come out are checking locals() and globals(), or using try...except expression:
myVar = myVar if 'myVar' in locals() and 'myVar' in globals() else "new"
or
try:
myVar
except NameError:
myVar = None
myVar = myVar if myVar else "new"
As we can see, the solutions are not that elegant. So I'd like to ask, is there any better way of doing this?
Using an undefined variable as a "default" is a bit of a code smell. As you discovered, it fails because you can't do a = a
if a doesn't already exist. It's better to initialize your variable with some default value (like None) and then check for that. So you pretty much found the solution. The only thing is that instead of leaving your variable uninitalized and trying to use "does not exist" as the "missing" value, you should explicitly initialize it. So, instead of doing this:
# code with no initialization. . .
a ||= blah
do this:
a = None
# code
if a is None:
a = blah
How about?
try:
a = a
except NameError:
a = "new"
It's not very short but does clearly (at least to me) explain the intent of the code.
If you really wanted this behaviour you'd be best off in Python using a dict
, eg: d.get('a', 'new')
. Which means you could muck about with globals()
/locals()
.get('a', 'new')
, but that's generally not the way to do things in Python - each name binding should have an initial value even if it's some sort of sentinel value (such as None
).
horrible example with globals() and using setdefault()
>>> a
Traceback (most recent call last):
File "<pyshell#66>", line 1, in <module>
a
NameError: name 'a' is not defined
>>> globals().setdefault('a', 'new')
'new'
>>> a
'new'
>>> a = 'old'
>>> globals().setdefault('a', 'new')
'old'
>>> a
'old'
Pythonic is that you should know it before using it especially in local/global vars rather than guess where it is. You can write this code but it is not pythonic
a = None
# other codes
a = a or 'new'
is all right
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With