Estoy tratando de aprender Python y encontré un código que es agradable y corto pero que no tiene mucho sentido.
el contexto fue:
def fn(*args):
return len(args) and max(args)-min(args)
Entiendo lo que está haciendo, pero ¿por qué Python hace esto, es decir, devuelve el valor en lugar de Verdadero / Falso?
10 and 7-2
devuelve 5. De manera similar, cambiar el y por o resultará en un cambio en la funcionalidad. Entonces
10 or 7 - 2
Volvería 10.
¿Es este estilo legítimo / confiable, o hay algún inconveniente en esto?
python
operators
logical-operators
Marcin
fuente
fuente
and
(así comoor
) no está restringido a trabajar o devolver valores booleanos.None
o una excepción)0
no se puede saber siargs
estaba vacío o no, pero tenía todos los elementos iguales.Respuestas:
TL; DR
Comenzamos resumiendo los dos comportamientos de los dos operadores lógicos
and
yor
. Estos modismos formarán la base de nuestra discusión a continuació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
Es una forma muy
pitónicaconcisa (y posiblemente menos legible) de decir "siargs
no está vacío, devuelve el resultado demax(args) - min(args)
"; de lo contrario, devuelve0
. En general, es una representación más concisa de unaif-else
expresión. Por ejemplo,Debería traducirse (aproximadamente) a:
O equivalente,
Similar,
Es equivalente a,
Donde
exp1
yexp2
son objetos de python arbitrarios o expresiones que devuelven algún objeto. La clave para comprender los usos de los operadores lógicosand
yor
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 incluyeint
,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 .
Como
and
funcionaNos basamos en la pregunta de OP como paso a una discusión sobre cómo funcionan estos operadores en estos casos.
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 aland
operador:Dado que
and
se utiliza, la segunda expresión también debe evaluarse si la primera esTrue
. 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 que0
(un número positivo), por lo que el resultado devuelto esmax(args) - min(args)
. OTOH, si no se pasan argumentos,len(args)
es0
cuál es Falsy y0
se devuelve.Tenga en cuenta que una forma alternativa de escribir esta función sería:
O, de forma más concisa,
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
funcionaExplico el funcionamiento de
or
de una manera similar con un ejemplo artificial.Usamos
or
para manejar el caso de la esquina aquí. Definimosfoo
como:foo
realiza una filtración en la lista para retener todos los números9000
. 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,
Como antes, esta estructura es más flexible en términos de manejo de errores.
fuente
if ... else (if ... else (if ... else (if ... else ...)))
también se puede reescribir como... and ... and ... and ... and ...
y en ese momento se vuelve realmente difícil argumentar la legibilidad en ambos casos.Citando de Python Docs
Entonces, así es como se diseñó Python para evaluar las expresiones booleanas y la documentación anterior nos da una idea de por qué lo hicieron.
Para obtener un valor booleano, simplemente modifíquelo.
¿Por qué?
Cortocircuito.
Por ejemplo:
Lo mismo vale
or
también, es decir, devolverá la expresión que es Verdad tan pronto como la encuentre, ya que evaluar el resto de la expresión es redundante.En lugar de devolver hardcore
True
oFalse
, Python devuelve Truthy o Falsey , que de todos modos evaluaránTrue
oFalse
. Puede usar la expresión tal como está y seguirá funcionando.Para saber qué es Truthy y Falsey , consulte la respuesta de Patrick Haugh
fuente
y y o realizar la lógica booleana, pero devolver uno de los valores reales cuando están comparando. Cuando se usa y , 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 verdad.
Si todos los valores son verdaderos en un contexto booleano y devuelve el último valor.
Si algún valor es falso en un contexto booleano y devuelve el primer valor falso.
Entonces el código
devuelve el valor de
max(args)-min(args)
cuando hay argumentos, de lo contrario, devuelvelen(args)
que es 0.fuente
Esto es legítimo, es una evaluación de cortocircuito donde se devuelve el último valor.
Das un buen ejemplo. La función devolverá
0
si no se pasan argumentos, y el código no tiene que buscar un caso especial de no pasar argumentos.Otra forma de usar esto es asignar por defecto los argumentos None a una primitiva mutable, como una lista vacía:
Si se le pasa algún valor que no sea verdadero, el valor
alist
predeterminado es una lista vacía, una forma práctica de evitar unaif
declaración y la trampa del argumento predeterminado mutablefuente
Gotchas
Sí, hay algunas trampas.
fn() == fn(3) == fn(4, 4)
Primero, si
fn
retorna0
, no puede saber si fue llamado sin ningún parámetro, con un parámetro o con múltiples parámetros iguales:¿Qué
fn
significa?Entonces, Python es un lenguaje dinámico. No se especifica en ninguna parte qué
fn
hace, cuál debería ser su entrada y cómo debería verse su salida. Por lo tanto, es muy importante nombrar la función correctamente. Del mismo modo, no es necesario invocar argumentosargs
.delta(*numbers)
ocalculate_range(*numbers)
podría describir mejor lo que se supone que debe hacer la función.Errores de argumento
Finalmente,
and
se supone que el operador lógico evita que la función falle si se llama sin ningún argumento. Sin embargo, todavía falla si algún argumento no es un número:Posible alternativa
Aquí hay una forma de escribir la función de acuerdo con "Es más fácil pedir perdón que permiso". principio :
Como ejemplo:
Si realmente no desea generar una excepción cuando
delta
se llama sin ningún argumento, puede devolver algún valor que no puede ser posible de otra manera (por ejemplo,-1
oNone
):fuente
Me gustaría agregar a esta pregunta que no solo es legítimo y confiable, sino que también es ultra práctico. Aquí hay un ejemplo simple:
Por lo tanto, realmente puede usarlo a su favor. Para ser conciso, así es como lo veo:
Or
operadorEl
or
operador de Python devuelve el primer valor Truth-y, o el último valor, y se detieneAnd
operadorEl
and
operador de Python devuelve el primer valor False-y, o el último valor, y se detieneEntre bastidores
En Python, todos los números se interpretan como
True
excepto 0. Por lo tanto, decir:es lo mismo que:
Que es claramente
False
. Por tanto, es lógico que devuelva 0fuente
Si. Este es el comportamiento correcto y la comparación.
Al menos en Python,
A and B
rendimientosB
siA
se esencialmenteTrue
incluyendo, siA
no es NULL, NONone
NO un recipiente vacío (tal como un vacíolist
,dict
, etc).A
se devuelve IFFA
es esencialmenteFalse
oNone
o Vacío o Nulo.Por otro lado,
A or B
los rendimientosA
siA
se esencialmenteTrue
incluyendo, siA
no es NULL, NONone
NO un recipiente vacío (tal como un vacíolist
,dict
, etc), de lo contrario devuelveB
.Es fácil no notar (o pasar por alto) este comportamiento porque, en Python, cualquier
non-null
objeto no vacío que se evalúe como True se trata como un booleano.Por ejemplo, todo lo siguiente imprimirá "Verdadero"
Por otro lado, todo lo siguiente imprimirá "Falso"
fuente
A
es esencialmenteTrue
. Corregido.para entender de forma sencilla,
Y:
if first_val is False return first_val else second_value
p.ej:
pero,
y => si alguien es falso, será falso. si ambos son ciertos, entonces solo se convertirá en cierto
O:
if first_val is False return second_val else first_value
la razón es que, si primero es falso, compruebe si 2 es verdadero o no.
p.ej:
pero,
o => si alguien es falso, será cierto. entonces, si el primer valor es falso, no importa cuál se suponga que sea el valor 2. por lo que devuelve el segundo valor, lo que sea.
si alguien es verdad, se convertirá en verdad. si ambos son falsos, se volverá falso.
fuente