我在 Python 2.7.3 上尝试了很多不同的东西,我遇到了这段代码:
输入:
x = 4
y = 7
x or y
输出:
4
根据文档,or
是一个布尔运算。不or
应该屈服True
还是False
只屈服?
所以,我用这段代码尝试了更多:
输入:
a = 3
b = 2
a or b
输出:
3
然后在这一点上,我假设代码将返回表达式的第一个参数。
为什么 Python 会给我这个输出?Pythonor
操作背后到底发生了什么?
我在 Python 2.7.3 上尝试了很多不同的东西,我遇到了这段代码:
输入:
x = 4
y = 7
x or y
输出:
4
根据文档,or
是一个布尔运算。不or
应该屈服True
还是False
只屈服?
所以,我用这段代码尝试了更多:
输入:
a = 3
b = 2
a or b
输出:
3
然后在这一点上,我假设代码将返回表达式的第一个参数。
为什么 Python 会给我这个输出?Pythonor
操作背后到底发生了什么?
从文档中:
x 或 y :如果 x 为假,则为 y,否则为 x (1)
对于每个不为零的整数,x or y
将返回x
georgesi 的回答完美地回答了您提出的确切问题——但是您链接到的文档也是如此,因为他只是引用了这些文档。所以,大概你想要更多。
你可能会问两件事:
or
应该返回 a时,为什么bool
Python 会这样设计?既然你加粗了“ Python操作背后到底发生了什么or
”这个问题,我猜是后者。
请记住,Python 有多种实现,只要它们符合参考文档设置的规范,它们就可以随意实现它们。但通常,当人们问“Python 是如何做到这一点的?”时。他们的意思是“CPython 实现是如何做到这一点的?”
首先,让我们看一些字节码:
>>> def f():
... return 1 or 2
>>> import dis
>>> dis.dis(f)
2 0 LOAD_CONST 1 (1)
3 JUMP_IF_TRUE_OR_POP 9
6 LOAD_CONST 2 (2)
>> 9 RETURN_VALUE
这是什么意思?在 Python 式的伪代码中,它是这样的:
top = 1
if top:
goto 9
else:
del top
top = 2
label 9
return top
如果您想更好地理解(而 CPython 是您关心的实现),您只需要知道 CPython 字节码解释器是一个简单的堆栈机器,并且该堆栈机器的代码在文件ceval.c
中。所以,我们可以在这里JUMP_IF_TRUE_OR_POP
找到代码。(操作码只是将常量值推送到堆栈上,这样就可以找到它们。我认为我们真的不需要研究它来理解它是如何工作的。)LOAD_CONST
w = TOP()
or
你可以看到它有点复杂。
这主要是因为它通过在调用等效的 C-API 之前if top
检查if top == False
和优化部件,并且因为它必须处理来自该调用的异常。但它也在优化堆栈的使用。如果不解释如何和工作,很难变得太精确,但基本思想是,它避免了将值从堆栈中弹出只是为了将它们推回以返回。if top == True
bool(top)
bool
DISPATCH
FAST_DISPATCH
但这就是“Pythonor
操作背后到底发生了什么?”
您还加粗了“不or
应该屈服True
还是False
只屈服? ”所以,这使我们回到问题 1。
首先,请记住鸭子类型是 Python 的核心。or
应该产生一些可以被使用的东西,就好像它在它重要的地方True
或False
任何地方一样。你应该特别写类似if foo:
而不是if foo == True:
(或if foo is True:
或if foo != False:
或其他)的东西,所以你不应该关心差异。
其次,大约一半的语言同意你的“布尔运算”应该严格返回布尔类型的值,而一半的语言不同意。即使在不是围绕鸭子类型构建的语言中,比如 C。那么,语言设计者如何决定呢?
使or
运算符始终返回的“C++ 风格”bool
避免了副本,允许编译器更好地执行静态类型,并为程序员提供更好的动态类型信息。前两个在 Python 中完全不相关,最后一个通常仅在您编写依赖于类型而不是鸭子类型的代码时才有用,这通常被认为是非 Python 的。
使其返回第一个真值(或最后一个假值)的“C 风格”使得实现稍微简单一些,并为程序员提供了一种三元表达式if
的速记。else
当 Python 没有三元if
-else
时,这是一个更容易调用的方法。如今,也许它是一个更接近的电话 - 特别是因为有些人讨厌a or b
它的速记a if a else b
并认为它不符合标准。
但是历史站在已经存在的一边;除非有令人信服的理由,否则什么都不会改变,并且根据您的口味可能会朝相反方向发展的近距离通话并不是令人信服的理由。
从您提供的文档链接:
表达式 x 或 y 首先计算 x;如果 x 为真,则返回其值;否则,评估 y 并返回结果值。
请注意,唯一or
应该返回一个假对象的情况是两个操作数都是假的。
考虑到这种行为,我们可以看到在第一个操作数为真的情况下,我们已经知道两个操作数都不为假。这意味着无论第二个操作数是什么,整个表达式的计算结果都应该为真。返回第一个操作数(为真)。
在第一个操作数(我们称之为 x)为false的情况下,x or y
逻辑上等价于y
. 如果 y 为真,则 x 和 y 都不为假,因此x or y
为真。如果 y 是假的,那么 x 和 y 都是假的,所以x or y
也是假的。这就是为什么如果 x 为假则返回 y。
这种方法称为短路评估,当 x 为假时,计算成本较低,因为不需要对 y 进行不必要的评估。
Python 中的or
运算符将返回第一个值,如果它被认为是 true,或者如果第一个是 false,第二个是 true,则返回第二个值。如果两者都是假的,那么它将返回False
。在这种情况下,4 和 3 都是真值,因此它们被返回。如果您改为使用 0,您将看到使用的第二个值
x = 0
y = 3
x or y
这将返回 3
这个问题已经回答了,但你仍然可能会问自己为什么这种行为是有意义的。
这是一个简单的用例:
port = int(raw_input("Port number (default 5000): ") or 5000)
在这种情况下,or
(and and
) 的行为非常合理。另一个:
url_scheme = enable_https and 'https' or 'http' # although this can be also expressed as:
url_scheme = 'https' if enable_https else 'http'
# but i personally prefer the above, because i can read it
# more easily due to the two possible values being closer together
这有点像 if 语句的简写。我一直在 JS 编码中使用它。
你可以AND
以同样的方式使用。
var x = 0;
x && console.log('x is not truth-y');
x || console.log('x is false-y');
正如一堆其他人已经说过的那样,&&
or||
运算符评估它们左侧的表达式,然后,取决于我们是在谈论&&
or||
并且取决于评估是真值还是假值,它们将要么停止,要么继续计算它们右侧的表达式。