What does an 'x = y or z' assignment do in Python?

Why do we see Python assignments with or?

For example:

def my_function(arg_1=None, arg_2=0):
    determination = arg_1 or arg_2 or 'no arguments given!'
    print(determination)
    return determination

When called with no arguments, the above function would print and return 'no arguments given!'

Why does Python do this, and how can one best make best use of this functionality?


Solution 1:

What the "or" expression does on assignment:

We sometimes see examples of this in Python as a substitute for conditional expression with ternary assignments, (in fact, it helped inspire the language to add conditional statements).

x = a or b

If bool(a) returns False, then x is assigned the value of b

Identical Use-case of Conditional Expressions (i.e. Ternary Assignments)

Here's an example of such a conditional expression that accomplishes the same thing, but with perhaps a bit less mystery.

def my_function(arg_1=None, arg_2=0):
    determination = arg_1 if arg_1 else arg_2 if arg_2 else 'no arguments given!'
    print(determination)
    return determination

Repeating this syntax too much is considered to be bad style, otherwise it's OK for one-liners. The downside is that it is a bit repetitive.

or Expressions

The base case, x or y returns x if bool(x) evaluates True, else it evaluates y, (see the docs for reference). Therefore, a series of or expressions has the effect of returning the first item that evaluates True, or the last item.

For example

'' or [] or 'apple' or () or set(['banana'])

returns 'apple', the first item that evaluates as True, and

'' or [] or ()

returns (), even though it evaluates as False.

Extended and usage

For contrast, x and y returns x if bool(x) evaluates as False, else it returns y.

It makes sense that and would work this way when you consider that all of the conditions in a conditional and series needs to evaluate as True for the control flow to proceed down that path, and that it makes no sense to continue evaluating those items when you come across one that is False.

The utility of using and for assignment is not immediately as apparent as using or, but it was historically used for ternary assignment. That is, before this more clear and straightforward construction was available:

a = x if condition else y

the equivalent formed with boolean operators was:

a = condition and x or z                      # don't do this!

which while the meaning is derivable based on a full understanding of Python and and or evaluation, is not nearly as readable as the ternary conditional, and is best avoided altogether.

Conclusion

Using Boolean expressions for assignment must be done carefully. Definitely never use and for assignment, which is confusing enough to be quite error-prone. Style mavens will find use of or for assignments less preferable (than the more verbose ternary, if condition else), but I have found that it is so common in the professional Python community that it could be considered idiomatic.

If you choose to use it, do so cautiously with the understanding that the final element, if reached, will always be returned regardless of its evaluation, so that final element should probably be a literal, so that you know you have a good default fallback for your variable.