Ich erhalte einen Fehler in der IF-Bedingung. Was mache ich falsch?
Der Grund dafür SyntaxError
ist, dass es &&
in Python keinen Operator gibt . Ebenso ||
und !
sind keine gültigen Python-Operatoren.
Einige der Operatoren, die Sie möglicherweise aus anderen Sprachen kennen, haben in Python einen anderen Namen. Die logischen Operatoren &&
und ||
werden tatsächlich and
und genannt or
. Ebenso wird der logische Negationsoperator !
aufgerufen not
.
Sie könnten also einfach schreiben:
if len(a) % 2 == 0 and len(b) % 2 == 0:
oder auch:
if not (len(a) % 2 or len(b) % 2):
Einige zusätzliche Informationen (die nützlich sein könnten):
Ich habe die Operator "Äquivalente" in dieser Tabelle zusammengefasst:
+------------------------------+---------------------+
| Operator (other languages) | Operator (Python) |
+==============================+=====================+
| && | and |
+------------------------------+---------------------+
| || | or |
+------------------------------+---------------------+
| ! | not |
+------------------------------+---------------------+
Siehe auch Python-Dokumentation: 6.11. Boolesche Operationen .
Neben den logischen Operatoren hat Python auch bitweise / binäre Operatoren:
+--------------------+--------------------+
| Logical operator | Bitwise operator |
+====================+====================+
| and | & |
+--------------------+--------------------+
| or | | |
+--------------------+--------------------+
In Python gibt es keine bitweise Negation (nur den bitweisen inversen Operator ~
- aber das entspricht nichtnot
).
Siehe auch 6.6. Unäre arithmetische und bitweise / binäre Operationen und 6.7. Binäre Rechenoperationen .
Die logischen Operatoren (wie in vielen anderen Sprachen) haben den Vorteil, dass diese kurzgeschlossen sind. Das heißt, wenn der erste Operand das Ergebnis bereits definiert, wird der zweite Operator überhaupt nicht ausgewertet.
Um dies zu zeigen, verwende ich eine Funktion, die einfach einen Wert nimmt, ihn druckt und wieder zurückgibt. Dies ist praktisch, um zu sehen, was aufgrund der print-Anweisungen tatsächlich ausgewertet wird:
>>> def print_and_return(value):
... print(value)
... return value
>>> res = print_and_return(False) and print_and_return(True)
False
Wie Sie sehen, wird nur eine print-Anweisung ausgeführt, sodass Python nicht einmal den richtigen Operanden angesehen hat.
Dies ist bei den Binäroperatoren nicht der Fall. Diese bewerten immer beide Operanden:
>>> res = print_and_return(False) & print_and_return(True);
False
True
Aber wenn der erste Operand nicht ausreicht, wird natürlich der zweite Operator ausgewertet:
>>> res = print_and_return(True) and print_and_return(False);
True
False
Um dies hier zusammenzufassen, ist eine andere Tabelle:
+-----------------+-------------------------+
| Expression | Right side evaluated? |
+=================+=========================+
| `True` and ... | Yes |
+-----------------+-------------------------+
| `False` and ... | No |
+-----------------+-------------------------+
| `True` or ... | No |
+-----------------+-------------------------+
| `False` or ... | Yes |
+-----------------+-------------------------+
Die True
und False
stellen dar, was bool(left-hand-side)
zurückkehrt, sie müssen nicht sein True
oder False
sie müssen nur zurückkehren True
oder False
wann sie bool
aufgerufen werden (1).
In Pseudo-Code (!) Funktionieren die Funktionen and
und or
wie folgt:
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)
Beachten Sie, dass dies Pseudocode und kein Python-Code ist. In Python können Sie keine Funktionen erstellen, die aufgerufen werden and
oder or
weil dies Schlüsselwörter sind. Auch sollten Sie niemals "evaluieren" oder verwenden if bool(...)
.
Anpassen des Verhaltens Ihrer eigenen Klassen
Diese implizite bool
Aufruf kann verwendet werden , um anzupassen , wie Ihre Klassen verhalten sich mit and
, or
und not
.
Um zu zeigen, wie dies angepasst werden kann, verwende ich diese Klasse, die wiederum print
etwas ist, um zu verfolgen, was passiert:
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)
Mal sehen, was mit dieser Klasse in Kombination mit diesen Operatoren passiert:
>>> 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)
Wenn Sie keine __bool__
Methode haben, prüft Python auch, ob das Objekt eine __len__
Methode hat und ob es einen Wert größer als Null zurückgibt. Dies kann hilfreich sein, wenn Sie einen Sequenzcontainer erstellen.
Siehe auch 4.1. Wahrheitswertprüfung .
NumPy-Arrays und Unterklassen
Wahrscheinlich etwas außerhalb des Rahmens der ursprünglichen Frage, aber falls Sie mit NumPy-Arrays oder -Unterklassen (wie Pandas Series oder DataFrames) arbeiten, wird der implizite bool
Aufruf die gefürchteten 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 diesen Fällen können Sie die Logik und Funktion von NumPy verwenden, die elementweise and
(oder or
) ausführt :
>>> 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])
Wenn Sie nur mit booleschen Arrays arbeiten, können Sie auch die Binäroperatoren mit NumPy verwenden. Diese führen elementweise (aber auch binäre) Vergleiche durch:
>>> 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)
Dass der bool
Aufruf der Operanden zurückkehren muss True
oder False
nicht ganz korrekt ist. Es ist nur der erste Operand, der in seiner __bool__
Methode einen Booleschen Wert zurückgeben muss :
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)
Das ist , weil and
tatsächlich den ersten Operanden zurückgibt , wenn der erste Operand ausgewertet False
und , wenn sie ausgewertet True
dann gibt er den zweiten Operanden:
>>> x1
Test(10)
>>> x2
Test(False)
Ähnliches gilt für, or
aber umgekehrt:
>>> Test(True) or Test(10)
Test(True)
>>> Test(False) or Test(10)
Test(10)
Wenn Sie sie jedoch in einer if
Anweisung verwenden, if
ruft bool
das Ergebnis implizit auch das Ergebnis auf. Daher sind diese Feinheiten für Sie möglicherweise nicht relevant.