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 = exp2 if exp1 else exp1
По аналогии,
exp1 or exp2
Должен (примерно) переводиться как:
r1 = exp1
if not r1:
r1 = exp2
Или, что то же самое,
r1 = exp1 if exp1 else 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)
foo()
Поскольку and
используется, второе выражение также должно быть вычислено, если первое True
. Обратите внимание: если первое выражение оценивается как истинное, возвращаемое значение всегда является результатом второго выражения . Если первое выражение оценивается как ложное, то возвращаемый результат является результатом первого выражения.
В приведенной выше функции If 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)
foo(1, 2, 3, 4)
foo
выполняет фильтрацию списка, чтобы сохранить все числа 9000
. Если такие числа существуют, результатом понимания списка является непустой список, который является Истинным, поэтому он возвращается (здесь происходит короткое замыкание). Если таких чисел не существует, то результатом составления списка будет []
Ложь. Итак, второе выражение теперь вычисляется (непустая строка) и возвращается.
Используя условные выражения, мы могли бы переписать эту функцию как,
def foo(*args):
r = [x for x in args if x > 9000]
if not r:
return 'No number over 9000!'
return r
Как и прежде, эта структура более гибкая с точки зрения обработки ошибок.
and
(а такжеor
) не ограничивается работой или возвратом логических значений.