86

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'
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
Hartator
  • 5,029
  • 4
  • 43
  • 73
  • 1
    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 –  Jun 19 '11 at 12:23
  • what is the use case for this ruby operator? – David Heffernan Jun 19 '11 at 12:54
  • 1
    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 Jun 19 '11 at 19:45

10 Answers10

220

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')
Keith Devens
  • 2,832
  • 2
  • 15
  • 7
32

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/

emish
  • 2,813
  • 5
  • 28
  • 34
  • 7
    Your first example doesn't work: >>> x = 'default' if not x else x Traceback (most recent call last): File "", line 1, in NameError: name 'x' is not defined – J Jones Jan 30 '15 at 23:06
  • 10
    This is an incorrect answer, and will fail if x does not exist. Since the question asks for a way to test for existance, this solution will not work. – Shayne Mar 29 '16 at 08:47
  • 2
    This answer solved the problem "conditional assignment". set a variable if it was not set. of course, everything on the right must be defined, else you will get an error (I just took it as a pseudo-code). `x = "value1" if True else "value2"`. in general. `x = 'value1' if condition else 'value2'` – Maubeh Jan 06 '19 at 14:54
  • This answer is both valid and very useful, and educational to boot. I would suggest a note be added that the variable must exist -within- the answer text, but fantastic otherwise. – Danin Jun 19 '22 at 00:00
16

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.

phihag
  • 278,196
  • 72
  • 453
  • 469
  • 2
    No, you [don't use `except:`](http://docs.python.org/howto/doanddont.html#except). –  Jun 19 '11 at 12:33
  • @delnan I didn't want to make specific assumptions about the nature of `complicated()`. Added it. – phihag Jun 19 '11 at 12:35
  • You sure? @emish offers a much simpler solution. – Donal Lafferty Dec 17 '12 at 16:39
  • That's a bad solution. Not only is it more complicated, but it's also much worse performance-wise. I would go as far as suggest to remove this solution from the question. – yuvalm2 Mar 19 '21 at 14:02
  • Using a `try . . .except` for control flow is bad practice. An exception should be used when something is wrong not when trying to assign a variable. – Paul D. Nov 07 '22 at 20:33
10

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.

the Tin Man
  • 158,662
  • 42
  • 215
  • 303
mainas
  • 754
  • 1
  • 6
  • 15
5

(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.

Jas
  • 327
  • 2
  • 9
4

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
Jochen Ritzel
  • 104,512
  • 31
  • 200
  • 194
1

I usually do this the following way:

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

I do this... just sharing in case it's useful for the OP or anyone else...

def iff(value, default):
    return default if not value else value

Usage:

z = iff(x,y) # z = x if and only if x is not null otherwise y
E_net4
  • 27,810
  • 13
  • 101
  • 139
chad steele
  • 828
  • 9
  • 13
0

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.

Jeff Silverman
  • 692
  • 1
  • 8
  • 15
-1

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)

tsimbalar
  • 5,790
  • 6
  • 37
  • 61
  • 2
    This breaks as soon as the value might be 0, "", an empty string, or anything else that's "falsy". Explicitly check whether it `is None`. –  Jun 19 '11 at 12:46
  • Oh yes, you are right, I hadn't thought of that. Thanks for the hint ! I have actually never had the need to do this "or" thing, and I thought it was a valid answer to the question ... but the question itself does not seem to be relevqnt to Python anyway ... – tsimbalar Jun 19 '11 at 12:47