Ricevo un errore nel condizionale IF. Che cosa sto facendo di sbagliato?
La ragione per cui si ottiene a SyntaxErrorè che non esiste un &&operatore in Python. Allo stesso modo ||e non! sono operatori Python validi .
Alcuni degli operatori che potresti conoscere da altre lingue hanno un nome diverso in Python. Gli operatori logici &&e ||sono effettivamente chiamati ande or. Allo stesso modo !viene chiamato l' operatore di negazione logicanot .
Quindi potresti semplicemente scrivere:
if len(a) % 2 == 0 and len(b) % 2 == 0:
o anche:
if not (len(a) % 2 or len(b) % 2):
Alcune informazioni aggiuntive (che potrebbero tornare utili):
Ho riassunto gli operatori "equivalenti" in questa tabella:
+------------------------------+---------------------+
| Operator (other languages) | Operator (Python) |
+==============================+=====================+
| && | and |
+------------------------------+---------------------+
| || | or |
+------------------------------+---------------------+
| ! | not |
+------------------------------+---------------------+
Vedi anche la documentazione di Python: 6.11. Operazioni booleane .
Oltre agli operatori logici, Python ha anche operatori bit a bit / binari:
+--------------------+--------------------+
| Logical operator | Bitwise operator |
+====================+====================+
| and | & |
+--------------------+--------------------+
| or | | |
+--------------------+--------------------+
Non c'è negazione bit a bit in Python (solo l'operatore inverso bit a bit ~- ma ciò non equivale a not).
Vedi anche 6.6. Operazioni aritmetiche unarie e bit a bit / binarie e 6.7. Operazioni aritmetiche binarie .
Gli operatori logici (come in molte altre lingue) hanno il vantaggio di essere in cortocircuito. Ciò significa che se il primo operando definisce già il risultato, il secondo operatore non viene valutato affatto.
Per mostrarlo uso una funzione che prende semplicemente un valore, lo stampa e lo restituisce di nuovo. Questo è utile per vedere cosa viene effettivamente valutato a causa delle dichiarazioni di stampa:
>>> def print_and_return(value):
... print(value)
... return value
>>> res = print_and_return(False) and print_and_return(True)
False
Come puoi vedere, viene eseguita una sola istruzione di stampa, quindi Python non ha nemmeno guardato l'operando giusto.
Questo non è il caso degli operatori binari. Questi valutano sempre entrambi gli operandi:
>>> res = print_and_return(False) & print_and_return(True);
False
True
Ma se il primo operando non è sufficiente, ovviamente viene valutato il secondo operatore:
>>> res = print_and_return(True) and print_and_return(False);
True
False
Per riassumere, ecco un'altra tabella:
+-----------------+-------------------------+
| Expression | Right side evaluated? |
+=================+=========================+
| `True` and ... | Yes |
+-----------------+-------------------------+
| `False` and ... | No |
+-----------------+-------------------------+
| `True` or ... | No |
+-----------------+-------------------------+
| `False` or ... | Yes |
+-----------------+-------------------------+
Il Truee Falserappresentano ciò che bool(left-hand-side)ritorna, non devono essere Trueo False, devono solo tornare Trueo Falsequando boolviene chiamato su di loro (1).
Quindi in Pseudo-Code (!) Le funzioni ande orfunzionano in questo modo:
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)
Si noti che questo è pseudo-codice non codice Python. In Python non è possibile creare funzioni chiamate ando orperché queste sono parole chiave. Inoltre non dovresti mai usare "valutare" o if bool(...).
Personalizzare il comportamento delle tue classi
Questa implicita boolchiamata può essere utilizzato per personalizzare come le vostre classi si comportano con and, ore not.
Per mostrare come questo può essere personalizzato, uso questa classe che di nuovo printè qualcosa per tenere traccia di ciò che sta accadendo:
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)
Quindi vediamo cosa succede con quella classe in combinazione con questi operatori:
>>> 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)
Se non hai un __bool__metodo, Python verifica anche se l'oggetto ha un __len__metodo e se restituisce un valore maggiore di zero. Potrebbe essere utile sapere nel caso in cui si crea un contenitore di sequenze.
Vedi anche 4.1. Test del valore di verità .
Array e sottoclassi di NumPy
Probabilmente un po 'oltre lo scopo della domanda originale ma nel caso in cui si tratti di array o sottoclassi di NumPy (come Pandas Series o DataFrames), la boolchiamata implicita aumenterà il temuto 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().
In questi casi puoi usare la logica e la funzione di NumPy che esegue un elemento 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])
Se hai a che fare solo con array booleani puoi anche usare gli operatori binari con NumPy, questi eseguono confronti a livello di elementi (ma anche binari):
>>> 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)
Che la boolchiamata sugli operandi debba tornare Trueo che Falsenon sia completamente corretta. È solo il primo operando che deve restituire un valore booleano nel suo __bool__metodo:
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)
Questo perché in andrealtà restituisce il primo operando se il primo operando valuta Falsee se valuta Truequindi restituisce il secondo operando:
>>> x1
Test(10)
>>> x2
Test(False)
Allo stesso modo per oril contrario:
>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)
Tuttavia, se li si utilizza in ifun'istruzione, ifverrà anche implicitamente richiamato boolil risultato. Quindi questi punti più fini potrebbero non essere rilevanti per te.