490

In C# there's a null-coalescing operator (written as ??) that allows for easy (short) null checking during assignment:

string s = null;
var other = s ?? "some default value";

Is there a python equivalent?

I know that I can do:

s = None
other = s if s else "some default value"

But is there an even shorter way (where I don't need to repeat s)?

Klaus Byskov Pedersen
  • 117,245
  • 29
  • 183
  • 222
  • 35
    The `??` operator is proposed as [PEP 505](https://www.python.org/dev/peps/pep-0505/). – 200_success Oct 20 '16 at 18:39
  • 35
    ..but never made it into the language. – MEMark Dec 11 '20 at 07:37
  • 6
    One of the biggest strengths of Python is its expressiveness. It's a pity Python doesn't provide a `None`-coalescing operator. The ternary alternative is way more verbose and the `or` solution is simply not the same (as it handles all "falsy" values, not just `None` - that's not always what you'd want and can be more error-prone). – at54321 Jul 21 '21 at 10:08

12 Answers12

656
other = s or "some default value"

Ok, it must be clarified how the or operator works. It is a boolean operator, so it works in a boolean context. If the values are not boolean, they are converted to boolean for the purposes of the operator.

Note that the or operator does not return only True or False. Instead, it returns the first operand if the first operand evaluates to true, and it returns the second operand if the first operand evaluates to false.

In this case, the expression x or y returns x if it is True or evaluates to true when converted to boolean. Otherwise, it returns y. For most cases, this will serve for the very same purpose of C♯'s null-coalescing operator, but keep in mind:

42    or "something"    # returns 42
0     or "something"    # returns "something"
None  or "something"    # returns "something"
False or "something"    # returns "something"
""    or "something"    # returns "something"

If you use your variable s to hold something that is either a reference to the instance of a class or None (as long as your class does not define members __nonzero__() and __len__()), it is secure to use the same semantics as the null-coalescing operator.

In fact, it may even be useful to have this side-effect of Python. Since you know what values evaluates to false, you can use this to trigger the default value without using None specifically (an error object, for example).

In some languages this behavior is referred to as the Elvis operator.

Cory Klein
  • 51,188
  • 43
  • 183
  • 243
Juliano
  • 39,173
  • 13
  • 67
  • 73
  • 4
    Will this work the same? I mean, will it break if `s` is a valid value but isn't truthy? (I don't know Python, so i'm not sure whether the concept of 'truthy' applies.) – cHao Feb 12 '11 at 15:33
  • 19
    The number 0, `None`, and empty containers (including strings) are considered false, in addition to the constant `False`. Most everything else is considered true. I would say that the main danger here would be that you would get a true but non-string value, but that won't be an issue in some programs. – kindall Feb 12 '11 at 15:52
  • 45
    Using this _other_ will get the default value if s is None **or False**, which may not be what is wanted. – pafcu Feb 12 '11 at 16:15
  • This technique works even works with default values that evaluate to `False`, e.g. `{}`: `data = None;` `data = data or {};` `data` is now set to `{}`. – chris Aug 01 '14 at 20:34
  • 13
    There are many obscure bugs caused by this as well. For example prior to Python 3.5, `datetime.time(0)` was also falsy! – Antti Haapala -- Слава Україні Jan 20 '16 at 00:06
  • 1
    `'' or None` would return None - skipping the first `False` value. – VISQL Jan 12 '17 at 03:19
  • This is actually my favorite answer I've ever encountered on SE! Note that if you `or` 2 (or n) different falsey values, you get the last one as the result. i.e. `'' or None` evaluates to `None` and `None or ''` evaluates to `''`. (So it's not symmetric for falsey values. But it should be symmetric for truthy values, except perhaps obscure corner cases.) – Apollys supports Monica Apr 21 '17 at 18:05
  • 60
    **This is bad.** I recommend adding a notice about its pitfalls. And recommending *not* to use it. – Mateen Ulhaq Jul 01 '18 at 04:57
  • 4
    Looks like the answer is missing the point of the original question. The value of ?? comes in when you do a??.calculate(). It works like the maybe monad in Haskell. I am no python expert, but still dont think the or operator solves the fundamental issue – user1559897 Jul 20 '18 at 15:38
  • @MateenUlhaq : You have the rep, why not edit the answer to add this? – Peter K. Oct 17 '18 at 13:43
  • 2
    @PeterK The edit would "conflict with the author's intent". – Mateen Ulhaq Oct 17 '18 at 15:44
  • @MateenUlhaq OK. Your comment seems superfluous in that case. – Peter K. Oct 17 '18 at 16:03
  • 4
    Please do not do this. This answer is not equivalent to the C# null-coalescing operator, since the C# `??` operator responds specifically to whether the first operand is `None`/`null` and the Python `or` responds to anything that resolves to `False` when treated as a Boolean. That "resolves to `False`" has many subtle cases, and will likely introduce hard-to-find bugs in the future. Hugh Bothwell's answer is much more obviously correct. – Mashmagar Jan 03 '19 at 20:03
  • Can I apply this to command line args. Exmaple: arg = argv[1] or 1. – variable Oct 11 '19 at 03:07
  • So they are not exactly the same, because in C#, `((bool?) false ?? true)` evaluates to False, but in Python, `False or True` evaluates to True – nonopolarity Mar 16 '20 at 10:31
  • `Consider x()?.y()?.z()` – nurettin Apr 24 '20 at 11:08
  • 42
    ⚠️ This is an **antipattern**. Use `other = "some default value" if s is None else s`. See also: https://stackoverflow.com/questions/13710631/is-there-shorthand-for-returning-a-default-value-if-none-in-python/13710674 – Niko Föhr Jul 13 '20 at 14:16
  • 3
    Not a good solution. Remember that *Explicit is better than implicit* – yuvalm2 Aug 26 '20 at 11:05
  • 1
    This is a terrible answer, and it got cited on the Wikipedia article on Null coalescing operator. The correct answer is "

    No.


    However ...(and what you wrote here)".
    – zamarov Sep 25 '20 at 19:33
  • Undesirable behavior if asker only wants to test for `None` this overrides anything falsy `0 or "default"` will default. – Andrew Jan 18 '21 at 19:03
  • @np8 What if `s` is an expression? – Dávid Horváth Apr 26 '21 at 06:52
  • @yuvalm2 Are you really talking about type system? – Kiruahxh Feb 07 '22 at 17:05
  • 1
    How does such an incorrect and awful answer have so many upvotes? – Mark K Cowan Feb 17 '22 at 18:29
  • Mark - because Python doesn't have a coalesce operator. I'm kinda surprised at the vitriol considering Python seems to want verbosity in an environment where people want conciseness. I'm about to use the OR method in my code - don't hate me bro. – Gerard ONeill Aug 31 '22 at 04:56
  • 1
    What to do about np.nan or 'test'? – Anatoly Alekseev May 15 '23 at 06:34
  • What if the default value is falsy e.g. `""`? – Toivo Säwén Sep 02 '23 at 16:14
142

Strictly,

other = s if s is not None else "default value"

Otherwise, s = False will become "default value", which may not be what was intended.

If you want to make this shorter, try:

def notNone(s,d):
    if s is None:
        return d
    else:
        return s

other = notNone(s, "default value")
MarredCheese
  • 17,541
  • 8
  • 92
  • 91
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
63

Here's a function that will return the first argument that isn't None:

def coalesce(*arg):
  return reduce(lambda x, y: x if x is not None else y, arg)

# Prints "banana"
print coalesce(None, "banana", "phone", None)

reduce() might needlessly iterate over all the arguments even if the first argument is not None, so you can also use this version:

def coalesce(*arg):
  for el in arg:
    if el is not None:
      return el
  return None
MarredCheese
  • 17,541
  • 8
  • 92
  • 91
mortehu
  • 3,470
  • 2
  • 19
  • 14
  • 36
    `def coalesce(*arg): return next((a for a in arg if a is not None), None)` does the same as your last example in one line. – glglgl Jun 24 '14 at 12:44
  • 7
    I get that people want to explain if else sytnax etc, but coalesce takes an arbitrary argument list so this should really be the top answer. – Eric Twilegar Jul 03 '14 at 05:02
  • 3
    glglgl has the best answer. I used timeit on a large test array and the reduce implementation is unacceptably slow, the multi-line for/if version is fastest, and the next implementation is very slightly behind. The next version is the best overall when considering simplicity and conciseness. – clay Jun 09 '15 at 20:57
  • 6
    @glglgl has interesting snippet. Unfortunately because Python does not have pass-by-name, coalesce like this is not short-circuiting; all of the arguments are evaluated before the code runs. – user1338062 Sep 17 '18 at 09:47
  • This works for me, but as of Python 3 (Python 2 is now EOL), `from functools import reduce` is required. Also, `print` is now a function that returns `None`, and not a statement. – Keyacom Aug 27 '22 at 09:30
28

In case you need to chain more than one null-conditional operation such as:

model?.data()?.first()

This is not a problem easily solved with or. It also cannot be solved with .get() which requires a dictionary type or similar (and cannot be nested anyway) or getattr() which will throw an exception when NoneType doesn't have the attribute.

The relevant PEP considering adding null coalescing to the language is PEP 505 and the discussion relevant to the document is in the python-ideas thread.

nurettin
  • 11,090
  • 5
  • 65
  • 85
  • 2
    There's no null-coalescing operator in `model?.data()?.first()`. This answer isn't relevant to the question. – Travis Mar 28 '22 at 02:19
  • 13
    @Travis did you read past that line? – nurettin Mar 28 '22 at 05:38
  • 2
    ^ it threw me off at first too - though if I'm being pedantic, that's not null coalescing in other languages either. It's C#'s [null-conditional operator](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-) or typescripts [optional chaining](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optional-chaining) – Chazt3n Jun 24 '22 at 18:52
  • 1
    @Chazt3n okay, fixed – nurettin Jun 27 '22 at 08:07
  • it's good it's here because I had no idea what that operator was called – SparK May 16 '23 at 17:11
18

I realize this is answered, but there is another option when you're dealing with dict-like objects.

If you have an object that might be:

{
   name: {
      first: "John",
      last: "Doe"
   }
}

You can use:

obj.get(property_name, value_if_null)

Like:

obj.get("name", {}).get("first", "Name is missing") 

By adding {} as the default value, if "name" is missing, an empty object is returned and passed through to the next get. This is similar to null-safe-navigation in C#, which would be like obj?.name?.first.

Cyberwiz
  • 11,027
  • 3
  • 20
  • 40
Craig
  • 666
  • 7
  • 17
  • 2
    Not all objects have `.get`, this only works for dict-like objects – Tim Diels Feb 22 '19 at 16:18
  • 1
    I'm submitting an answer edit to cover `getattr()` also. – dgw Aug 20 '19 at 20:35
  • 3
    `get` on dict does not use the default parameter if the value is None but uses the default parameter if the value does not exist because the key is not in the dict. `{'a': None}.get('a', 'I do not want None')` will still give you `None` as a result. – Patrick Mevzek Jan 29 '20 at 22:33
11

Addionally to @Bothwells answer (which I prefer) for single values, in order to null-checking assingment of function return values, you can use new walrus-operator (since python3.8):

def test():
    return

a = 2 if (x:= test()) is None else x

Thus, test function does not need to be evaluated two times (as in a = 2 if test() is None else test())

Henhuy
  • 1,034
  • 1
  • 13
  • 23
  • This is the cleanest way of achieving null-coalescing in my opinion. I use it for functions that can return the object or None, and want to access it on the same line; ie: `email = user.email if (user := get_user_fn()) else None` – Polosky Mar 13 '23 at 19:26
2

In addition to Juliano's answer about behavior of "or": it's "fast"

>>> 1 or 5/0
1

So sometimes it's might be a useful shortcut for things like

object = getCachedVersion() or getFromDB()
Orca
  • 57
  • 4
0

Regarding answers by @Hugh Bothwell, @mortehu and @glglgl.

Setup Dataset for testing

import random

dataset = [random.randint(0,15) if random.random() > .6 else None for i in range(1000)]

Define implementations

def not_none(x, y=None):
    if x is None:
        return y
    return x

def coalesce1(*arg):
  return reduce(lambda x, y: x if x is not None else y, arg)

def coalesce2(*args):
    return next((i for i in args if i is not None), None)

Make test function

def test_func(dataset, func):
    default = 1
    for i in dataset:
        func(i, default)

Results on mac i7 @2.7Ghz using python 2.7

>>> %timeit test_func(dataset, not_none)
1000 loops, best of 3: 224 µs per loop

>>> %timeit test_func(dataset, coalesce1)
1000 loops, best of 3: 471 µs per loop

>>> %timeit test_func(dataset, coalesce2)
1000 loops, best of 3: 782 µs per loop

Clearly the not_none function answers the OP's question correctly and handles the "falsy" problem. It is also the fastest and easiest to read. If applying the logic in many places, it is clearly the best way to go.

If you have a problem where you want to find the 1st non-null value in a iterable, then @mortehu's response is the way to go. But it is a solution to a different problem than OP, although it can partially handle that case. It cannot take an iterable AND a default value. The last argument would be the default value returned, but then you wouldn't be passing in an iterable in that case as well as it isn't explicit that the last argument is a default to value.

You could then do below, but I'd still use not_null for the single value use case.

def coalesce(*args, **kwargs):
    default = kwargs.get('default')
    return next((a for a in arg if a is not None), default)
debo
  • 319
  • 2
  • 8
0

to take care of possible exceptions:

def default_val(expr, default=None):
    try:
        tmp = expr()
    except Exception:
        tmp = default
    return tmp

use it like that:

default_val(lambda: some['complex'].expression('with', 'possible')['exceptions'], '')
-2

For those like me that stumbled here looking for a viable solution to this issue, when the variable might be undefined, the closest i got is:

if 'variablename' in globals() and ((variablename or False) == True):
  print('variable exists and it\'s true')
else:
  print('variable doesn\'t exist, or it\'s false')

Note that a string is needed when checking in globals, but afterwards the actual variable is used when checking for value.

More on variable existence: How do I check if a variable exists?

Itaca
  • 39
  • 6
-3
Python has a get function that its very useful to return a value of an existent key, if the key exist;
if not it will return a default value.

def main():
    names = ['Jack','Maria','Betsy','James','Jack']
    names_repeated = dict()
    default_value = 0

    for find_name in names:
        names_repeated[find_name] = names_repeated.get(find_name, default_value) + 1

if you cannot find the name inside the dictionary, it will return the default_value, if the name exist then it will add any existing value with 1.

hope this can help

Angelo
  • 1
  • 2
  • 1
    Hi, welcome to Stack Overflow. What new information does your answer add which wasn't already covered by existing answers? See @Craig's answer for example – Gricey Oct 18 '19 at 00:31
-5

The two functions below I have found to be very useful when dealing with many variable testing cases.

def nz(value, none_value, strict=True):
    ''' This function is named after an old VBA function. It returns a default
        value if the passed in value is None. If strict is False it will
        treat an empty string as None as well.

        example:
        x = None
        nz(x,"hello")
        --> "hello"
        nz(x,"")
        --> ""
        y = ""   
        nz(y,"hello")
        --> ""
        nz(y,"hello", False)
        --> "hello" '''

    if value is None and strict:
        return_val = none_value
    elif strict and value is not None:
        return_val = value
    elif not strict and not is_not_null(value):
        return_val = none_value
    else:
        return_val = value
    return return_val 

def is_not_null(value):
    ''' test for None and empty string '''
    return value is not None and len(str(value)) > 0
  • 6
    This kind of things adds a whole bunch of slightly different terminology (e.g. "null" and "nz" neither of which mean anything in the context of Python), imported from other languages, plus with variants (strict or non-strict!). This only adds confusion. Explicit "is None" checks are what you should be using. Plus you don't get the benefit of any short-cutting semantics that operators can do when you use a function call. – spookylukey Feb 07 '17 at 10:35