Dostaję błąd w warunkowym IF. Co ja robię źle?
Istnieje powód, dla którego dostajesz SyntaxErrorto, że &&w Pythonie nie ma operatora. Podobnie ||i nie! są poprawnymi operatorami języka Python.
Niektóre operatory, które możesz znać z innych języków, mają w Pythonie inną nazwę. Operatory logiczne &&i ||faktycznie są nazywane andi or. Podobnie !wywoływany jest operator logicznej negacji not.
Więc możesz po prostu napisać:
if len(a) % 2 == 0 and len(b) % 2 == 0:
lub nawet:
if not (len(a) % 2 or len(b) % 2):
Kilka dodatkowych informacji (które mogą się przydać):
Podsumowałem operatora „ekwiwalenty” w tej tabeli:
+------------------------------+---------------------+
| Operator (other languages) | Operator (Python) |
+==============================+=====================+
| && | and |
+------------------------------+---------------------+
| || | or |
+------------------------------+---------------------+
| ! | not |
+------------------------------+---------------------+
Zobacz także dokumentację Pythona: 6.11. Operacje logiczne .
Oprócz operatorów logicznych Python ma także operatory bitowe / binarne:
+--------------------+--------------------+
| Logical operator | Bitwise operator |
+====================+====================+
| and | & |
+--------------------+--------------------+
| or | | |
+--------------------+--------------------+
W Pythonie nie ma bitowej negacji (tylko bitowy operator odwrotny ~- ale to nie jest równoważne not).
Zobacz także 6.6. Jednoargumentowe operacje arytmetyczne i bitowe / binarne oraz 6.7. Binarne operacje arytmetyczne .
Operatory logiczne (podobnie jak w wielu innych językach) mają tę zaletę, że są zwarte. Oznacza to, że jeśli pierwszy argument już określa wynik, to drugi operator nie jest w ogóle oceniany.
Aby to pokazać, używam funkcji, która po prostu przyjmuje wartość, drukuje ją i zwraca ponownie. Jest to przydatne, aby zobaczyć, co jest faktycznie oceniane na podstawie instrukcji print:
>>> def print_and_return(value):
... print(value)
... return value
>>> res = print_and_return(False) and print_and_return(True)
False
Jak widać, wykonywana jest tylko jedna instrukcja print, więc Python tak naprawdę nawet nie spojrzał na odpowiedni operand.
Nie dotyczy to operatorów binarnych. Zawsze oceniają oba operandy:
>>> res = print_and_return(False) & print_and_return(True);
False
True
Ale jeśli pierwszy operand nie wystarczy, wówczas oceniany jest drugi operator:
>>> res = print_and_return(True) and print_and_return(False);
True
False
Podsumowując, oto kolejna tabela:
+-----------------+-------------------------+
| Expression | Right side evaluated? |
+=================+=========================+
| `True` and ... | Yes |
+-----------------+-------------------------+
| `False` and ... | No |
+-----------------+-------------------------+
| `True` or ... | No |
+-----------------+-------------------------+
| `False` or ... | Yes |
+-----------------+-------------------------+
TrueI Falsereprezentują co bool(left-hand-side)powraca, nie trzeba być Truealbo False, po prostu trzeba zwrócić Truelub Falsegdy boolnazywa się na nich (1).
Tak więc w Pseudokodzie (!) Funkcje andi ordziałają w następujący sposób:
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)
Zauważ, że to pseudo-kod, a nie kod Pythona. W Pythonie nie można tworzyć wywoływanych funkcji andlub orponieważ są to słowa kluczowe. Nigdy też nie powinieneś używać „oceny” lub if bool(...).
Dostosowywanie zachowania własnych klas
To niejawne boolwywołanie może być użyte do dostosowania sposobu, w jaki zachowują się twoje klasy and, ororaz not.
Aby pokazać, jak można to dostosować, używam tej klasy, która ponownie printjest czymś, co pozwala śledzić, co się dzieje:
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)
Zobaczmy więc, co dzieje się z tą klasą w połączeniu z tymi operatorami:
>>> 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)
Jeśli nie masz __bool__metody, Python sprawdza również, czy obiekt ma __len__metodę i czy zwraca wartość większą niż zero. Może to być przydatne, jeśli utworzysz kontener sekwencji.
Zobacz także 4.1. Testowanie wartości prawdy .
Tablice i podklasy NumPy
Prawdopodobnie nieco poza zakres pierwotnego pytania, ale w przypadku, gdy masz do czynienia z tablicami lub podklasami NumPy (takimi jak Pandas Series lub DataFrames), niejawne boolwywołanie wzbudzi przerażenie 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().
W takich przypadkach można użyć funkcji logicznej i funkcji NumPy, która wykonuje element and(lub 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])
Jeśli masz do czynienia tylko z tablicami logicznymi, możesz także użyć operatorów binarnych z NumPy, które wykonują porównania elementarne (ale także binarne):
>>> 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)
Że boolwywołanie na operandach musi zostać zwrócone Truelub Falsenie jest całkowicie poprawne. To tylko pierwszy operand, który musi zwrócić wartość logiczną w swojej __bool__metodzie:
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)
Jest tak, ponieważ andfaktycznie zwraca pierwszy operand, jeśli pierwszy operand ewaluuje Falsei jeśli ewaluuje, Trueto zwraca drugi operand:
>>> x1
Test(10)
>>> x2
Test(False)
Podobnie, orale tylko na odwrót:
>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)
Jeśli jednak użyjesz ich w ifinstrukcji if, domyślnie wywoła również boolwynik. Więc te drobniejsze punkty mogą nie być dla ciebie odpowiednie.