2010-09-29 4 views
8

Этот метод выполняет поиск первой группы словных символов (то есть: [a-zA-Z0-9_]), возвращая первую согласованную группу или None в случае сбоя.Операции «Boolean» в Python (т.е.: и/или операторы)

def test(str): 
    m = re.search(r'(\w+)', str) 
    if m: 
     return m.group(1) 
    return None 

Ту же функцию можно переписать в виде:

def test2(str): 
    m = re.search(r'(\w+)', str) 
    return m and m.group(1) 

Это работает так же, и документируется поведение; а this page ясно сказано:

Выражение x and y сначала вычисляет x; если x является ложным, возвращается его значение; в противном случае вычисляется y и возвращается полученное значение.

Однако, будучи булевым оператором (он даже говорит об этом в руководстве), я ожидал, что and вернет логическое значение. В результате я был astonished, когда узнал (как это работает).

Каковы другие варианты использования этого и/или что является обоснованием для этой довольно неинтуитивной реализации?

+1

На самом деле на нескольких языках это, конечно, предшествует Python. Это традиционно использовалось в качестве замены тернарного условного выражения, прежде чем мы имели выражения if if else, и его все еще можно использовать как оператор C# с нулевым коалесцированием '??'. Лично я бы старался избегать всех, кроме небольшого тривиального использования этого, как из-за потенциальных проблем с «ложными» значениями, так и потому, что «явный лучше, чем неявный». 'return m и m.group (1)' довольно хорошо, но если вы пойдете дальше этого, 'm не является None и ...' может быть более ясным. – bobince

ответ

5

Какие другие случаи использования этого,

Лаконичность (и, следовательно, ясность, как только вы привыкнете к нему, так как после того, как все это делает не жертву читаемость на всех! -) в любое время вам нужно кое-что проверить и либо использовать что-то, если это правда, или другое значение, если что-то неверно (это для and - обратный его or - и я очень намеренно избегая фактических ключевых слов или -подобный True и False, так как я говорю бит каждый объект, не только bool! -).

Вертикальное пространство на любом экране компьютера ограничено, и, учитывая выбор, его лучше всего тратить на полезные средства чтения (docstrings, комментарии, стратегически размещенные пустые строки для разделения блоков ...), чем при повороте, скажем, линии, такие как:

inverses = [x and 1.0/x for x in values] 

в шесть таких как:

inverses = [] 
for x in values: 
    if x: 
     inverses.append(1.0/x) 
    else: 
     inverses.append(x) 

или более стесненных их варианты.

и/или что является обоснованием для этого довольно неинтуитивной реализации?

Далеко «неинтуитивными», новички регулярно были сбиты с толку тем, что некоторые языки (например, стандартный Pascal) сделал не указать порядок оценки и короткого замыкания характер and и or; одна из отличий между Turbo Pascal и языковым стандартом, которая в тот же день сделала Turbo самым популярным диалектом Pascal всех времен, была именно тем, что Turbo реализовала and и or, как это было раньше, и Python сделал это раньше. .).

+1

Разве это не должно быть 'x и 1.0/x for ...'? – NullUserException

+0

@Null, ** oops **, вы правы - видите, вы _do_ находите конструкцию читаемой, несмотря на мою ужасную опечатку! -) Tx, редактирование для исправления. –

+0

Совершенно без темы; есть! -) смайлик? – poke

0

Я не нашел это удивительным, и на самом деле ожидал, что он сработает, когда я изначально попробовал.

Хотя не все значения равны bools, обратите внимание, что все значения равны boolean - они представляют значение истины. (В Python значение bool - это значение, которое только представляет true или false.) Число 0 не является bool, но явно (на Python) имеет логическое значение False.

Другими словами, логический оператор and не всегда возвращают bool, но всегда возвращают логическое значение; тот, который представляет true или false, даже если он также имеет другую информацию, логически привязанную к нему (например, строку).

Возможно, это ретроактивное оправдание; Я не уверен, но в любом случае логично, что логические операторы Python ведут себя так же, как и они.


Когда его использовать?

В вашем примере test2 чувствует себя более ясным. Я могу сказать, что они оба делают одинаково: конструкция в test2 не усложняет понимание. Все остальные равны, более сжатый код в test2 - незначительно - более быстро понят. Тем не менее, это тривиальное различие, и я не предпочитаю либо достаточно, чтобы пересказывать что-либо.

Это может быть так же полезно и в других отношениях:

a = { 
    "b": a and a.val, 
    "c": b and b.val2, 
    "d": c and c.val3, 
} 

Это может быть переписано по-разному, но это понятно, просто и сжато.

Не за борт; «a() и b() или c()« в качестве замены «a()? b(): c()» являются опасными и запутанными, поскольку в итоге вы получите c(), если b() ложный. Если вы пишете тройственный оператор, используйте терминологический синтаксис, хотя это ужасно уродливо: b() if a() else c().

+0

Я бы сказал, что test2 действительно затрудняет понимание, если читатель не знаком с этой темой. Тот факт, что обсуждаемая тема говорит мне, что явное if/else более понятно. –

+1

@ Russell Borogove: для любого заданного бита синтаксиса есть кто-то, кто его не понимает, и все больше людей обсуждают его. Это элементарно в Python (и нескольких других языках, Python не придумал этого), и если вы не пишете учебный код, предназначенный для наименее общего знаменателя начинающих программистов, я думаю, что все в порядке. –

0

В основном a and b возвращает операнд, который имеет то же значение истины, что и целое выражение.

Это может показаться немного запутанным, но просто сделать это в вашей голове: Если a является False, то b больше не имеет значения (потому что False and anything всегда будет False), так что он может вернуться a сразу.

Но когда a является True, то только b вопросов, поэтому он возвращает b сразу, даже не глядя.

Это очень распространенная и очень простая в использовании оптимизация многих языков.

+0

Я знаю об оценке короткого замыкания, это просто возможность того, что это выражение имеет совершенно разные типы возврата, которые беспокоят меня. – NullUserException

+1

@NullUserException: Не совсем «совершенно». Булево эквивалентное значение одно и то же. –

3

Какие другие случаи использования этого,

No.

, что является обоснованием для этого достаточно неинтуитивными реализации?

"unintuitive"? В самом деле? Я бы не согласился.

Давайте подумаем.

«a и b» фальсифицировано, если a является ложным. Поэтому первое ложное значение достаточно для того, чтобы узнать ответ. Зачем нужно преобразовывать a в другой логический? Это уже неверно. Сколько еще ложных False? Точно так же верно, верно?

Значение a - при эквиваленте False - достаточно ложно, так что это значение всего выражения. Никакой дальнейшей конверсии или обработки. Готово.

Значение a равнозначно True, тогда значение b - это все, что требуется. Никакой дальнейшей конверсии или обработки. Зачем преобразовывать b в другой логический? Это ценность - это все, что нам нужно знать. Если это что-то вроде True, то это действительно так. Насколько точнее True?

Зачем создавать ложные дополнительные объекты?

Такой же анализ для или.

Зачем преобразовать в булевое? Это уже достаточно верно или достаточно ложно. Сколько еще Истина может получить?


Попробуйте это.

>>> False and 0 
False 
>>> True and 0 
0 
>>> (True and 0) == False 
True 

В то время как на самом деле (True and 0)0, он равен False. Это ложно - достаточно для всех практических целей.

Если это проблема, то bool(a and b) заставит явное преобразование.

+0

В некотором смысле это имеет смысл +1 – NullUserException

0

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

В большинстве языков возвращаемое значение активной функции определяется типом функции. Если он явно не перегружен. Предположим, что функция типа 'strlen' должна возвращать целое число, а не строку.

В линейных функциях, таких как основные артритные и логические функции (+ -/* | &!), Еще более сдержан, потому что они также имеют историю формальной математической теории позади них. (Подумайте обо всех аргументах о порядке операций для этих функций)

Для того чтобы фундаментальные функции возвращали что-либо, но их наиболее распространенный тип данных (логический или цифровой), следует классифицировать как целенаправленную обфускацию.

Практически в каждом общем языке '&' или '& &' или 'AND' является логической или булевой функцией.За кулисами компиляторы оптимизации могут использовать короткую режущую логику, как описано выше в LOGIC FLOW, но не модификацию DATA STRUCTURE (любой оптимизирующий компилятор, который изменил значение таким образом, считался бы сломанным), но если ожидается, что значение будет использоваться в переменной для дальнейшей обработки он должен быть в логическом или логическом типе, потому что это «формальный» для этих операторов в большинстве случаев.