ChatGPT解决这个技术问题 Extra ChatGPT

是否有与 C# null-coalescing 运算符等效的 Python?

在 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)?

?? 运算符建议为 PEP 505
..但从来没有把它变成语言。
Python 的最大优势之一是它的表现力。遗憾的是 Python 没有提供 None 合并运算符。三元替代方案更加冗长,并且 or 解决方案根本不一样(因为它处理所有“虚假”值,而不仅仅是 None - 这并不总是您想要的,而且更容易出错) .

C
Cory Klein
other = s or "some default value"

好的,必须弄清楚 or 运算符是如何工作的。它是一个布尔运算符,因此它在布尔上下文中工作。如果这些值不是布尔值,则将它们转换为布尔值以供运算符使用。

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

在这种情况下,如果表达式 x or yTrue,则返回 x,或者在转换为布尔值时计算结果为 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__()),那么使用它是安全的与 null-coalescing 运算符的语义相同。

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

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


除了常量 False 之外,数字 0、None 和空容器(包括字符串)被认为是错误的。大多数其他一切都被认为是真实的。我会说这里的主要危险是你会得到一个真实但非字符串的值,但这在某些程序中不会成为问题。
如果 s 为 None 或 False,则使用此 other 将获得默认值,这可能不是我们想要的。
也有许多由此引起的晦涩的错误。例如,在 Python 3.5 之前,datetime.time(0) 也是虚假的!
这是不好的。我建议添加有关其陷阱的通知。并建议不要使用它。
⚠️ 这是一个反模式。使用 other = "some default value" if s is None else s。另请参阅:stackoverflow.com/questions/13710631/…
M
MarredCheese

严格来说,

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

这应该是答案
我想知道如果我的情况是other = s.name if s is not None else "default value"怎么办,还有像notNone这样更短的方法吗?
M
MarredCheese

这是一个函数,它将返回不是 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)

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

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

def coalesce(*arg): return next((a for a in arg if a is not None), None) 与您在一行中的最后一个示例相同。
我知道人们想解释 if else sytnax 等,但 coalesce 采用任意参数列表,所以这应该是最佳答案。
glglgl 有最好的答案。我在一个大型测试数组上使用了 timeit,reduce 实现慢得令人无法接受,多行 for/if 版本最快,下一个实现稍微落后。考虑到简单性和简洁性,下一个版本总体上是最好的。
@glglgl 有有趣的片段。不幸的是,因为 Python 没有 pass-by-name,所以像这样的合并不是短路的;在代码运行之前评估所有参数。
n
nurettin

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

model?.data()?.first()

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

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


model?.data()?.first() 中没有空值合并运算符。这个答案与问题无关。
@Travis 你读过那条线了吗?
^ 一开始它也让我失望了——虽然如果我是迂腐的,那在其他语言中也不是空值合并。它是 C# 的 null-conditional operator 或 typescripts optional chaining
@Chazt3n 好的,已修复
C
Cyberwiz

我意识到这已得到解答,但是当您处理类似 dict 的对象时,还有另一种选择。

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

{
   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


并非所有对象都有 .get,这仅适用于 dict-like 对象
我正在提交一个回答编辑以涵盖 getattr()
dict 上的 get 如果值为 None 则不使用默认参数,但如果值不存在则使用默认参数,因为键不在 dict 中。作为结果,{'a': None}.get('a', 'I do not want None') 仍会为您提供 None
H
Henhuy

除了@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()


O
Orca

除了朱利亚诺关于“或”行为的回答:它是“快”

>>> 1 or 5/0
1

所以有时它可能是一个有用的捷径,比如

object = getCachedVersion() or getFromDB()

您正在寻找的术语是“短路”。
d
debo

关于@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 的响应就是要走的路。但它解决了与 OP 不同的问题,尽管它可以部分处理这种情况。它不能采用可迭代和默认值。最后一个参数将是返回的默认值,但是在这种情况下您不会传入一个可迭代的,并且最后一个参数是默认值也不是明确的。

然后您可以在下面执行,但我仍将 not_null 用于单值用例。

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

I
Itaca

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

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?


(variablename or False) == Truevariablename == True 相同
A
Angelo
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。

希望这可以帮助


您好,欢迎来到 Stack Overflow。您的答案添加了哪些现有答案尚未涵盖的新信息?例如,请参阅@Craig 的答案
M
Mike Stabile

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

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

这种东西添加了一大堆稍微不同的术语(例如,“null”和“nz”在 Python 的上下文中都没有任何意义),从其他语言导入,加上变体(严格或非严格!)。这只会增加混乱。明确的“无”检查是您应该使用的。另外,当您使用函数调用时,您不会受益于操作员可以执行的任何快捷语义。