Ich schreibe ein Sicherheitssystem, das unbefugten Benutzern den Zugriff verweigert.
name = input("Hello. Please enter your name: ")
if name == "Kevin" or "Jon" or "Inbar":
print("Access granted.")
else:
print("Access denied.")
Es gewährt autorisierten Benutzern wie erwartet Zugriff, lässt aber auch nicht autorisierte Benutzer herein!
Hello. Please enter your name: Bob
Access granted.
Warum passiert das? Ich habe klar gesagt, dass nur Zugriff gewährt werden soll, wenn name
Kevin, Jon oder Inbar gleich sind. Ich habe auch die entgegengesetzte Logik ausprobiert if "Kevin" or "Jon" or "Inbar" == name
, aber das Ergebnis ist das gleiche.
Hinweis: Diese Frage ist als kanonisches doppeltes Ziel dieses sehr häufigen Problems gedacht. Es gibt eine weitere beliebte Frage: Wie teste ich mehrere Variablen auf Gleichheit mit einem einzigen Wert? das hat das gleiche grundlegende Problem, aber die Vergleichsziele sind vertauscht. Diese Frage sollte nicht als Duplikat dieser Frage geschlossen werden, da dieses Problem bei Python-Neulingen auftritt, die möglicherweise Schwierigkeiten haben, das Wissen aus der umgekehrten Frage auf ihr Problem anzuwenden.
Lösung des Problems
In vielen Fällen sieht Python aus und verhält sich wie natürliches Englisch, aber dies ist ein Fall, in dem diese Abstraktion fehlschlägt. Menschen können Kontexthinweise verwenden, um festzustellen, dass "Jon" und "Inbar" Objekte sind, die mit dem Verb "equals" verbunden sind, aber der Python-Interpreter denkt wörtlicher.
if name == "Kevin" or "Jon" or "Inbar":
is logically equivalent to:
if (name == "Kevin") or ("Jon") or ("Inbar"):
Was für Benutzer Bob äquivalent ist zu:
if (False) or ("Jon") or ("Inbar"):
Der or
Operator wählt das erste Argument mit positivem Wahrheitswert:
if "Jon":
Und da "Jon" einen positiven Wahrheitswert hat, wird der if
Block ausgeführt. Das bewirkt, dass „Zugriff gewährt" unabhängig vom angegebenen Namen gedruckt wird.
All diese Überlegungen gelten auch für den Ausdruck if "Kevin" or "Jon" or "Inbar" == name
. der erste Wert, "Kevin"
, ist wahr, also wird der if
Block ausgeführt.
Es gibt zwei gängige Methoden, um diese Bedingung richtig zu konstruieren.
Verwenden Sie mehrere ==
Operatoren, um jeden Wert explizit zu prüfen:
if name == "Kevin" or name == "Jon" or name == "Inbar":
Erstellen Sie eine Sammlung gültiger Werte (z. B. eine Menge, eine Liste oder ein Tupel) und verwenden Sie den in
Operator, um die Mitgliedschaft zu testen:
if name in {"Kevin", "Jon", "Inbar"}:
Im Allgemeinen sollte der zweite bevorzugt werden, da er einfacher zu lesen und auch schneller ist:
>>> import timeit
>>> timeit.timeit('name == "Kevin" or name == "Jon" or name == "Inbar"',
setup="name='Inbar'")
0.4247764749999945
>>> timeit.timeit('name in {"Kevin", "Jon", "Inbar"}', setup="name='Inbar'")
0.18493307199999265
Für diejenigen, die einen Beweis wollen, if a == b or c or d or e:...
der tatsächlich so analysiert wird. Das eingebaute ast
Modul gibt eine Antwort:
>>> import ast
>>> ast.parse("a == b or c or d or e", "<string>", "eval")
<ast.Expression object at 0x7f929c898220>
>>> print(ast.dump(_, indent=4))
Expression(
body=BoolOp(
op=Or(),
values=[
Compare(
left=Name(id='a', ctx=Load()),
ops=[
Eq()],
comparators=[
Name(id='b', ctx=Load())]),
Name(id='c', ctx=Load()),
Name(id='d', ctx=Load()),
Name(id='e', ctx=Load())]))
Wie man sehen kann, ist es der boolesche Operator or
, der auf vier Unterausdrücke angewendet wird: Vergleich a == b
; und einfache Ausdrücke c
, d
, und e
.
Keine Kommentare:
Kommentar veröffentlichen