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

Kla*_*sen 258 python null-coalescing-operator

在C#中有一个null-coalescing运算符(写为??),允许在赋值期间进行简单(短)空检查:

string s = null;
var other = s ?? "some default value";
Run Code Online (Sandbox Code Playgroud)

是否有python等价物?

我知道我能做到:

s = None
other = s if s else "some default value"
Run Code Online (Sandbox Code Playgroud)

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

Jul*_*ano 372

other = s or "some default value"
Run Code Online (Sandbox Code Playgroud)

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

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

在这种情况下,表达式x or y返回,x如果是,True或者在转换为boolean时求值为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"
Run Code Online (Sandbox Code Playgroud)

如果你使用你的变量s来保存一个对类实例的引用或者None(只要你的类没有定义成员__nonzero__()__len__()),那么使用与null-coalescing运算符相同的语义是安全的.

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

在某些语言中,此行为称为Elvis运算符.

  • 如果s为None**或False**,则使用此_other_将获得默认值,这可能不是所需的. (22认同)
  • ⚠️这是一个**反模式**。如果 s 是 None else s,则使用“other =“某个默认值””。另请参阅:/sf/ask/959744201/ (14认同)
  • **这很糟糕.**我建议添加关于其陷阱的通知.并建议*不*使用它. (13认同)
  • 除了常量"False"之外,数字0,"无"和空容器(包括字符串)被认为是假的.其他大多数都被认为是真的.我会说这里的主要危险是你会获得一个真正但非字符串的值,但这在某些程序中不会成为问题. (9认同)
  • 这也引起了许多模糊的错误.例如在Python 3.5之前,`datetime.time(0)`也是假的! (6认同)
  • 看起来答案没有抓住原来问题的要点。的价值 ??当你执行 ??.calculate() 时出现。它的工作原理类似于 Haskell 中的 Maybe monad。我不是Python专家,但仍然不认为or运算符解决了根本问题 (4认同)
  • 这会是一样的吗?我的意思是,如果`s`是一个有效的值而不是真的,它会破裂吗?(我不知道Python,所以我不确定'truthy'的概念是否适用.) (3认同)
  • 这不是一个好的解决方案。请记住*显式优于隐式* (3认同)
  • @PeterK 编辑将“与作者的意图相冲突”。 (2认同)
  • 请不要这样做。这个答案不等同于 C# 空合并运算符,因为 C# `??` 运算符专门响应第一个操作数是否为 `None`/`null`,而 Python`or` 响应任何解析为 `False 的内容` 当被视为布尔值时。“解析为`False`”有很多微妙的情况,将来可能会引入难以发现的错误。Hugh Bothwell 的回答显然是正确的。 (2认同)

Hug*_*ell 54

严格,

other = s if s is not None else "default value"
Run Code Online (Sandbox Code Playgroud)

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

如果你想缩短它,试试吧

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

other = notNone(s, "default value")
Run Code Online (Sandbox Code Playgroud)

  • 这应该是答案 (10认同)
  • 这应该是答案,Python 可以考虑添加这样一个方便的运算符 (5认同)

mor*_*ehu 39

这是一个函数,它将返回第一个不是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)
Run Code Online (Sandbox Code Playgroud)

即使第一个参数不是None,reduce()也可能会不必要地遍历所有参数,因此您也可以使用此版本:

def coalesce(*arg):
  for el in arg:
    if el is not None:
      return el
  return None
Run Code Online (Sandbox Code Playgroud)

  • `def coalesce(*arg):返回next((如果a不是None,则a表示arg),None)`与一行中的最后一个例子相同. (22认同)
  • 我知道人们想解释是否还有 sytnax 等,但是 coalesce 需要一个任意的参数列表,所以这应该是最好的答案。 (2认同)
  • glglgl有最好的答案.我在一个大型测试阵列上使用了timeit,并且reduce实现速度慢得令人无法接受,for/if版本的多线路速度最快,下一个实现略微落后.考虑到简洁性和简洁性,下一个版本是最好的. (2认同)
  • @glglgl有有趣的摘要。不幸的是,由于Python没有名字传递,像这样的合并不会造成短路。在代码运行之前,将评估所有参数。 (2认同)

Hen*_*huy 11

除了@Bothwells答案(我更喜欢)对于单个值之外,为了对函数返回值进行空检查分配,您可以使用新的海象运算符(自python3.8起):

def test():
    return

a = 2 if (x:= test()) is None else x
Run Code Online (Sandbox Code Playgroud)

因此,test函数不需要计算两次(如a = 2 if test() is None else test()


Cra*_*aig 10

我意识到这已经得到了回答,但是在处理对象时还有另一种选择。

如果您的对象可能是:

{
   name: {
      first: "John",
      last: "Doe"
   }
}
Run Code Online (Sandbox Code Playgroud)

您可以使用:

obj.get(property_name, value_if_null)
Run Code Online (Sandbox Code Playgroud)

喜欢:

obj.get("name", {}).get("first", "Name is missing") 
Run Code Online (Sandbox Code Playgroud)

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

  • 如果值为 None,则 dict 上的 `get` 不使用默认参数,但如果该值不存在,则使用默认参数,因为键不在字典中。`{'a': None}.get('a', 'I do not Want None')` 仍然会给你 `None` 结果。 (3认同)
  • 并非所有对象都有 `.get`,这只适用于类似字典的对象 (2认同)

nur*_*tin 9

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

model?.data()?.first()

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

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

  • @Travis 你读过那行吗? (23认同)
  • `model?.data()?.first()` 中没有空合并运算符。这个答案与问题无关。 (2认同)
  • ^ 一开始它也让我感到困惑——尽管如果我很迂腐的话,这在其他语言中也不是空合并。它是 C# 的 [null-conditional 运算符](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-) 或typescripts [可选链接](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#optical-chaining) (2认同)