¿Cómo probar la igualdad de múltiples variables frente a un solo valor?
Estoy intentando crear una función que compare varias variables con un número entero y genere una cadena de tres letras. Me preguntaba si había alguna manera de traducir esto a Python. Así que di:
x = 0
y = 1
z = 3
mylist = []
if x or y or z == 0:
mylist.append("c")
if x or y or z == 1:
mylist.append("d")
if x or y or z == 2:
mylist.append("e")
if x or y or z == 3:
mylist.append("f")
que devolvería una lista de:
["c", "d", "f"]
No entiendes cómo funcionan las expresiones booleanas; no funcionan como una oración en inglés y supongo que estás hablando de la misma comparación para todos los nombres aquí. Estás buscando:
if x == 1 or y == 1 or z == 1:
x
y y
de lo contrario se evalúan por sí solos ( False
si 0
, True
de lo contrario).
Puedes acortarlo usando una prueba de contención contra una tupla :
if 1 in (x, y, z):
o mejor aún:
if 1 in {x, y, z}:
usar aset
para aprovechar la prueba de membresía de costo constante (es decir, in
toma una cantidad de tiempo fija cualquiera que sea el operando de la izquierda).
Explicación
Cuando usas or
, Python ve cada lado del operador como expresiones separadas . La expresión x or y == 1
se trata primero como una prueba booleana para x
, luego, si es False, y == 1
se prueba la expresión.
Esto se debe a la precedencia de los operadores . El or
operador tiene una precedencia menor que la ==
prueba, por lo que esta última se evalúa primero .
Sin embargo, incluso si este no fuera el caso, y la expresión x or y or z == 1
en realidad se interpretara como (x or y or z) == 1
tal, esto todavía no haría lo que usted espera que haga.
x or y or z
se evaluaría como el primer argumento que sea "verdadero", por ejemplo, not False
, numérico 0 o vacío (consulte expresiones booleanas para obtener detalles sobre lo que Python considera falso en un contexto booleano).
Entonces, para los valores x = 2; y = 1; z = 0
, x or y or z
se resolvería en 2
, porque ese es el primer valor verdadero en los argumentos. Entonces 2 == 1
sería False
, aunque y == 1
sería True
.
Lo mismo se aplicaría a la inversa; probar múltiples valores contra una sola variable; x == 1 or 2 or 3
fracasaría por las mismas razones. Utilice x == 1 or x == 2 or x == 3
o x in {1, 2, 3}
.
Su problema se soluciona más fácilmente con una estructura de diccionario como:
x = 0
y = 1
z = 3
d = {0: 'c', 1:'d', 2:'e', 3:'f'}
mylist = [d[k] for k in [x, y, z]]
Como afirma Martijn Pieters, el formato correcto y más rápido es:
if 1 in {x, y, z}:
Siguiendo su consejo, ahora tendría declaraciones if separadas para que Python lea cada declaración, ya sea que las primeras fueran True
o False
. Como:
if 0 in {x, y, z}:
mylist.append("c")
if 1 in {x, y, z}:
mylist.append("d")
if 2 in {x, y, z}:
mylist.append("e")
...
Esto funcionará, pero si te sientes cómodo usando diccionarios (mira lo que hice allí), puedes limpiar esto creando un diccionario inicial que asigne los números a las letras que deseas y luego simplemente usando un bucle for:
num_to_letters = {0: "c", 1: "d", 2: "e", 3: "f"}
for number in num_to_letters:
if number in {x, y, z}:
mylist.append(num_to_letters[number])
La forma directa de escribir x or y or z == 0
es
if any(map((lambda value: value == 0), (x,y,z))):
pass # write your logic.
Pero no creo que te guste. :) Y así es feo.
La otra forma (mejor) es:
0 in (x, y, z)
Por cierto, muchos if
s podrían escribirse como algo como esto
my_cases = {
0: Mylist.append("c"),
1: Mylist.append("d")
# ..
}
for key in my_cases:
if key in (x,y,z):
my_cases[key]()
break
Si ERES muy vago, puedes poner los valores dentro de una matriz. Como
list = []
list.append(x)
list.append(y)
list.append(z)
nums = [add numbers here]
letters = [add corresponding letters here]
for index in range(len(nums)):
for obj in list:
if obj == num[index]:
MyList.append(letters[index])
break
También puedes poner los números y letras en un diccionario y hacerlo, pero esto probablemente sea MUCHO más complicado que simplemente declaraciones if. Eso es lo que te pasa por intentar ser muy vago :)
Una cosa más, tu
if x or y or z == 0:
se compilará, pero no de la forma deseada. Cuando simplemente pones una variable en una declaración if (ejemplo)
if b
el programa comprobará si la variable no es nula. Otra forma de escribir la declaración anterior (que tiene más sentido) es
if bool(b)
Bool es una función incorporada en Python que básicamente ejecuta el comando de verificar una declaración booleana (si no sabes qué es eso, es lo que estás intentando hacer en tu declaración if ahora mismo :))
Otra forma perezosa que encontré es:
if any([x==0, y==0, z==0])
Para comprobar si un valor está contenido dentro de un conjunto de variables, puede utilizar los módulos incorporados itertools
y operator
.
Por ejemplo:
Importaciones:
from itertools import repeat
from operator import contains
Declarar variables:
x = 0
y = 1
z = 3
Cree un mapeo de valores (en el orden que desea verificar):
check_values = (0, 1, 3)
Utilícelo itertools
para permitir la repetición de las variables:
check_vars = repeat((x, y, z))
Finalmente, use la map
función para crear un iterador:
checker = map(contains, check_vars, check_values)
Luego, al verificar los valores (en el orden original), use next()
:
if next(checker) # Checks for 0
# Do something
pass
elif next(checker) # Checks for 1
# Do something
pass
etc...
Esto tiene una ventaja sobre lambda x: x in (variables)
porque operator
es un módulo incorporado y es más rápido y eficiente que el uso lambda
que tiene que crear una función personalizada en el lugar.
Otra opción para comprobar si hay un valor distinto de cero (o Falso) en una lista:
not (x and y and z)
Equivalente:
not all((x, y, z))