Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is there any expression in python that similar to ruby's ||=

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?

like image 240
Conan Avatar asked Jul 20 '12 07:07

Conan


4 Answers

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
like image 53
BrenBarn Avatar answered Oct 15 '22 01:10

BrenBarn


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.

like image 20
casevh Avatar answered Oct 15 '22 02:10

casevh


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'
like image 1
Jon Clements Avatar answered Oct 15 '22 02:10

Jon Clements


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

like image 1
angeloce Avatar answered Oct 15 '22 00:10

angeloce