要获得完整的解释,请考虑以下示例:
>>> import dis
>>> def is_truthy(x):
>>> return "Those sweed words!" if x else "All lies!"
>>> is_truthy(None)
'All lies!'
>>> is_truthy(1)
'Those sweed words!'
>>> is_truthy([])
'All lies!'
>>> is_truthy(object())
'Those sweed words!'
is_truthy() 发生了什么?让我们来了解一下。运行dis.dis(is_truthy) 会给你:
2 0 LOAD_FAST 0 (x)
3 POP_JUMP_IF_FALSE 10
6 LOAD_CONST 1 ('The pure word')
9 RETURN_VALUE
>> 10 LOAD_CONST 2 ('All lies!')
13 RETURN_VALUE
如您所见,x 被压入堆栈,然后POP_JUMP_IF_FALSE 被执行。这将跳转到第一次推送,然后返回正确的答案。
POP_JUMP_IF_FALSE 定义在ceval.c:
TARGET(POP_JUMP_IF_FALSE) {
PyObject *cond = POP();
int err;
if (cond == Py_True) {
Py_DECREF(cond);
FAST_DISPATCH();
}
if (cond == Py_False) {
Py_DECREF(cond);
JUMPTO(oparg);
FAST_DISPATCH();
}
err = PyObject_IsTrue(cond);
Py_DECREF(cond);
if (err > 0)
err = 0;
else if (err == 0)
JUMPTO(oparg);
else
goto error;
DISPATCH();
如您所见,如果POP_JUMP_IF_FALSE 消费的对象已经是True 或False,答案很简单。否则,解释器试图通过调用PyObject_IsTrue() 来找出对象是否是真实,它在object protocol 中定义。 code in object.c 向您展示了它的工作原理:
PyObject_IsTrue(PyObject *v)
{
Py_ssize_t res;
if (v == Py_True)
return 1;
if (v == Py_False)
return 0;
if (v == Py_None)
return 0;
else if (v->ob_type->tp_as_number != NULL &&
v->ob_type->tp_as_number->nb_bool != NULL)
res = (*v->ob_type->tp_as_number->nb_bool)(v);
else if (v->ob_type->tp_as_mapping != NULL &&
v->ob_type->tp_as_mapping->mp_length != NULL)
res = (*v->ob_type->tp_as_mapping->mp_length)(v);
else if (v->ob_type->tp_as_sequence != NULL &&
v->ob_type->tp_as_sequence->sq_length != NULL)
res = (*v->ob_type->tp_as_sequence->sq_length)(v);
else
return 1;
/* if it is negative, it should be either -1 or -2 */
return (res > 0) ? 1 : Py_SAFE_DOWNCAST(res, Py_ssize_t, int);
}
同样,如果对象只是True 或False 本身,答案很简单。 None 也被认为是错误的。然后检查各种协议,如number protocol、mapping protocol 和sequence protocol。否则对象被认为是真的。
总结一下:如果x 是True,则认为True 为真,根据数字、映射或序列协议或其他类型的对象为真。如果您希望您的对象评估为假,您可以通过实现任何上述协议来实现,请参阅提供的链接。
与if x is None 中的None 比较是显式比较。上面的逻辑不适用。