TL; DR
Почнемо з підсумовування двох поведінок двох логічних операторів andі or. Ці ідіоми ляжуть в основу нашого обговорення нижче.
and
Поверніть перше значення Falsy, якщо воно є, інакше поверніть останнє значення у виразі.
or
Поверніть перше значення Truthy, якщо воно є, інакше поверніть останнє значення у виразі.
Поведінка також узагальнена в документах , особливо в цій таблиці:

Єдиним оператором, що повертає булеве значення, незалежно від його операндів, є notоператор.
"Правдивість" та "Істинність" Оцінки
Заява
len(args) and max(args) - min(args)
Це дуже пітонічний лаконічний (і, можливо, менш читабельний) спосіб сказати "якщо argsне порожній, поверніть результат max(args) - min(args)", інакше поверніть 0. Загалом, це більш стисле подання if-elseвиразу. Наприклад,
exp1 and exp2
Чи слід (приблизно) перекласти на:
r1 = exp1
if r1:
r1 = exp2
Або, що еквівалентно,
r1 = exp1 if exp1 else exp2
Так само,
exp1 or exp2
Еквівалентно,
r1 = exp1
if not r1:
r1 = exp2
Де exp1і exp2є довільними об'єктами python, або виразами, що повертають якийсь об'єкт. Ключем до розуміння використання логіки andта orоператорів тут є розуміння того, що вони не обмежуються роботою або поверненням булевих значень. Тут можна перевірити будь-який об’єкт, що має значення істинності. Це включає в себе int, str, list, dict, tuple, set, NoneType, і певні користувачем об'єкти. Правила короткого замикання все ще застосовуються.
Але що таке правдивість?
Це стосується того, як обчислюються об’єкти при використанні в умовних виразах. @Patrick Haugh резюмує правдивість у цьому дописі .
Усі значення вважаються "неправдивими", за винятком наступних, які є "хибними":
None
False
0
0.0
0j
Decimal(0)
Fraction(0, 1)
[] - порожній list
{} - порожній dict
() - порожній tuple
'' - порожній str
b'' - порожній bytes
set() - порожній set
- порожній
range, якrange(0)
- об'єкти для яких
obj.__bool__() повертається False
obj.__len__() повертається 0
"Істинне" значення задовольнить перевірку, виконану ifабо while
твердженнями. Ми використовуємо "неправдивий" та "хибний", щоб диференціювати
boolзначення Trueта False.
Як andпрацює
Ми спираємося на питання OP як на півтону в дискусії про те, як працюють ці оператори в цих випадках.
Дано функцію з визначенням
def foo(*args):
...
Як повернути різницю між мінімальним і максимальним значенням у списку з нуля або більше аргументів?
Знайти мінімум і максимум просто (використовуйте вбудовані функції!). Єдина загроза тут полягає у правильній обробці кутового випадку, коли список аргументів може бути порожнім (наприклад, виклик foo()). Ми можемо зробити обидва в одному рядку завдяки andоператору:
def foo(*args):
return len(args) and max(args) - min(args)
foo(1, 2, 3, 4, 5)
# 4
foo()
# 0
Оскільки andвикористовується, другий вираз також повинен бути обчислений, якщо перший є True. Зверніть увагу, що якщо перший вираз оцінюється як істинний, повернене значення завжди є результатом другого виразу . Якщо перший вираз оцінено як помилковий, то повернутий результат є результатом першого виразу.
У наведеній вище функції, якщо fooотримує один або кілька аргументів, len(args)більше 0(позитивне число), тож результат повертається max(args) - min(args). Ото, якщо не передаються аргументи, len(args)в 0яких є Falsy, і 0повертається.
Зверніть увагу, що альтернативним способом написання цієї функції буде:
def foo(*args):
if not len(args):
return 0
return max(args) - min(args)
Або, коротше,
def foo(*args):
return 0 if not args else max(args) - min(args)
Звичайно, жодна з цих функцій не виконує жодної перевірки типу, тому, якщо ви повністю не довіряєте наданим введенням, не покладайтесь на простоту цих конструкцій.
Як orпрацює
Я пояснюю роботу " orподібним чином" на надуманому прикладі.
Дано функцію з визначенням
def foo(*args):
...
Як би ви завершили fooповернення всіх номерів 9000?
Тут ми orобробляємо кутовий футляр. Ми визначаємо fooяк:
def foo(*args):
return [x for x in args if x > 9000] or 'No number over 9000!'
foo(9004, 1, 2, 500)
# [9004]
foo(1, 2, 3, 4)
# 'No number over 9000!'
fooвиконує фільтрацію в списку, щоб зберегти всі номери 9000. Якщо такі числа існують, результатом розуміння списку є непорожній список, який є істинним, тому він повертається (коротке замикання в дії тут). Якщо таких цифр не існує, то результатом списку comp є те, []що є Falsy. Отже, другий вираз обчислюється (не пустий рядок) і повертається.
Використовуючи умовні умови, ми могли б переписати цю функцію як,
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
Як і раніше, ця структура є більш гнучкою з точки зору обробки помилок.
and(як іor) не обмежується роботою або поверненням булевих значень.