Per una spiegazione completa consideri il seguente esempio:
>>> 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!'
Cosa succede a is_truthy()
? Scopriamolo. Esecuzione dis.dis(is_truthy)
ti dà:
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
Come si può vedere x
viene inserito nello stack, quindi POP_JUMP_IF_FALSE
viene eseguito. Questo prenderà il salto prima spinta e poi restituirà la risposta giusta.
POP_JUMP_IF_FALSE
è definito in 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();
Come si può vedere, se l'oggetto consumato da POP_JUMP_IF_FALSE
è già sia True
o False
, la risposta è semplice. In caso contrario, l'interprete prova a scoprire se l'oggetto è vero chiamando il numero PyObject_IsTrue()
definito nello object protocol. Il code in object.c vi mostra esattamente come funziona:
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);
}
Anche in questo caso, se l'oggetto è solo True
o False
se stessi, la risposta è semplice. None
è considerato falso.Quindi vengono controllati vari protocolli come number protocol, mapping protocol e sequence protocol. Altrimenti l'oggetto è considerato vero.
Per concludere: x
si considera vero se è True
, vero in base al numero, al protocollo di mappatura o sequenza o ad un altro tipo di oggetto. Se vuoi che il tuo oggetto venga valutato come falso, puoi farlo implementando uno qualsiasi dei suddetti protocolli, vedi i collegamenti forniti.
Il confronto con None
come in if x is None
è un confronto esplicito. La logica sopra non si applica.
Nota: attualmente [ 'se:' è equivalente a 'se .has_children():'] (http: //hg.python .org/cpython/file/43f27e69bc29/Lib/xml/etree/ElementTree.py # l231) è molto diverso da 'se non è None:'. –
jfs