Python中是否存在与c#空合并运算符等效的操作符?

在c#中,有一个空合并操作符(写为??),允许在赋值时简单(短)检查null:

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

python中有等效的吗?

我知道我能做到:

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

但是否有更短的方法(在那里我不需要重复s)?

192374 次浏览
other = s or "some default value"

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

注意,or操作符不仅返回TrueFalse。相反,如果第一个操作数为真,它返回第一个操作数,如果第一个操作数为假,它返回第二个操作数。

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

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__()__len__()),使用与空合并操作符相同的语义是安全的。

事实上,Python的这种副作用甚至可能是有用的。因为你知道哪些值的值为false,所以你可以使用它来触发默认值,而不需要特别使用None(例如,一个错误对象)。

在某些语言中,此行为被称为猫王运营商

严格来说,

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

否则,s = False将变成"default value",这可能不是预期的结果。

如果你想让这段话更短,试试:

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


other = notNone(s, "default value")

下面是一个函数,返回的第一个参数不是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

除了Juliano关于“或”行为的回答: 这是“快速”< / p >

>>> 1 or 5/0
1

有时候这可能是一个有用的快捷方式

object = getCachedVersion() or getFromDB()

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

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

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

如果你有一个对象可能是:

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

你可以使用:

obj.get(property_name, value_if_null)

如:

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

通过添加{}作为默认值,如果"name"则返回一个空对象并传递给下一个get。这类似于c#中的null-safe-navigation,类似于obj?.name?.first

关于@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)

使用python 2.7在mac i7 @2.7Ghz上的结果

>>> %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的响应就是正确的方法。但它是< em > < / em >不同的问题 than OP的解决方案,尽管它可以部分处理这种情况。它不能接受可迭代对象和默认值。最后一个参数将是返回的默认值,但在这种情况下,你不会传入一个可迭代对象,而且最后一个参数是默认值也不是显式的。

然后你可以在下面做,但我仍然会使用not_null作为单值用例。

def coalesce(*args, **kwargs):
default = kwargs.get('default')
return next((a for a in arg if a is not None), default)
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

希望这能有所帮助

对于那些像我一样跌跌撞撞地在这里寻找一个可行的解决方案,当变量可能是未定义的,我得到的最接近的是:

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

请注意,签入全局变量时需要字符串,但之后在检查value时使用实际变量。

关于变量存在的更多信息: 如何检查变量是否存在? < / p >

除了单个值的@Bothwells answer(我更喜欢这个),为了检查函数返回值的空值分配,你可以使用new 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()那样)。

如果你需要链接多个空条件操作,例如:

model?.data()?.first()

这不是一个容易用or解决的问题。它也不能用.get()来解决,它需要一个字典类型或类似的(无论如何都不能嵌套)或getattr()来解决,当NoneType没有属性时,getattr()会抛出异常。

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

处理可能的异常:

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

像这样使用它:

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