TL; DR
Zaczynamy od podsumowania dwóch zachowań dwóch operatorów logicznych andi 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 notoperator.
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 argsnie jest puste, zwróć wynik max(args) - min(args)”, w przeciwnym razie zwróć 0. Ogólnie jest to bardziej zwięzła reprezentacja if-elsewyraż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 exp1i exp2są dowolnymi obiektami Pythona lub wyrażeniami, które zwracają jakiś obiekt. Kluczem do zrozumienia zastosowań logiki andi oroperatoró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 iflub while. Używamy „prawda” i „fałsz”, aby odróżnić
boolwartości Truei False.
Jak anddział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 andoperatorowi:
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
foo()
Ponieważ andjest 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 0jest Falsy i 0jest 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 ordział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ł foozwracanie wszystkich liczb9000 ?
Używamy tutaj ordo obsługi skrzynki narożnej. Definiujemy foojako:
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.