W wielu przypadkach Python wygląda i zachowuje się jak naturalny angielski, ale jest to jeden przypadek, w którym ta abstrakcja zawodzi. Ludzie mogą używać wskazówek kontekstowych, aby określić, że „Jon” i „Inbar” są obiektami połączonymi z czasownikiem „równa się”, ale interpreter Pythona jest bardziej dosłowny.
if name == "Kevin" or "Jon" or "Inbar":
jest logicznie równoważne z:
if (name == "Kevin") or ("Jon") or ("Inbar"):
Co dla użytkownika Bob jest równoważne z:
if (False) or ("Jon") or ("Inbar"):
or
Operator wybiera pierwszy argument z pozytywnej wartości logicznej :
if ("Jon"):
A ponieważ „Jon” ma dodatnią wartość prawdy, if
blok jest wykonywany. To właśnie powoduje, że "Przyznany dostęp" jest drukowany niezależnie od podanej nazwy.
Całe to rozumowanie odnosi się również do wyrażenia if "Kevin" or "Jon" or "Inbar" == name
. pierwsza wartość "Kevin"
to prawda, więc if
blok jest wykonywany.
Istnieją dwa typowe sposoby prawidłowego skonstruowania tego warunku.
Użyj wielu ==
operatorów, aby jawnie sprawdzić każdą wartość:
if name == "Kevin" or name == "Jon" or name == "Inbar":
Utwórz sekwencję prawidłowych wartości i użyj in
operatora, aby przetestować członkostwo:
if name in {"Kevin", "Jon", "Inbar"}:
Ogólnie rzecz biorąc, druga powinna być preferowana, ponieważ jest łatwiejsza do odczytania, a także szybsza:
>>> 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
Dla tych, którzy mogą chcieć dowodu, który if a == b or c or d or e: ...
rzeczywiście jest analizowany w ten sposób. Wbudowany ast
moduł dostarcza odpowiedzi:
>>> import ast
>>> ast.parse("if a == b or c or d or e: ...")
<_ast.Module object at 0x1031ae6a0>
>>> ast.dump(_)
"Module(body=[If(test=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())]), body=[Expr(value=Ellipsis())], orelse=[])])"
>>>
Więc test
z if
wyglądem rachunku, takich jak ten:
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())
]
)
Jak widać, jest to operator logiczna or
zastosowana do wielokrotnego values
, a mianowicie, a == b
i c
, d
i e
.