Python条件赋值运算符

87

是否存在Python中与Ruby的||=运算符相等的操作(“如果变量未设置,则设置变量”)?

Ruby示例:

 variable_not_set ||= 'bla bla'
 variable_not_set == 'bla bla'

 variable_set = 'pi pi'
 variable_set ||= 'bla bla'
 variable_set == 'pi pi'

1
如果它没有被设置,它就不会被设置 - 只有在当前值为false(falsenil)时才会被设置。当然,在将0和""视为false的语言中,这种区别更为重要,但仍然需要注意。 - user395760
这个 Ruby 操作符的使用场景是什么? - David Heffernan
1
实现这个功能的方法是使用try except NameError,正如phihag所指出的那样。但是在Python中,正如大家所说的那样,这并没有太多意义。在Ruby中,由于人们将任意代码块传递给函数来运行的方式,它更有用。目标函数可能需要设置一个在执行外部块时未初始化的变量。在Python中不存在这种情况。 - jsbueno
10个回答

221

我很惊讶没有人提供这个答案。它不像 Ruby 的 ||= 一样是内置的,但基本上等效且仍然只有一行:

foo = foo if 'foo' in locals() else 'default'

当然,locals()只是一个字典,所以你可以这样做:

foo = locals().get('foo', 'default')

3
为什么会感到惊讶呢?也许人们只是不知道而已。 - Zingg

32

我会使用

x = 'default' if not x else x

比这里提出的所有替代方案都要短得多,并且一针见血。阅读:“如果x未设置,则将x设置为'default',否则保持其为x。” 但是,如果您需要 None 0 False “”作为有效值,则需要更改此行为,例如:

valid_vals = ("", 0, False) # We want None to be the only un-set value

x = 'default' if not x and x not in valid_vals else x
这种情况也很适合编写一个函数,以便随处可用:
setval_if = lambda val: 'default' if not val and val not in valid_vals else val

在这个时候,你可以这样使用它:

>>> x = None # To set it to something not valid
>>> x = setval_if(x) # Using our special function is short and sweet now!
>>> print x # Let's check to make sure our None valued variable actually got set
'default'

最后,如果你非常想念 Ruby 中缀符号,你可以通过遵循这个人的技巧,重载 ||=|(或类似的东西)来实现:http://code.activestate.com/recipes/384122-infix-operators/


7
你的第一个例子无法运行:>>> x = 'default' if not x else x 跟踪最近的调用如下: File "<stdin>", line 1, in <module> NameError: name 'x' is not defined - J Jones
10
这个答案是错误的,如果x不存在将会失败。由于问题要求测试存在的方法,因此这个解决方法不可行。 - Shayne
2
这个答案解决了“条件赋值”的问题,即如果变量未设置,则设置它。当然,右侧的所有内容都必须定义,否则会出现错误(我只是将其视为伪代码)。 x = "value1" if True else "value2"。 一般来说, x = 'value1' if condition else 'value2' - Maubeh
这个答案既有效又非常有用,而且还具有教育意义。我建议添加一条注释,说明变量必须存在于答案文本之内,但除此之外非常棒。 - Danin

16
不,替换内容是:

没有,替换的内容是:

try:
   v
except NameError:
   v = 'bla bla'

然而,想要使用这种结构通常意味着代码流程过于复杂。通常情况下,你会执行以下步骤:

try:
   v = complicated()
except ComplicatedError: # complicated failed
   v = 'fallback value'

并且永远不要不确定 v 是否设置。 如果它是可以设置或不设置的多个选项之一,请使用字典及其get方法,该方法允许设置默认值。


2
不,你不应该使用 except: - user395760
@delnan 我不想对 complicated() 的性质做出具体的假设。已添加。 - phihag
你确定吗?@emish提供了一个简单得多的解决方案。 - Donal Lafferty
这是一个糟糕的解决方案。它不仅更加复杂,而且性能也更差。我甚至建议将此解决方案从问题中删除。 - yuvalm2
使用 try . . .except 来控制流程是不好的实践。当尝试分配变量时,应该在出现问题时使用异常。 - Paul D.

10
在 Python 2.5 及以后版本中,有一种条件赋值语法 - 由于其语法不太明显,很容易被忽视。下面是它的用法:
x = true_value if condition else false_value

如需更多参考,请查看Python 2.5文档


这段话提到了Python 2.5文档,如果需要更多信息可以查看此文档。请点击上方链接前往文档页面。

这不是被要求的内容。 - Shayne
所以针对所提出的问题:variable = "bla bla" if not variable else variable - undefined

5

(无法评论,否则我会这样做)我认为检查上面的本地内容的建议不太正确。应该是:

foo = foo if 'foo' in locals() or 'foo' in globals() else 'default'

在所有情况下都正确。

然而,尽管它得到了赞同,我认为这甚至不是Ruby运算符的一个好比喻。因为Ruby运算符允许左侧不仅仅是一个简单的名称:

foo[12] ||= something
foo.bar ||= something

异常处理方法可能是最接近的类比。

4
不知道哪些变量被定义是Python中的一个错误,而不是一个特性。请使用字典代替:
d = {}
d.setdefault('key', 1)
d['key'] == 1

d['key'] = 2
d.setdefault('key', 1)
d['key'] == 2

1

我通常是这样做的:

def set_if_not_exists(obj,attr,value):
 if not hasattr(obj,attr): setattr(obj,attr,value)

1

我这样做只是为了分享,以防对问题发起人或其他人有所帮助...

def iff(value, default):
    return default if not value else value

使用方法:

z = iff(x,y) # z = x if and only if x is not null otherwise y

0

我认为如果你在字典中查找某些内容,你需要的是 setdefault 方法:

(Pdb) we=dict()
(Pdb) we.setdefault('e',14)
14
(Pdb) we['e']
14
(Pdb) we['r']="p"
(Pdb) we.setdefault('r','jeff')
'p'
(Pdb) we['r']
'p'
(Pdb) we[e]
*** NameError: name 'e' is not defined
(Pdb) we['e']
14
(Pdb) we['q2']

*** KeyError: 'q2' (Pdb)

需要注意的是,在我的例子中,setdefault 方法仅在所引用的键不存在时才更改字典。


-1

我不确定我是否正确理解了问题...试图“读取”一个“未定义”的变量名称的值将触发一个NameError。(请参见{{link1:这里,Python有“名称”而不是变量...)。

== 编辑 ==

正如delnan在评论中指出的那样,下面的代码并不健壮,并且会在许多情况下崩溃...

尽管如此,如果您的变量“存在”,但具有某种虚拟值,例如None,则以下内容将起作用:

>>> my_possibly_None_value = None
>>> myval = my_possibly_None_value or 5
>>> myval
5
>>> my_possibly_None_value = 12
>>> myval = my_possibly_None_value or 5
>>> myval
12
>>> 

(请参见有关真值的段落)


2
只要值可能为0、""(空字符串)或其他任何“假值”,这个代码就会出错。请明确检查它是否为None - user395760
哦,是的,你说得对,我没有想到那个。谢谢你的提示!实际上,我从来没有需要做这个“或”操作,而且我认为这是一个有效的答案,但问题本身似乎与Python无关... - tsimbalar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接