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
) не обмежується роботою або поверненням булевих значень.