En Matemáticas, la división de números enteros está definida de manera que el resto sea siempre positivo. Así, estos serían en Matemáticas los resultados de cuatro divisiones en los que intervienen enteros positivos y negativos:
Pero en los lenguajes de programación, la división de números enteros no sigue siempre esa regla.
En el caso de Python, la regla es que el resto sea del mismo signo que el divisor. Así, estos serían en Python los resultados de las cuatro divisiones del ejemplo anterior, que se obtendrían con los operadores // y %:
Si el divisor es positivo, el resultado es el mismo, pero si el divisor es negativo, el resultado es diferente.
Otros lenguajes siguen otras reglas. Por ejemplo, en JavaScript y en PHP el resto tiene el mismo signo que el dividendo y en otros, como C o C++, el resultado depende del compilador.
Referencia: Resto de la división de enteros (Wikipedia)
Python permite utilizar valores no booleanos en las expresiones lógicas. Para evaluar las expresiones, Python convierte esos valores en booleanos. Lo curioso en estos casos es que la respuesta de Python no es un valor booleano, sino alguno de los valores de la expresión. Por ejemplo:
>>> 2 or 3 2 >>> 3 and 5 5
Desde el punto de vista lógico, ambas respuestas son correctas. Teniendo en cuenta que los números distintos de 0 se consideran True, el resultado de las dos expresiones es True. Python nos contesta con dos números distintos de cero, que considerados como booleanos, son True.
La pregunta que surge es por qué Python contesta los valores que contesta y no otros (3 en ambos casos, o cualquier otro valor distinto de cero).
La respuesta se encuentra en la manera cómo Python evalúa las expresiones. Al evaluar las expresiones, hay un momento en que Python ya sabe la respuesta final, sin necesidad de terminar las expresiones. El valor que contesta es precisamente el valor con el que ya sabe la respuesta.
Por ejemplo, al evaluar 2 or 3, como se trata de un or, en cuanto Python evalúa el primer valor (2, o sea True), ya sabe que el valor final va a ser True. Por eso contesta 2.
Sin embargo, el evaluar 3 and 5, como se trata de un and, Python tiene que evaluar los dos valores. Como los dos son True, el resultado es True. Python contesta entonces el último valor que ha evaluado, 5.
Los ejemplos siguientes muestran cómo Python sigue este criterio en expresiones más complejas:
>>> 0 or "" or "Pepe" or True 'Pepe' >>> 3 and "" and 5 and [1, 2, 3] '' >>> 4 or 3 and 2 or 5 4 >>> (4 or 3) and (2 or 5) 2