问题 Python相当于C#6中引入的空条件运算符


Python中是否有与C#相当的# 零条件运算符

System.Text.StringBuilder sb = null;
string s = sb?.ToString(); // No error

10712
2017-07-09 20:03


起源



答案:


怎么样:

s = sb and sb.ToString()

如果sb是Falsy,则短路布尔值停止,否则返回下一个表达式。

顺便说一下,如果得到无则很重要......

sb = ""

#we wont proceed to sb.toString, but the OR will return None here...
s = (sb or None) and sb.toString()

print s, type(s)

输出:

None <type 'NoneType'>

8
2017-07-10 04:26



谢谢,如果没有其他的话,我会在一段时间后接受这个答案。 - Andrey Grachev
如果不是sb,此解决方案会产生意外结果 None 但是一个假的。例如,如果 sb="" 然后这给了 "", 代替 "".method() - Tanmay


答案:


怎么样:

s = sb and sb.ToString()

如果sb是Falsy,则短路布尔值停止,否则返回下一个表达式。

顺便说一下,如果得到无则很重要......

sb = ""

#we wont proceed to sb.toString, but the OR will return None here...
s = (sb or None) and sb.toString()

print s, type(s)

输出:

None <type 'NoneType'>

8
2017-07-10 04:26



谢谢,如果没有其他的话,我会在一段时间后接受这个答案。 - Andrey Grachev
如果不是sb,此解决方案会产生意外结果 None 但是一个假的。例如,如果 sb="" 然后这给了 "", 代替 "".method() - Tanmay


那么,最简​​单的解决方案是:

result = None if obj is None else obj.method()

但是如果你想要具有与C#的Null条件运算符相同的线程安全性的完全等价,那么它将是:

obj = 'hello'
temp = obj
result = None if temp is None else temp.split()

权衡的是代码不是很漂亮;还有一个额外的名字 temp 被添加到命名空间。

另一种方式是:

def getattr_safe(obj, attr):
    return None if obj is None else getattr(obj,attr)

obj = 'hello'
result = getattr_safe(obj,'split')()

在这里,权衡是调用开销的函数,但更清晰的代码,特别是如果你多次使用它。


5
2017-07-09 20:27



谢谢,我知道这个方法,但希望有一个更短的方法来做到这一点。 - Andrey Grachev
不幸的是,没有。但是,如果您不介意开销,可以将其包装在一个函数中。 - Tanmay
我认为这个答案中的例子需要一些修改,因为它需要额外的上下文 - Python没有内置的 ToString 方法;为什么我们需要额外的步骤 temp=sb? - Andrey Grachev
我用了 ToString 只是为了与问题保持一致;我会编辑它以使其变得更加明智。额外的一步 temp=sb 是必需的,因为这是Null条件运算符的工作方式。如果我们这样做 None if sb is None else sb.ToString(),它不是线程安全的,因为在两个引用期间可以更改sb引用。 - Tanmay
@Tanmay Python中的多线程并不常见,值得关注,因为直到Python 2“线程”在隔离进程中运行,并且现代python多线程是围绕未来构建的,它们再次没有共享状态。在大多数Python代码中,方法的线程安全性根本不是问题。 - Asad Saeeduddin


我用你需要的行为编写了这个函数。这种优势超链接 and 就长链而言,它更容易编写。抬头这不适用于对象键,只有属性。

def null_conditional(start, *chain):
    current = start
    for c in chain:
        current = getattr(current, c, None)
        if current is None:
            break
    return current

这是我运行的一些测试,所以你可以看到它是如何工作的

class A(object):
    b = None
    def __init__(self, v):
        self.b = v

class B(object):
    c = None
    def __init__(self, v):
        self.c = v    

a_1 = A(B(2))
a_2 = A(None)
print(null_conditional(a_1, 'b', 'c')) # 2
print(null_conditional(a_1, 'b', 'd')) # None
print(null_conditional(a_2, 'b', 'c')) # None
print(null_conditional(None, 'b')) # None
print(null_conditional(None, None)) # TypeError: attribute name must be string

1
2018-04-28 14:27