GOOGLE ADS

Sonntag, 1. Mai 2022

Warum ergibt "a == x or y or z" immer True?

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 nameKevin, 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 orOperator wählt das erste Argument mit positivem Wahrheitswert:

if "Jon":

Und da "Jon" einen positiven Wahrheitswert hat, wird der ifBlock 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 ifBlock 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 inOperator, 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 astModul 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

    Warum werden SCHED_FIFO-Threads derselben physischen CPU zugewiesen, obwohl CPUs im Leerlauf verfügbar sind?

    Lösung des Problems Wenn ich das richtig verstehe, versuchen Sie, SCHED_FIFO mit aktiviertem Hyperthreading ("HT") zu verwenden, ...