Python中相当于Perl/Ruby的||=
可能是重复的问题:
Python 条件赋值运算符
抱歉问这么简单的问题,但在网上搜索 ||=
并没有找到什么有用的信息;)
在 Python 中有没有类似于 Ruby 和 Perl 中的 ||=
这种写法呢?
举个例子:
foo = "hey"
foo ||= "what" # assign foo if it's undefined
# foo is still "hey"
bar ||= "yeah"
# bar is "yeah"
另外,这种写法的通用名称是什么呢?我最开始猜是条件赋值,但在维基百科上看到的内容并不是我想要的。
3 个回答
我不太确定这个名字。 我能想到的最好名字是:
>>> a = 'foo'
>>> a = 'a' in locals() and a or 'what'
>>> a
'foo'
>>> b = 'b' in locals() and b or 'yeah'
>>> b
'yeah'
在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
时,如果第一个参数是“真值”,它会停止继续判断,这叫做短路运算。无论如何,它返回的是实际的参数,而不是简单的True
或False
。所以如果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
异常,然后捕获这个异常。
稍微多说一点,但最简单的方法是
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'