“与”和“或”在一个语句中如何组合使用?
这个函数让我有点困惑:
def protocol(port):
return port == "443" and "https://" or "http://"
有人能解释一下它背后发生的事情是怎样让它这样工作的嘛?
我之前是这样理解的,直到我试了一下:
要么是 A)
def protocol(port):
if port == "443":
if bool("https://"):
return True
elif bool("http://"):
return True
return False
要么是 B)
def protocol(port):
if port == "443":
return True + "https://"
else:
return True + "http://"
这是Python中的某种特殊情况吗?还是我完全搞错了语句是怎么运作的?
7 个回答
你真正想问的是像 C and X or Y
这样的表达式是什么意思或有什么作用。这是Python用户早期尝试用来代替 C ? X : Y
的一种方式。
大部分情况下,这种写法是有效的,但如果 X
是 False
,就会出现问题,这导致了很多Python代码中的bug。因此在 Python常见问题解答 中,你会发现更正确的写法是 (C and [X] or [Y])[0]
,因为一个只有一个元素的列表,无论它的布尔值是什么,都会被认为是 True
!例如: [None]
是 True
,但 None
不是。上面提到的例子之所以有效,是因为表示 X
的字符串不是空的。
不过,这一切在Python 2.5中发生了变化,当时语言中加入了三元或条件运算符,让你可以使用更简洁的 X if C else Y
,正如这里其他帖子所提到的。如果你看到代码使用旧的格式,那是因为这个用户是个老牌的Python程序员,还没有采用新语法,或者他们复制粘贴了其他旧代码,或者他们的公司仍在使用2.4.x(或更早的版本)等等。
说到这里,针对你具体的问题,还有一个“隐藏特性”需要提到,让我们仔细看看 return port == "443" and "https://" or "http://"
:
这里的 and
的优先级比 or
高,这意味着你可以把它想象成这个等价表达式: (port == "443" and "https://") or "http://"
。此外,我提到的隐藏特性被称为 短路,也就是说如果 (port == "443" and "https://")
都为真(实际上是的),那么 or
的部分会被完全忽略。然而,如果其中一个或两个都不为真,只有在这种情况下 or
的部分才会被使用。
还有一点需要注意:非空字符串总是被认为是 True
,所以 port == "443"
是唯一可能为 False
的部分,因此这是主要的问题。如果它为真,评估就会移动到 and
的右边,也就是说会返回 "https://"
。如果它为假,另一个短路就会发生,"https://"
会被跳过,评估会继续到 or
的右边。
总结一下这段代码的作用:它检查 port == "443"
,如果是,就返回 "https://"
,否则返回 "http://"
。返回值不会是 True
或 False
。最准确的等价写法是:
def protocol(port):
if port == "443":
return "https://"
else:
return "http://"
在现代Python中,你可以这样写:
def protocol(port):
return "https://" if port == "443" else "http://"
最后一个假设是 port
是一个字符串。一个更健壮的版本会支持整数输入,例如 return "https://" if str(port) == "443" else "http://"
。
and
这个操作符的意思是,如果左边的值是真的(也就是有意义的),那么就返回右边的值。or
这个操作符则是,如果左边的值是假的(也就是没有意义的),那么就返回右边的值。否则,它们都会返回左边的值。我们可以说它们是合并的意思。
这是一个比较老的说法;用括号来表示优先级。
(port == "443" and "https://") or "http://"
x and y
的意思是,如果 x
是“真”的话,就返回 y
;如果 x
是“假”的话,就返回 x
。而 a or b
则正好相反,如果 a
是“真”的话,就返回 a
,否则返回 b
。
所以,如果 port == "443"
是真的,这个表达式就会返回 and
右边的部分,也就是 "https://"
。如果不是,那么 and
就是假的,这时就会用到 or
,返回 "http://"
,也就是它右边的部分。
在现代的 Python 中,有一种更好的方式来表达这个比较老的说法:
"https://" if port == "443" else "http://"