60
votes

Does a Python equivalent to the Ruby ||= operator ("set the variable if the variable is not set") exist?

Example in Ruby :

 variable_not_set ||= 'bla bla'
 variable_not_set == 'bla bla'

 variable_set = 'pi pi'
 variable_set ||= 'bla bla'
 variable_set == 'pi pi'
9
It doesn't set it if it's not set - it sets it if its current value is false (false or nil). Granted, this distinction is more important in languages that e.g. treat 0 and "" as false, but still - user395760
what is the use case for this ruby operator? - David Heffernan
The way to do it would be to use a try except NameError as indicated by phihag, butthis does not make myuch sense in Python as stated by everyone here. In Ruby it is more usefull due to the way people do pass arbitrary code blocks to be run inside a function. The target function than might need to set a variable that was not initialized in the foreign block it executed. There are no such cases in Python. - jsbueno

9 Answers

16
votes

No, the replacement is:

try:
   v
except NameError:
   v = 'bla bla'

However, wanting to use this construct is a sign of overly complicated code flow. Usually, you'd do the following:

try:
   v = complicated()
except ComplicatedError: # complicated failed
   v = 'fallback value'

and never be unsure whether v is set or not. If it's one of many options that can either be set or not, use a dictionary and its get method which allows a default value.

185
votes

I'm surprised no one offered this answer. It's not as "built-in" as Ruby's ||= but it's basically equivalent and still a one-liner:

foo = foo if 'foo' in locals() else 'default'

Of course, locals() is just a dictionary, so you can do:

foo = locals().get('foo', 'default')
24
votes

I would use

x = 'default' if not x else x

Much shorter than all of your alternatives suggested here, and straight to the point. Read, "set x to 'default' if x is not set otherwise keep it as x." If you need None, 0, False, or "" to be valid values however, you will need to change this behavior, for instance:

valid_vals = ("", 0, False) # We want None to be the only un-set value

x = 'default' if not x and x not in valid_vals else x

This sort of thing is also just begging to be turned into a function you can use everywhere easily:

setval_if = lambda val: 'default' if not val and val not in valid_vals else val

at which point, you can use it as:

>>> x = None # To set it to something not valid
>>> x = setval_if(x) # Using our special function is short and sweet now!
>>> print x # Let's check to make sure our None valued variable actually got set
'default'

Finally, if you are really missing your Ruby infix notation, you could overload ||=| (or something similar) by following this guy's hack: http://code.activestate.com/recipes/384122-infix-operators/

6
votes

There is conditional assignment in Python 2.5 and later - the syntax is not very obvious hence it's easy to miss. Here's how you do it:

x = true_value if condition else false_value

For further reference, check out the Python 2.5 docs.

4
votes

No, not knowing which variables are defined is a bug, not a feature in Python.

Use dicts instead:

d = {}
d.setdefault('key', 1)
d['key'] == 1

d['key'] = 2
d.setdefault('key', 1)
d['key'] == 2
4
votes

(can't comment or I would just do that) I believe the suggestion to check locals above is not quite right. It should be:

foo = foo if 'foo' in locals() or 'foo' in globals() else 'default'

to be correct in all contexts.

However, despite its upvotes, I don't think even that is a good analog to the Ruby operator. Since the Ruby operator allows more than just a simple name on the left:

foo[12] ||= something
foo.bar ||= something

The exception method is probably closest analog.

1
votes

I usually do this the following way:

def set_if_not_exists(obj,attr,value):
 if not hasattr(obj,attr): setattr(obj,attr,value)
0
votes

I think what you are looking for, if you are looking for something in a dictionary, is the setdefault method:

(Pdb) we=dict()
(Pdb) we.setdefault('e',14)
14
(Pdb) we['e']
14
(Pdb) we['r']="p"
(Pdb) we.setdefault('r','jeff')
'p'
(Pdb) we['r']
'p'
(Pdb) we[e]
*** NameError: name 'e' is not defined
(Pdb) we['e']
14
(Pdb) we['q2']

*** KeyError: 'q2' (Pdb)

The important thing to note in my example is that the setdefault method changes the dictionary if and only if the key that the setdefault method refers to is not present.

-1
votes

I am not sure I understand the question properly here ... Trying to "read" the value of an "undefined" variable name will trigger a NameError. (see here, that Python has "names", not variables...).

== EDIT ==

As pointed out in the comments by delnan, the code below is not robust and will break in numerous situations ...

Nevertheless, if your variable "exists", but has some sort of dummy value, like None, the following would work :

>>> my_possibly_None_value = None
>>> myval = my_possibly_None_value or 5
>>> myval
5
>>> my_possibly_None_value = 12
>>> myval = my_possibly_None_value or 5
>>> myval
12
>>> 

(see this paragraph about Truth Values)