是否有C#null-coalescing运算符的Python等价物?

时间:2011-02-12 15:04:49

标签: python null-coalescing-operator

在C#中有null-coalescing operator(写为??),允许在分配期间进行简单(空)检查:

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

是否有python等价物?

我知道我能做到:

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

但是有更短的方式(我不需要重复s)吗?

11 个答案:

答案 0 :(得分:333)

other = s or "some default value"

好的,必须澄清or运算符的工作原理。它是一个布尔运算符,因此它在布尔上下文中工作。如果值不是布尔值,则为操作符的目的将它们转换为布尔值。

请注意,or运算符不会仅返回TrueFalse。相反,如果第一个操作数的计算结果为true,则返回第一个操作数;如果第一个操作数的计算结果为false,则返回第二个操作数。

在这种情况下,表达式x or y如果是x则返回True,或者在转换为布尔值时求值为true。否则,它返回y。对于大多数情况,这将用于C♯的null-coalescing运算符的相同目的,但请记住:

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

如果您使用变量s来保存某个类的实例或None的引用(只要您的类没有定义成员__nonzero__()和{ {1}}),使用与null-coalescing运算符相同的语义是安全的。

事实上,拥有Python的这种副作用甚至可能是有用的。由于您知道哪些值的计算结果为false,因此您可以使用它来触发默认值而不使用__len__()(例如,错误对象)。

在某些语言中,此行为称为Elvis operator

答案 1 :(得分:49)

严格,

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

否则s = False将成为“默认值”,这可能不是预期的。

如果您想缩短时间,请尝试

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

other = notNone(s, "default value")

答案 2 :(得分:34)

这是一个函数,它将返回第一个不是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()可能会不必要地迭代所有参数,即使第一个参数不是None,所以你也可以使用这个版本:

def coalesce(*arg):
  for el in arg:
    if el is not None:
      return el
  return None

答案 3 :(得分:6)

如果您需要嵌套多个null合并操作,例如:

#!/bin/bash -xe sudo yum install -y python36 python36-devel postgresql-devel unixODBC-devel # For pyodbc, psycopg2 virtualenv --system-site-packages /home/hadoop/workspace -p /usr/bin/python3.6 # Install virualenv source /home/hadoop/workspace/bin/activate aws s3 cp s3://<bucket>/requirements.txt /home/hadoop/ # Keep your required pip freeze info (tensorflow, etc...) on s3 pip install -r /home/hadoop/requirements.txt # Install your packages # Run your scripts during main execcution using /home/hadoop/workspace/bin/python3

使用model?.data()?.first()可以轻松解决这个问题。也无法通过or来解决,.get()需要一个字典类型或类似的类型(并且不能嵌套),或者getattr()会在NoneType没有属性时抛出异常。

考虑在语言中添加空合并的相关点是PEP 505,与文档相关的讨论在python-ideas线程中。

答案 4 :(得分:2)

除了Juliano关于&#34;或&#34;的行为的答案: 它&#34;快速&#34;

>>> 1 or 5/0
1

因此,有时它可能是

之类的有用捷径
object = getCachedVersion() or getFromDB()

答案 5 :(得分:2)

我知道这是答案,但是当您处理对象时,还有另一种选择。

如果您的对象可能是:

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

您可以使用:

obj.get(property_name, value_if_null)

赞:

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

通过添加{}作为默认值,如果缺少“名称”,则返回一个空对象并将其传递到下一个get。这类似于C#中的null安全导航,就像obj?.name?.first

答案 6 :(得分:1)

除了@Bothwells答案(我更喜欢单个值)之外,为了对函数返回值进行空值检查,您可以使用新的walrus-operator(自python3.8起):

def test():
    return

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

因此,test函数不需要进行两次评估(如a = 2 if test() is None else test()中一样)

答案 7 :(得分:0)

关于@Hugh Bothwell,@ mortehu和@glglgl的答案。

设置测试数据集

import random

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

定义实现

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)

启用测试功能

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

在Mac i7 @ 2.7Ghz上使用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

很显然,not_none函数可以正确回答OP的问题并处理“虚假”问题。它也是最快,最容易阅读的。如果将逻辑应用于很多地方,显然这是最好的方法。

如果您有一个问题想要在迭代中找到第一个非空值,那么@mortehu的响应就是解决方法。但这是对 不同问题 的一种解决方案,尽管它可以部分解决这种情况。它不能采用可迭代的AND默认值。最后一个参数将是返回的默认值,但是在那种情况下,您将不会传递可迭代的值,而且也不清楚最后一个参数是否是value的默认值。

您可以在下面进行操作,但对于单一值用例,我仍将使用not_null

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

答案 8 :(得分:0)

对于像我这样偶然发现此问题的可行解决方案的人,当变量可能未定义时,我得到的最接近的是:

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')

请注意,在检查全局变量时需要一个字符串,但之后在检查值时将使用实际变量。

有关变量存在的更多信息: How do I check if a variable exists?

答案 9 :(得分:-2)

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

如果您在词典中找不到名称,它将返回default_value, 如果名称存在,则它将使用1添加任何现有值。

希望这会有所帮助

答案 10 :(得分:-7)

下面的两个函数我发现在处理许多变量测试用例时非常有用。

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