Python中相当于Perl/Ruby的||=

9 投票
3 回答
3148 浏览
提问于 2025-04-17 11:55

可能是重复的问题:
Python 条件赋值运算符

抱歉问这么简单的问题,但在网上搜索 ||= 并没有找到什么有用的信息;)

在 Python 中有没有类似于 Ruby 和 Perl 中的 ||= 这种写法呢?

举个例子:

foo = "hey"
foo ||= "what"    # assign foo if it's undefined
# foo is still "hey"

bar ||= "yeah"
# bar is "yeah"

另外,这种写法的通用名称是什么呢?我最开始猜是条件赋值,但在维基百科上看到的内容并不是我想要的。

3 个回答

1

我不太确定这个名字。 我能想到的最好名字是:

>>> a = 'foo'
>>> a = 'a' in locals() and a or 'what'
>>> a
'foo'
>>> b = 'b' in locals() and b or 'yeah'
>>> b
'yeah'
3

在Python中,你几乎不会遇到未定义的变量,如果遇到了,通常意味着你犯了错误。不过,幸运的是,很多常用的默认值(比如空的容器、长度为零的字符串、数字零和None)在Python中都是“假值”,所以你有时会看到一些利用布尔运算符工作原理的写法:

name = name or "Guido"   # if name is empty, set it to "Guido"
numb = numb or 42        # if numb is zero, set it to 42

之所以这样有效,是因为Python在处理or时,如果第一个参数是“真值”,它会停止继续判断,这叫做短路运算。无论如何,它返回的是实际的参数,而不是简单的TrueFalse。所以如果name是“Jim”,那么"Jim" or "Guido"的结果就是"Jim",因为"Jim"是一个非零长度的字符串,因此是“真值”。

当然,当你不知道正在处理的值的类型,或者“假值”是一个有效值时,这种方法就不太好用了。不过,它在处理配置文件和raw_input()时效果很好,因为缺失的值会返回一个空字符串:

name = raw_input("What is your name? ") or "Guido"

另一个常见的用法是在处理字典中的项目时。字典类的get()方法允许你指定一个默认值,如果变量不在字典中,就会使用这个默认值。

name = values.get("name", "Guido")

当你的函数使用**kwargs传递关键字参数时,这个方法也可以用上。你也可以用它处理变量,因为globals()locals()函数分别返回当前作用域内的所有全局或局部变量,格式是字典:

name = locals().get("name", "Guido")

不过,正如我所说,你在Python中几乎不会遇到真正未定义的变量。在像Web框架这样的情况下,你会收到查询字符串参数作为字典,然后可以在这个字典上使用.get()方法。

在极少数情况下,如果一个名称确实不存在(比如你的配置文件是Python语法,并且你是作为Python模块导入而不是解析它,并且你希望用户可以省略某些值……或者其他类似的奇怪情况),那么你可以使用getattr(),它(像字典的.get()一样)也接受一个默认值:

import config
name = getattr(config, "name", "Guido")    # rather than just name.config

或者让它抛出一个NameError异常,然后捕获这个异常。

11

稍微多说一点,但最简单的方法是

foo = "hey"
foo = foo or "what"
#foo is still "hey"

bar = None
bar = bar or "yeah"
#bar is "yeah"

你也可以使用三元运算符

bar = None
bar = bar if bar else "yeah"

不过,如果我理解得没错,||= 是用来给那些之前没有定义的变量赋值的,对吧?我之前还真不知道。

要在本地作用域做到这一点,这个看起来不太好看的方法可以用

bar = locals()['bar'] if 'bar' in locals() else 'yeah'

编辑:

刚看到重复的问题,里面有很多解决方案 :) 对于那些懒得去找的人,它们还包括了我最后一个方法的一个更好的变体

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

不过这个方法对未定义的变量是无效的,只有假值会被替换,而未定义的变量会引发一个NameError。而下一个方法则只对未定义的变量有效,并且始终保持之前的假值,正如@Borodin所说,这就像Perl中的//=

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

当然,还有人使用了异常 :(

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

撰写回答