#python
Понимаю, что в Python применются ленивые вычисления, но мне кажется это настоящие грабли. Вот реальный пример: (sqlalchemy_migrate) funcname = upgrade and "upgrade" or "downgrade" То есть в зависимости от значения upgrade (True или False), переменная получит соответствующее имя. С ходу довольно сложно понять, что вернет такое выражение. Кроме того, bool and str может вернуть как bool, так и str, в зависимости от того, чему равен bool. Считаете ли вы такой подход рациональным?
Ответы
Ответ 1
Насколько я понимаю, у Вас нет вопроса, как именно вычисляется выражение в примере, но все же напишу. Т.к. приоритет and и or одинаков, и эти операторы левоассоциативны, то upgrade and "upgrade" or "downgrade" эквивалентно (upgrade and "upgrade") or "downgrade" Первым вычисляем выражение в скобках, оно равно False если upgrade == False(1), или "upgrade", если upgrade == True(2). В итоге имеем (1) False or "downgrade" --> "downgrade" (2) "upgrade" or "downgrade" --> "upgrade" (т.к. "upgrade" - истинно) П.С. Лично мне именно эта строчка также кажется не слишком читаемой. Вообще, здесь явно напрашивается использование тернарного оператора, который имеется в Питоне, хотя и синтаксически отличается от тернарного оператора в большинстве других языков: funcname = "upgrade" if upgrade else "downgrade" Это всего на один символ длиннее, но бывают случаи, когда подобная запись действительно удобна и читаема: do_something() or do_something_else() do_something_else выполнится только в том случае, если do_something вернет False (например, что-то пошло не так). Это, фактически, стандартная идиома для языка perl, в Питоне я что-то подобное встречал значительно реже.Ответ 2
Понять, что вернет логическое выражение довольно таки несложно: a and b возвращает a, если a ложно, и b в противном случае. a or b возвращает a, если a истино, и b в противном случае. Следующие объекты считаются ложными: None False нулевые значения числовых типов (0, 0L, 0.0, 0j) пустые последовательности ('', [], ()) пустой словарь ({}) объект user-defined класса, реализующий метод __nonzero__, который возвращает 0 или False, или не реализующий метод __nonzero__, но реализующий метод __len__, возвращающий 0 Во всех остальных случаях объект считается истинным.Ответ 3
funcname = upgrade and "upgrade" or "downgrade" эквивалентно: funcname = "upgrade" if upgrade else "downgrade" Или (для полной ясности): if upgrade: funcname = "upgrade" else: funcname = "downgrade" В тех случаях когда используется динамическое выражение вместо "upgrade" константы, and-or выражение может сломаться, поэтому предпочительней всегда использовать if-else конструкцию в коде на современных версиях Питона, которые поддерживает эту конструкцию (Python 2.6+, Python 3). Пример, когда and-or ломается: >>> True and 0 or "broken" 'broken' >>> 0 if True else "works" 0 Чтобы понять какие Питон-объекты в if-условии эквивалентны True, see Truth Value Testing. Так называемое short-circuit evaluation достаточно распространено в программировании, поэтому следует научиться понимать подобные конструкции. Во всех случаях возвращаются сами объекты (а не их boolean значения): >>> "" and 1/0 '' Пустая строка возвращается потому что bool("") is False в Питоне. 1/0 не вычисляется (short-circuit) -- иначе бы ZeroDivisionError мы бы увидели.
Комментариев нет:
Отправить комментарий