Recibo un error en el condicional IF. ¿Qué estoy haciendo mal?
La razón por la que obtienes un SyntaxError
es que no hay &&
operador en Python. Del mismo modo ||
y no!
son operadores válidos de Python.
Algunos de los operadores que puede conocer de otros idiomas tienen un nombre diferente en Python. Los operadores lógicos &&
y en ||
realidad se llaman and
y or
. Del mismo modo, !
se llama al operador de negación lógica not
.
Entonces podrías escribir:
if len(a) % 2 == 0 and len(b) % 2 == 0:
o incluso:
if not (len(a) % 2 or len(b) % 2):
Alguna información adicional (que puede ser útil):
Resumí el operador "equivalentes" en esta tabla:
+------------------------------+---------------------+
| Operator (other languages) | Operator (Python) |
+==============================+=====================+
| && | and |
+------------------------------+---------------------+
| || | or |
+------------------------------+---------------------+
| ! | not |
+------------------------------+---------------------+
Consulte también la documentación de Python: 6.11. Operaciones booleanas .
Además de los operadores lógicos, Python también tiene operadores bit a bit / binarios:
+--------------------+--------------------+
| Logical operator | Bitwise operator |
+====================+====================+
| and | & |
+--------------------+--------------------+
| or | | |
+--------------------+--------------------+
No hay negación bit a bit en Python (solo el operador inverso bit a bit ~
, pero eso no es equivalente a not
).
Ver también 6.6. Operaciones aritméticas unitarias y bit a bit / binarias y 6.7. Operaciones aritméticas binarias .
Los operadores lógicos (como en muchos otros idiomas) tienen la ventaja de que están en cortocircuito. Eso significa que si el primer operando ya define el resultado, entonces el segundo operador no se evalúa en absoluto.
Para mostrar esto, uso una función que simplemente toma un valor, lo imprime y lo devuelve nuevamente. Esto es útil para ver qué se evalúa realmente debido a las declaraciones de impresión:
>>> def print_and_return(value):
... print(value)
... return value
>>> res = print_and_return(False) and print_and_return(True)
False
Como puede ver, solo se ejecuta una declaración de impresión, por lo que Python realmente ni siquiera miró el operando correcto.
Este no es el caso de los operadores binarios. Aquellos siempre evalúan ambos operandos:
>>> res = print_and_return(False) & print_and_return(True);
False
True
Pero si el primer operando no es suficiente, entonces, por supuesto, se evalúa el segundo operador:
>>> res = print_and_return(True) and print_and_return(False);
True
False
Para resumir esto aquí hay otra tabla:
+-----------------+-------------------------+
| Expression | Right side evaluated? |
+=================+=========================+
| `True` and ... | Yes |
+-----------------+-------------------------+
| `False` and ... | No |
+-----------------+-------------------------+
| `True` or ... | No |
+-----------------+-------------------------+
| `False` or ... | Yes |
+-----------------+-------------------------+
El True
y False
representa lo que bool(left-hand-side)
regresa, no tienen que ser True
o False
, solo necesitan regresar True
o False
cuando bool
se les solicite (1).
Entonces, en Pseudo-Code (!) Las funciones and
y or
funcionan así:
def and(expr1, expr2):
left = evaluate(expr1)
if bool(left):
return evaluate(expr2)
else:
return left
def or(expr1, expr2):
left = evaluate(expr1)
if bool(left):
return left
else:
return evaluate(expr2)
Tenga en cuenta que este es un pseudocódigo y no un código de Python. En Python no puede crear funciones llamadas and
o or
porque son palabras clave. Además, nunca debe usar "evaluar" o if bool(...)
.
Personalizando el comportamiento de tus propias clases
Este implícita bool
llamada se puede utilizar para personalizar la forma en sus clases se comportan con and
, or
y not
.
Para mostrar cómo se puede personalizar esto, uso esta clase, que nuevamente print
es algo para rastrear lo que está sucediendo:
class Test(object):
def __init__(self, value):
self.value = value
def __bool__(self):
print('__bool__ called on {!r}'.format(self))
return bool(self.value)
__nonzero__ = __bool__ # Python 2 compatibility
def __repr__(self):
return "{self.__class__.__name__}({self.value})".format(self=self)
Entonces, veamos qué sucede con esa clase en combinación con estos operadores:
>>> if Test(True) and Test(False):
... pass
__bool__ called on Test(True)
__bool__ called on Test(False)
>>> if Test(False) or Test(False):
... pass
__bool__ called on Test(False)
__bool__ called on Test(False)
>>> if not Test(True):
... pass
__bool__ called on Test(True)
Si no tiene un __bool__
método, Python también verifica si el objeto tiene un __len__
método y si devuelve un valor mayor que cero. Puede ser útil saberlo en caso de que cree un contenedor de secuencia.
Ver también 4.1. Prueba de valor de verdad .
Matrices y subclases NumPy
Probablemente un poco más allá del alcance de la pregunta original, pero en caso de que esté lidiando con matrices o subclases NumPy (como Pandas Series o DataFrames), la bool
llamada implícita aumentará el temido ValueError
:
>>> import numpy as np
>>> arr = np.array([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> arr and arr
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> import pandas as pd
>>> s = pd.Series([1,2,3])
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> s and s
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
En estos casos, puede usar la lógica y la función de NumPy que realiza un elemento inteligente and
(o or
):
>>> np.logical_and(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([False, False, True, False])
>>> np.logical_or(np.array([False,False,True,True]), np.array([True, False, True, False]))
array([ True, False, True, True])
Si se trata solo de matrices booleanas , también podría usar los operadores binarios con NumPy, estos realizan comparaciones de elementos (pero también binarios):
>>> np.array([False,False,True,True]) & np.array([True, False, True, False])
array([False, False, True, False])
>>> np.array([False,False,True,True]) | np.array([True, False, True, False])
array([ True, False, True, True])
(1)
Que la bool
llamada en los operandos tiene que regresar True
o False
no es completamente correcta. Es solo el primer operando que necesita devolver un booleano en su __bool__
método:
class Test(object):
def __init__(self, value):
self.value = value
def __bool__(self):
return self.value
__nonzero__ = __bool__ # Python 2 compatibility
def __repr__(self):
return "{self.__class__.__name__}({self.value})".format(self=self)
>>> x = Test(10) and Test(10)
TypeError: __bool__ should return bool, returned int
>>> x1 = Test(True) and Test(10)
>>> x2 = Test(False) and Test(10)
Esto se debe a que en and
realidad devuelve el primer operando si el primer operando se evalúa False
y si se evalúa a True
continuación, devuelve el segundo operando:
>>> x1
Test(10)
>>> x2
Test(False)
Del mismo modo, or
pero al revés:
>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)
Sin embargo, si los usa en una if
declaración if
, también invocará implícitamente bool
el resultado. Entonces, estos puntos más finos pueden no ser relevantes para usted.