TL; DR
Comenzamos resumiendo los dos comportamientos de los dos operadores lógicos and
y or
. Estos modismos formarán la base de nuestra discusión a continuación.
and
Devuelve el primer valor de Falsy si hay alguno; de lo contrario, devuelve el último valor de la expresión.
or
Devuelve el primer valor de Verdad si hay alguno; de lo contrario, devuelve el último valor de la expresión.
El comportamiento también se resume en los documentos , especialmente en esta tabla:

El único operador que devuelve un valor booleano independientemente de sus operandos es el not
operador.
Evaluaciones de "veracidad" y "veracidad"
La declaración
len(args) and max(args) - min(args)
Es una forma muy pitónica concisa (y posiblemente menos legible) de decir "si args
no está vacío, devuelve el resultado de max(args) - min(args)
"; de lo contrario, devuelve 0
. En general, es una representación más concisa de una if-else
expresión. Por ejemplo,
exp1 and exp2
Debería traducirse (aproximadamente) a:
r1 = exp1
if r1:
r1 = exp2
O equivalente,
r1 = exp1 if exp1 else exp2
Similar,
exp1 or exp2
Es equivalente a,
r1 = exp1
if not r1:
r1 = exp2
Donde exp1
y exp2
son objetos de python arbitrarios o expresiones que devuelven algún objeto. La clave para comprender los usos de los operadores lógicos and
y or
aquí es comprender que no están restringidos a operar o devolver valores booleanos. Aquí se puede probar cualquier objeto con un valor de veracidad. Esto incluye int
, str
, list
, dict
, tuple
, set
, NoneType
, y el usuario define objetos. Las reglas de cortocircuito también se aplican.
Pero, ¿qué es la veracidad?
Se refiere a cómo se evalúan los objetos cuando se usan en expresiones condicionales. @Patrick Haugh resume muy bien la veracidad en esta publicación .
Todos los valores se consideran "verdaderos" excepto los siguientes, que son "falsos":
None
False
0
0.0
0j
Decimal(0)
Fraction(0, 1)
[]
- un vacío list
{}
- un vacío dict
()
- un vacío tuple
''
- un vacío str
b''
- un vacío bytes
set()
- un vacío set
- un vacío
range
, comorange(0)
- objetos para los cuales
obj.__bool__()
devoluciones False
obj.__len__()
devoluciones 0
Un valor "veraz" satisfará la verificación realizada por if
o while
declaraciones. Usamos "verdad" y "falsedad" para diferenciar de los
bool
valores True
y False
.
Como and
funciona
Nos basamos en la pregunta de OP como paso a una discusión sobre cómo funcionan estos operadores en estos casos.
Dada una función con la definición
def foo(*args):
...
¿Cómo devuelvo la diferencia entre el valor mínimo y máximo en una lista de cero o más argumentos?
Encontrar el mínimo y el máximo es fácil (¡use las funciones incorporadas!). El único inconveniente aquí es manejar adecuadamente el caso de la esquina donde la lista de argumentos podría estar vacía (por ejemplo, llamando foo()
). Podemos hacer ambas cosas en una sola línea gracias al and
operador:
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4
foo()
# 0
Dado que and
se utiliza, la segunda expresión también debe evaluarse si la primera es True
. Tenga en cuenta que, si la primera expresión se evalúa como veraz, el valor de retorno es siempre el resultado de la segunda expresión . Si la primera expresión se evalúa como falsa, el resultado devuelto es el resultado de la primera expresión.
En la función anterior, Si foo
recibe uno o más argumentos, len(args)
es mayor que 0
(un número positivo), por lo que el resultado devuelto es max(args) - min(args)
. OTOH, si no se pasan argumentos, len(args)
es 0
cuál es Falsy y 0
se devuelve.
Tenga en cuenta que una forma alternativa de escribir esta función sería:
def foo(*args):
if not len(args):
return 0
return max(args) - min(args)
O, de forma más concisa,
def foo(*args):
return 0 if not args else max(args) - min(args)
Si, por supuesto, ninguna de estas funciones realiza ninguna verificación de tipo, a menos que confíe completamente en la entrada proporcionada, no confíe en la simplicidad de estas construcciones.
Como or
funciona
Explico el funcionamiento de or
de una manera similar con un ejemplo artificial.
Dada una función con la definición
def foo(*args):
...
¿Cómo completarías foo
para devolver todos los números 9000
?
Usamos or
para manejar el caso de la esquina aquí. Definimos foo
como:
def foo(*args):
return [x for x in args if x > 9000] or 'No number over 9000!'
foo(9004, 1, 2, 500)
# [9004]
foo(1, 2, 3, 4)
# 'No number over 9000!'
foo
realiza una filtración en la lista para retener todos los números 9000
. Si existen tales números, el resultado de la comprensión de la lista es una lista no vacía que es Verdad, por lo que se devuelve (cortocircuito en acción aquí). Si no existen tales números, entonces el resultado de la []
composición de la lista es cuál es Falsy. Entonces, la segunda expresión ahora se evalúa (una cadena no vacía) y se devuelve.
Usando condicionales, podríamos reescribir esta función como,
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
Como antes, esta estructura es más flexible en términos de manejo de errores.
and
(así comoor
) no está restringido a trabajar o devolver valores booleanos.