2.6. La peculiar naturaleza de and y or

En Python, and y or realizan las operaciones de lógica booleana como cabe esperar, pero no devuelven valores booleanos; devuelven uno de los valores reales que están comparando.

Ejemplo 2.16. Presentación de and

>>> 'a' and 'b'         1
'b'
>>> '' and 'b'          2
''
>>> 'a' and 'b' and 'c' 3
'c'
1 Cuando se utiliza and, los valores se evalúan en un contexto booleano de izquierda a derecha. 0, '', [], (), {} y None son falsos en un contexto booleano; todo lo demás es verdadero.[3] Si todos los valores son verdaderos en un contexto booleano, and devuelve el último valor. En este caso, and evalúa 'a', que es verdadera, después 'b', que es verdadera, y devuelve 'b'.
2 Si alguno de los valores es falso en contexto booleano, and devuelve el primer valor falso. En este caso, '' es el primer valor falso.
3 Todos los valores son verdaderos, luego and devuelve el último valor, 'c'.

Ejemplo 2.17. Presentación de or

>>> 'a' or 'b'          1
'a'
>>> '' or 'b'           2
'b'
>>> '' or [] or {}      3
{}
>>> def sidefx():
...     print "in sidefx()"
...     return 1
>>> 'a' or sidefx()     4
'a'
1 Cuando se utiliza or, los valores se evalúan en un contexto booleano, de izquierda a derecha, como con and. Si algún valor es verdadero, or devuelve ese valor inmediatamente. En este caso, 'a' es el primer valor verdadero.
2 or evalúa '', que es falsa, después 'b', que es verdadera, y devuelve 'b'.
3 Si todos los valores son falsos, or devuelve el último valor. or evalúa '', que es falsa, después [], que es falsa, después {}, que es falsa, y devuelve {}.
4 Advierta que or sólo evalúa valores hasta que encuentra uno verdadero en contexto booleano, y entonces omite el resto. Esta distinción es importante si algunos valores tienen efectos laterales. Aquí, la función sidefx no se llama nunca, porque or evalúa 'a', que es verdadera, y devuelve 'a' inmediatamente.

Si es usted un hacker de C, le será familiar la expresión bool ? a : b, que se evalúa como a si bool es verdadero, y b en caso contrario. Por el modo en que and y or funcionan en Python, se puede obtener el mismo efecto.

Ejemplo 2.18. Presentación del truco and-or

>>> a = "first"
>>> b = "second"
>>> 1 and a or b 1
'first'
>>> 0 and a or b 2
'second'
1 Esta sintaxis resulta similar a la de la expresión bool ? a : b en C. La expresión entera se evalúa de izquierda a derecha, luego and se evalúa primero. 1 and 'first' da como resultado 'first', después 'first' or 'second' da como resultado 'first'.
2 0 and 'first' da como resultado 0, después 0 or 'second' da como resultado 'second'.

Sin embargo, como esta expresión de Python es simplemente lógica booleana, y no una construcción especial del lenguaje, hay una diferencia muy, muy, muy importante entre este truco and-or en Python y la sintaxis bool ? a : b en C. Si el valor de a es falso, la expresión no funcionará como sería de esperar. (¿Puedes decir que he estado obsesionado con esto? ¿Más de una vez?)

Ejemplo 2.19. Cuando falla el truco and-or

>>> a = ""
>>> b = "second"
>>> 1 and a or b 1
'second'
1 Como a es una cadena vacía, que Python considera falsa en contexto booleano, 1 and '' se evalúa como '', después '' or 'second' se evalúa como 'second'. ¡Uy! Eso no es lo que queríamos.
Importante
El truco and-or, bool and a or b, no funcionará como la expresión bool ? a : b en C cuando a sea falsa en contexto booleano.

El truco real que hay tras el truco and-or es pues asegurarse de que el valor de a nunca es falso. Una forma habitual de hacer esto es convertir a en [a] y b en [b], y después tomar el primer elemento de la lista devuelta, que será a o b.

Ejemplo 2.20. Utilización segura del truco and-or

>>> a = ""
>>> b = "second"
>>> (1 and [a] or [b])[0] 1
''
1 Como [a] es una lista no vacía, nunca es falsa. Incluso si a es 0 o '' o cualquier otro valor falso, la lista [a] es verdadera porque tiene un elemento.

Hasta aquí, puede parecer que este truco tiene más inconvenientes que ventajas. Después de todo, se podría conseguir el mismo efecto con una sentencia if, así que ¿por qué meterse en este follón? Bien, en muchos casos, se elige entre dos valores constantes, luego se puede utilizar la sintaxis más simple sin preocuparse, porque se sabe que el valor de a será siempre verdadero. E incluso si hay que usar la forma más compleja, hay buenas razones para ello; en algunos casos no se permite la sentencia if, por ejemplo en las funciones lambda.

Lecturas complementarias

Footnotes

[3] Bueno, casi todo. Por omisión, las instancias de clases son verdaderas en un contexto booleano, pero se pueden definir métodos especiales en las clases para hacer que una instancia se evalúe como falsa. Aprenderá usted todo sobre las clases y los métodos especiales en el capítulo 3.