在 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。
None
合并运算符。三元替代方案更加冗长,并且 or
解决方案根本不一样(因为它处理所有“虚假”值,而不仅仅是 None
- 这并不总是您想要的,而且更容易出错) .
other = s or "some default value"
好的,必须弄清楚 or
运算符是如何工作的。它是一个布尔运算符,因此它在布尔上下文中工作。如果这些值不是布尔值,则将它们转换为布尔值以供运算符使用。
请注意,or
运算符不仅返回 True
或 False
。相反,如果第一个操作数的计算结果为真,则返回第一个操作数,如果第一个操作数的计算结果为假,则返回第二个操作数。
在这种情况下,如果表达式 x or y
为 True
,则返回 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。
严格来说,
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
这样更短的方法吗?
这是一个函数,它将返回不是 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)
即使第一个参数不是 None
,reduce()
也可能会不必要地迭代所有参数,因此您也可以使用此版本:
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)
与您在一行中的最后一个示例相同。
如果您需要链接多个空条件操作,例如:
model?.data()?.first()
这不是使用 or
可以轻松解决的问题。它也不能用 .get()
解决,它需要字典类型或类似类型(无论如何都不能嵌套)或 getattr()
当 NoneType 没有属性时会抛出异常。
考虑向语言添加空值合并的相关 PEP 是 PEP 505,与文档相关的讨论在 python-ideas 线程中。
model?.data()?.first()
中没有空值合并运算符。这个答案与问题无关。
我意识到这已得到解答,但是当您处理类似 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()
。
get
如果值为 None 则不使用默认参数,但如果值不存在则使用默认参数,因为键不在 dict 中。作为结果,{'a': None}.get('a', 'I do not want None')
仍会为您提供 None
。
除了@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()
)
除了朱利亚诺关于“或”行为的回答:它是“快”
>>> 1 or 5/0
1
所以有时它可能是一个有用的捷径,比如
object = getCachedVersion() or getFromDB()
关于@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)
对于像我这样偶然发现此问题的可行解决方案的人,当变量可能未定义时,我得到的最接近的是:
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) == True
与 variablename == True
相同
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。
希望这可以帮助
我发现下面的两个函数在处理许多可变测试用例时非常有用。
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
False
之外,数字 0、None
和空容器(包括字符串)被认为是错误的。大多数其他一切都被认为是真实的。我会说这里的主要危险是你会得到一个真实但非字符串的值,但这在某些程序中不会成为问题。datetime.time(0)
也是虚假的!other = "some default value" if s is None else s
。另请参阅:stackoverflow.com/questions/13710631/…