Метка: логика

Короткое замыкание

Провод горит в розетке

Поговорим о логических операциях. Допустим у нас есть цепочка из or

if x() or y() or z():
    print('bingo!')

Чтобы print сработал, нужно, чтобы хотя бы один из трех вызовов давал бы True (или приводился к True). Что если x() сразу вернет True? Тогда, очевидно, все выражение будет равняться True в любом случае и независимо от того, что будет в y() и z(). Если смысл их вычислять? Нет! Python и не вычисляет. Тем самым достигается некоторая оптимизация, которая называется short circuiting (или короткое замыкание).

Это хорошо, только, если в оставшихся логических выражениях нет побочных эффектов, потому они не будут выполнены, если вычисление логического выражение будет остановлено. Давайте проверим:

def check(b):
    print('check.')
    return b

if True or check(True):
    print('ok.')  # ok.

if False or check(True):
    print('ok.')  # check. ok.

В первом случае check не работает, потому что первый операнд True уже предопределит судьбу выражения. А во втором случае – сработает, потому первый операнд False не дает определенности и нужно вычислить check().

Аналогично все с оператором and: как только первый операнд в цепочке вернет False, выполнение прекратиться. 

if True and False and check(True):
    ...  # не выполнится check

Встроенные функции all и any тоже используют короткое замыкание, то есть all перестает проверять на первом False, а any – на первом True.

all(check(i) for i in [1, 1, 0, 1, 1])  # выведет 3 check из 5
any(check(i) for i in [0, 1, 0, 0, 0])  # выведет 2 check из 5

Эту особенность стоит помнить. Лично я сталкивался с алгоритмом, где было что-то вроде:

while step(x, y, True) or step(x, y, False): ...

По задумке оба step должны выполнятся на каждой итерации, но из-за короткого замыкания второй из них иногда не выполнялся; алгоритм работал неверно.

Что если не нужно такое поведение?

Оказывается, что можно применять побитовые операторы «или» и «и» в логических выражениях, при этом каждый операнд будет вычисляться в любом случае. Цепочка вычисления не прервется, даже если результат уже очевиден. 

def check(b):
    print('check.')
    return b

check(False) & check(False)  # & – битовое и
check(True) | check(False)   # | - битовое или

В этом случае оба check сработают!

❗Внимание: есть подводные камни. Этот прием работает корректно только с булевыми типами! Если мы подставим целые числа, то результат может быть не тот, что ожидается. Яркий пример – это числа 1 и 2:

>>> bool(1 and 2)
True
>>> bool(1 & 2)
False
>>> 1 & 2
0

Поэтому, в логическом выражении, если тип операнда не булев, то его нужно привести. Недавний пример должен быть переписан так:

while bool(step(x, y, True)) | bool(step(x, y, False)):
    ...

Второй подводный камень: приоритет операторов | и & гораздо выше, чем у not, and и or. Так что, если миксуем их, то всегда ставим скобки: 

>>> not False or True
True
>>> not False | True
False
>>> (not False) | True
True

Не подумайте, что я призываю использовать побитовые операции вместо логических. Но в редких случаях это может быть оправдано.

Специально для канала @pyway. Подписывайтесь на мой канал в Телеграм @pyway 👈 

О познании

Написал в 2 часа ночи. Ночью я часто не могу уснуть, и подобные мысли вертятся в голове. На этот раз я схватил ноутбук и быстренько их изложил, а потом спокойно уснул. Пожалуй, буду и в преть так делать.

бывает, что одни говорят, что знают все, другие говорят, что не знают ничего.
и те, и другие по сути неправы.
разве можно сравнивать несравнимое?
разве может кто-то утверждать, что умнее (или знает больше) другого?
вряд ли это так.
да, я могу сказать, что я обладаю знаниями.
почему я могу это сказать?
потому что я могу это сказать. я обладаю этим знанием,
я могу выразить это на языке, могу записать, чтобы сохранить это, могу рассказать об этом другим голосом или письмом или в какой-то другой форме
могу ли я утверждать, что знаю все?
нет, ведь я не знаю и малой части всего.
могу ли я утверждать, что познал что-то до конца?
нет, потому что нельзя определить границ этого чего-то.
даже самое простое знание бесконечно глубоко в своей непознаваемости.
возьмем простой пример:
дважды два равно четыре.
почти любой человек это знает.
почти любой может объяснить это на пальцах или двигая яблоки, спички.
но если мне попадется человек, который скажет, что познал это знание полностью, и назовет это знание истиной, то я рассмеюсь.
почему?
потому что можно по-разному интерпретировать это.
в какой систиме исчисления эти числа?
а числа ли это? может, под этими знаками заключен иной смысл?
что значит операция умножения? не переопределил ли ее кто-то ранее?
что значит знак тождества?
любой математик (и в тоже время он не-матемтик, потому что не познал математику целиком) с легкостью опровергнет это тождество.
а почему вообще мы говорим о математике? можно анализировать это с точки зрения языков, истории и прочих наук.
и разговор этот может идти долго, но никогда не раскроет всех тайн дважды два четыре.
человек, который говорит, что ничего не знает, тоже не прав.
он уже знает, что ничего не знает, и даже может тебе это сказать.
а значит его утверждение неистинно, даже если он промолчит.
он может возразить: я не знаю ничего, кроме того, что я знаю, что не знаю ничего.
э, брат. ты строишь в уме и в речи своей такие сложные конструкции, так ты почти философ, а говоришь, что ничего не знаешь.
таким образом, я обладаю знаниями, как и любой другой.
но знаю ли я больше, чем кто-то другой?
нет, ведь мы обладаем разными знаниями, каждое из которые еще и неизмеримо.
каждый из нас знает великое количество вещей и сущностей, которые не знает другой.
и у каждой этой вещи или сущности есть огромное количество оттенков и нюанансов, подобно тому, сколько их у дважды два четыре.
а сравнивать бесконечности — дело гиблое.
пускай мы начали сравнивать свои знания;
и на каждое знание тратим сколько то времени;
тогда нам понадобится бесконечное количество времени на сравнение.
более того, сравнивая знания мы обмениваемся ими.
а знаешь ли ты, что трижды три девять?
теперь да, а знаешь ли ты, что семь минус пять равно два?
теперь да.
поэтому эксперимент сразу теряет смысл;
поэтому никто не умнее никого.
что же остается мне?
познавать!
но зачем познавать, когда я не познаю всего, я не познаю ничего полностью, я не смогу утверждать, что я умнее кого-то? зачем?
тебе незачем познать все, незачем мериться знаниями с кем-то.
могу ли я сказать, что познал все? — нет.
могу ли я сказать, что познал десятую часть всего? — нет.
могу ли я сказать, что познал сотую часть хотя бы десятой части? — тоже нет.
могу ли я сказать, что познал хотя бы одно знание про дважды два четыре целиком? — увы.
позвавай просто так то, что ты хочешь узнать.
важен сам процесс.
важно само движение, как изменения тебя и мира, мира тобой и тебя миром.
познание — как маленькая и в тоже время огромная разница знаний между мигом до и мигом после. познание это сейчас, каждый миг, прямо сейчас мы познаем.
может быть, я не хочу ничего познавать?
знание не может быть статично, и ты не можешь узнать до конца статично ли оно; пытась узнать это, ты будешь в вечном процессе познания.
ты познаешь всегда и везде;
даже сейчас,
даже если ты в темной комнате, или просто неспособен видеть;
даже если ты в тишине, или просто неспособен слышать;
даже если любое либо каждое из чувств не дает тебе знаний —
твой ум сам родит знания
мысли рождаются сами из тех знаний, что уже есть и оседают новыми знаниями.
нет момента, когда ты не чувствуешь и не думаешь.
скажут тебе: не думай о слоне. и ты будешь думать о слоне.
скажут тебе: не смотри. и ты повернешься, чтобы увидеть или представишь себе это.
ты чувствуешь, даже как течет время.
поэтому процесс познания и есть жизнь.
знаю ли я это неверняка? нет, но я пытаюсь узнать.
а значит, то, как ты получаешь знания и есть то, как ты проживаешь жизнь.