83

I am a RoR programmer new to Python. I am trying to find the syntax that will allow me to set a variable to a specific value only if it wasn't previously assigned. Basically I want:

# only if var1 has not been previously assigned

var1 = 4
BMW
  • 42,880
  • 12
  • 99
  • 116
Spencer
  • 21,348
  • 34
  • 85
  • 121
  • 7
    Under what circumstance would you be referencing variables that may not exist? Do you want to reference variables that have been declared but not yet initialized? – mwcz Sep 07 '11 at 18:20

9 Answers9

162

You should initialize variables to None and then check it:

var1 = None
if var1 is None:
    var1 = 4

Which can be written in one line as:

var1 = 4 if var1 is None else var1

or using shortcut (but checking against None is recommended)

var1 = var1 or 4

alternatively if you will not have anything assigned to variable that variable name doesn't exist and hence using that later will raise NameError, and you can also use that knowledge to do something like this

try:
    var1
except NameError:
    var1 = 4

but I would advise against that.

phoenix
  • 7,988
  • 6
  • 39
  • 45
Anurag Uniyal
  • 85,954
  • 40
  • 175
  • 219
  • Note that if you want to assign a value, you either need a `global`/`nonlocal` declaration or use `except UnboundLocalError` (and accept that the variable will be local and a globally-set value will be ignored). –  Sep 07 '11 at 18:22
  • @delnan where in my example I would get UnboundLocalError ? – Anurag Uniyal Sep 07 '11 at 18:25
  • 2
    Because of the assignment later on (in the `except`), `var1` is a local variable unless the snippet is at module (that is, global) level or there is a line `global var1`. Accessing a not-yet-assigned local variable raises `UnboundLocalError` instead of `NameError` (which is reserved for global names). –  Sep 07 '11 at 18:27
  • 1
    @delnan I don't understand can you give an example demonstrating this because `>>> issubclass(UnboundLocalError, NameError) True` – Anurag Uniyal Sep 08 '11 at 02:01
  • 1
    Oh damn, I always forget that subtype relationship. Your code is indeed correct then. Sorry for the confusion. –  Sep 08 '11 at 13:14
  • Why would you advise against using the `try` `except` construction? It looks a bit bulky, but doesn't make any assumptions. – cgogolin Jun 08 '15 at 15:14
  • @cgogolin I think it is better to be explicit and declare variable before hand, assigning to None convention is better than try/catch everywhere – Anurag Uniyal Jun 09 '15 at 08:25
  • 10
    The `var1 = var1 or 4` can hurt you if var1 was `0` as `0` is a falsey value and therefore `0 or 4` evaluates to `4` which is not what you won't in this case. You can check which other things evaluate to "false" in https://docs.python.org/2/library/stdtypes.html#truth-value-testing – RubenLaguna Oct 21 '15 at 22:01
  • A `NameError` should be an indication that you made a typo in a variable name, not something you use for flow control. – chepner Nov 16 '22 at 20:09
59
var1 = var1 or 4

The only issue this might have is that if var1 is a falsey value, like False or 0 or [], it will choose 4 instead. That might be an issue.

ubadub
  • 3,571
  • 21
  • 32
  • 9
    See [truth value testing](https://docs.python.org/2/library/stdtypes.html#truth-value-testing) for a complete list of things that evaluate to False, some of them may surprising for some. – RubenLaguna Oct 09 '14 at 09:32
37

This is a very different style of programming, but I always try to rewrite things that looked like

bar = None
if foo():
    bar = "Baz"

if bar is None:
    bar = "Quux"

into just:

if foo():
    bar = "Baz"
else:
    bar = "Quux"

That is to say, I try hard to avoid a situation where some code paths define variables but others don't. In my code, there is never a path which causes an ambiguity of the set of defined variables (In fact, I usually take it a step further and make sure that the types are the same regardless of code path). It may just be a matter of personal taste, but I find this pattern, though a little less obvious when I'm writing it, much easier to understand when I'm later reading it.

SingleNegationElimination
  • 151,563
  • 33
  • 264
  • 304
  • 57
    This could even be shortened in a one-liner using `bar = "Baz" if foo() else "Quux"` – mdeous Sep 07 '11 at 18:50
  • 1
    What is foo()? And how is this an answer to the question? The reply does not consist of conditional assigning to variable depending on its existence. – Eduard Mar 04 '18 at 09:14
  • 4
    Be careful, this fails if any of the intended values are falsy (eg. `False`, `0`, `''`, `[]`, `{}`). Better to say `x = y if x is None else x`. – Ninjakannon Apr 16 '19 at 10:36
  • @mdeous that is wrong, as foo() == False will make bar be "Quux". Yours is an about average quality Python solution. – Henry Henrinson Oct 28 '19 at 10:17
  • @HenryHenrinson isn't that the exact same behavior as the 2nd example in the answer? (not to mention that this issue has already been brought up by @Ninjakannon) – mdeous Oct 29 '19 at 14:44
27

I'm also coming from Ruby so I love the syntax foo ||= 7.

This is the closest thing I can find.

foo = foo if 'foo' in vars() else 7

I've seen people do this for a dict:

try:
    foo['bar']
except KeyError:
    foo['bar'] = 7

Upadate: However, I recently found this gem:

foo['bar'] = foo.get('bar', 7)

If you like that, then for a regular variable you could do something like this:

vars()['foo'] = vars().get('foo', 7)
l__flex__l
  • 1,388
  • 1
  • 16
  • 22
18

Here is the easiest way I use, hope works for you,

var1 = var1 or 4

This assigns 4 to var1 only if var1 is None , False or 0

DeepBlue
  • 415
  • 4
  • 9
7

One-liner solution here:

var1 = locals().get("var1", "default value")

Instead of having NameError, this solution will set var1 to default value if var1 hasn't been defined yet.

Here's how it looks like in Python interactive shell:

>>> var1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
NameError: name 'var1' is not defined
>>> var1 = locals().get("var1", "default value 1")
>>> var1
'default value 1'
>>> var1 = locals().get("var1", "default value 2")
>>> var1
'default value 1'
>>>
codinaut
  • 71
  • 1
  • 1
4

IfLoop's answer (and MatToufoutu's comment) work great for standalone variables, but I wanted to provide an answer for anyone trying to do something similar for individual entries in lists, tuples, or dictionaries.

Dictionaries

existing_dict = {"spam": 1, "eggs": 2}
existing_dict["foo"] = existing_dict["foo"] if "foo" in existing_dict else 3

Returns {"spam": 1, "eggs": 2, "foo": 3}

Lists

existing_list = ["spam","eggs"]
existing_list = existing_list if len(existing_list)==3 else 
                existing_list + ["foo"]

Returns ["spam", "eggs", "foo"]

Tuples

existing_tuple = ("spam","eggs")
existing_tuple = existing_tuple if len(existing_tuple)==3 else 
                 existing_tuple + ("foo",)

Returns ("spam", "eggs", "foo")

(Don't forget the comma in ("foo",) to define a "single" tuple.)

The lists and tuples solution will be more complicated if you want to do more than just check for length and append to the end. Nonetheless, this gives a flavor of what you can do.

Alex P. Miller
  • 2,128
  • 1
  • 23
  • 20
0

If you mean a variable at the module level then you can use "globals":

if "var1" not in globals():
    var1 = 4

but the common Python idiom is to initialize it to say None (assuming that it's not an acceptable value) and then testing with if var1 is not None.

6502
  • 112,025
  • 15
  • 165
  • 265
  • 7
    That way lies madness. This breaks on local variables, using `locals()` breaks on globals, and I don't think either works with nonlocals. To fix that, one would have to emulate the whole scoping rules or write the code assuming one of both. –  Sep 07 '11 at 18:20
  • 2
    @delnan: About local/nonglobal this is what I meant with "If you mean a variable at the module level". About that idiotic "That way lies madness" you should tell the OP, not me... by the way in the answer is actually told this is not how things should be done. – 6502 Sep 07 '11 at 21:34
  • Don't introduce constraints that weren't in the original question. There was no mention of doing something only for global variables. – chepner Nov 16 '22 at 20:12
  • @chepner: that kind of use reminded me of `defvar` of common lisp, my wild guess was that it was looked for at global level – 6502 Nov 16 '22 at 20:34
0

Just use not condition in if condition

var1=None
if not var1:
  var1=4

Ayaz Khan
  • 104
  • 1
  • 9