TL; DR
Zaczynamy od podsumowania dwóch zachowań dwóch operatorów logicznych and
i or
. Te idiomy będą stanowić podstawę naszej dyskusji poniżej.
and
Zwróć pierwszą wartość Falsy, jeśli takie istnieją, w przeciwnym razie zwróć ostatnią wartość w wyrażeniu.
or
Zwróć pierwszą wartość Truthy, jeśli istnieje, w przeciwnym razie zwróć ostatnią wartość w wyrażeniu.
Zachowanie jest również podsumowane w dokumentach , zwłaszcza w tej tabeli:
Jedynym operatorem zwracającym wartość logiczną niezależnie od jej operandów jest not
operator.
Oceny „Prawdy” i „Prawdy”
Wyrok
len(args) and max(args) - min(args)
Jest bardzo pytonicznym zwięzłym (i prawdopodobnie mniej czytelnym) sposobem powiedzenia „jeśli args
nie jest puste, zwróć wynik max(args) - min(args)
”, w przeciwnym razie zwróć 0
. Ogólnie jest to bardziej zwięzła reprezentacja if-else
wyrażenia. Na przykład,
exp1 and exp2
Powinien (z grubsza) przetłumaczyć na:
r1 = exp1
if r1:
r1 = exp2
Lub równoważnie
r1 = exp2 if exp1 else exp1
Podobnie,
exp1 or exp2
Powinien (z grubsza) przetłumaczyć na:
r1 = exp1
if not r1:
r1 = exp2
Lub równoważnie
r1 = exp1 if exp1 else exp2
Gdzie exp1
i exp2
są dowolnymi obiektami Pythona lub wyrażeniami, które zwracają jakiś obiekt. Kluczem do zrozumienia zastosowań logiki and
i or
operatorów jest zrozumienie, że nie ograniczają się one do operowania lub zwracania wartości boolowskich. Każdy obiekt, który ma wartość prawdziwości, może zostać tutaj przetestowany. Obejmuje to int
, str
, list
, dict
, tuple
, set
, NoneType
, i zdefiniowane przez użytkownika obiektów. Nadal obowiązują zasady dotyczące zwarć.
Ale czym jest prawdomówność?
Odnosi się do sposobu oceny obiektów, gdy są używane w wyrażeniach warunkowych. @Patrick Haugh ładnie podsumowuje prawdomówność w tym poście .
Wszystkie wartości są uważane za „prawdziwe” z wyjątkiem następujących, które są „fałszywe”:
None
False
0
0.0
0j
Decimal(0)
Fraction(0, 1)
[]
- pusty list
{}
- pusty dict
()
- pusty tuple
''
- pusty str
b''
- pusty bytes
set()
- pusty set
- pusty
range
, jakrange(0)
- obiekty, dla których
obj.__bool__()
zwroty False
obj.__len__()
zwroty 0
Wartość „prawdziwa” spełni sprawdzenie dokonane przez
instrukcje if
lub while
. Używamy „prawda” i „fałsz”, aby odróżnić
bool
wartości True
i False
.
Jak and
działa
Opieramy się na pytaniu OP jako o przejściu do dyskusji na temat tego, jak ci operatorzy w tych przypadkach.
Biorąc pod uwagę funkcję z definicją
def foo(*args):
...
Jak zwrócić różnicę między wartością minimalną i maksymalną na liście zawierającej zero lub więcej argumentów?
Znalezienie minimum i maksimum jest łatwe (skorzystaj z wbudowanych funkcji!). Jedynym problemem jest odpowiednia obsługa przypadku narożnika, w którym lista argumentów może być pusta (na przykład wywołanie foo()
). Możemy to zrobić w jednej linii dzięki and
operatorowi:
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
foo()
Ponieważ and
jest używane, drugie wyrażenie również musi zostać ocenione, jeśli jest to pierwsze True
. Zauważ, że jeśli pierwsze wyrażenie jest oceniane jako prawdziwe, wartość zwracana jest zawsze wynikiem drugiego wyrażenia . Jeśli pierwsze wyrażenie zostanie ocenione jako Falsy, zwrócony wynik jest wynikiem pierwszego wyrażenia.
W powyższej funkcji If foo
otrzymuje jeden lub więcej argumentów, len(args)
jest większe niż 0
(liczba dodatnia), więc zwracany wynik to max(args) - min(args)
. OTOH, jeśli nie zostaną przekazane żadne argumenty, len(args)
to 0
jest Falsy i 0
jest zwracane.
Zauważ, że alternatywnym sposobem zapisania tej funkcji byłoby:
def foo(*args):
if not len(args):
return 0
return max(args) - min(args)
Lub, bardziej zwięźle,
def foo(*args):
return 0 if not args else max(args) - min(args)
Jeśli oczywiście żadna z tych funkcji nie sprawdza typów, więc jeśli nie ufasz całkowicie dostarczonym danym wejściowym, nie polegaj na prostocie tych konstrukcji.
Jak or
działa
Wyjaśniam działanie or
w podobny sposób na wymyślonym przykładzie.
Biorąc pod uwagę funkcję z definicją
def foo(*args):
...
Jak byś ukończył foo
zwracanie wszystkich liczb9000
?
Używamy tutaj or
do obsługi skrzynki narożnej. Definiujemy foo
jako:
def foo(*args):
return [x for x in args if x > 9000] or 'No number over 9000!'
foo(9004, 1, 2, 500)
foo(1, 2, 3, 4)
foo
przeprowadza filtrację na liście, aby zachować wszystkie liczby 9000
. Jeśli istnieją takie liczby, wynikiem zrozumienia listy jest niepusta lista, która jest Prawdą, więc jest zwracana (zwarcie w działaniu tutaj). Jeśli nie ma takich liczb, wynikiem zestawienia listy []
jest Falsy. Zatem drugie wyrażenie jest teraz oceniane (niepusty łańcuch) i jest zwracane.
Korzystając z warunków warunkowych, możemy ponownie napisać tę funkcję jako,
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
Tak jak poprzednio, ta struktura jest bardziej elastyczna pod względem obsługi błędów.
and
(jak równieżor
) nie ogranicza się do pracy z wartościami logicznymi ani do zwracania ich.