Ограничения Python по сравнению с Ruby: лямбда - PullRequest
6 голосов
/ 16 апреля 2010

Я просматривал некоторые страницы из WikiVS, которые я цитирую:

потому что лямбды в Python ограничены выражениями и не могут содержать заявления

Я хотел бы знать, что было бы хорошим примером (или более), где было бы это ограничение, предпочтительно по сравнению с языком Ruby. * +1007 *

Спасибо за ваши ответы, комментарии и отзывы!

Ответы [ 5 ]

12 голосов
/ 16 апреля 2010

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

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

Javascript:

responses = {
        "resp1": {
                "start": function() { ...  },
                "stop": function() { ... },
        },
        "resp2": {
                "start": function() { ...  },
                "stop": function() { ... },
        },
        ...
}
responses["resp1"]["start"]();

Lua:

responses = {
        resp1 = {
                start = function() ...  end;
                end = function() ...  end;
        };
        ...
}
responses.resp1.start();

Ruby:

responses = {
    "resp1" => {
        "start" => lambda { },
        "stop" => lambda { },
    },
}
responses["resp1"]["start"].call

Python:

def resp1_start():
    pass
def resp1_stop():
    pass
responses = {
    "resp1": {
        "start": resp1_start,
        "stop": resp1_stop,
    },
}
responses["resp1"]["start"]()

Обратите внимание, что в JavaScript и Lua нет лямбд: у них нет причин существовать, поскольку встроенные функции охватывают их гораздо более естественным и общим способом.

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

9 голосов
/ 16 апреля 2010

Наиболее часто встречающаяся ситуация с утверждениями - это, вероятно, оператор Python 2.X print.

Например,

say_hi = lambda name: "Hello " + name

работает как положено.

Но это не скомпилируется:

say_hi = lambda name: print "Hello " + name

потому что print не является надлежащей функцией в Python 2.

>>> say_hi = lambda name: "Hello " + name
>>> say_hi("Mark")
'Hello Mark'
>>> 
>>> say_hi = lambda name: print "Hello " + name
SyntaxError: invalid syntax

Остальные операторы, кроме print, можно найти в документации по Python онлайн :

simple_stmt ::=  expression_stmt
                 | assert_stmt
                 | assignment_stmt
                 | augmented_assignment_stmt
                 | pass_stmt
                 | del_stmt
                 | print_stmt
                 | return_stmt
                 | yield_stmt
                 | raise_stmt
                 | break_stmt
                 | continue_stmt
                 | import_stmt
                 | global_stmt
                 | exec_stmt

Вы можете попробовать остальные из них в REPL, если вы хотите, чтобы они потерпели неудачу:

>> assert(True)
>>> assert_lambda = lambda: assert(True)
SyntaxError: invalid syntax
>>> pass
>>> pass_lambda = lambda: pass
SyntaxError: invalid syntax

Я не уверен, что есть параллели между lambda ограничениями Python и proc или lambda в Ruby. В Ruby все является сообщением, поэтому у вас нет ключевых слов (хорошо, у вас есть ключевых слов , но у вас нет ключевых слов, которые выглядят как функции, подобные Python print). Вдобавок ко всему, нет легко ошибочных конструкций Ruby, которые потерпят неудачу в proc.

4 голосов
/ 16 апреля 2010

Пример, который иногда приходит ко мне, выглядит примерно так:

def convert(value):
    n = expensive_op(value)
    return (n, n + 1)

new_list = map(convert, old_list)

Несмотря на то, что он достаточно короткий и приятный, вы не можете преобразовать его в лямбду, не выполняя дважды команду expensive_op() (что, как следует из названия, не нужно), т.е.

new_list = map(lambda v: (expensive_op(v), expensive_op(v) + 1), old_list)

потому что присваивание (n = ...) является оператором.

2 голосов
/ 09 июля 2010

Вместо f=lambda s:pass вы можете сделать f=lambda s:None.

1 голос
/ 16 апреля 2010

lambda - это просто быстрый путь в Python для определения функции, которая возвращает простое выражение. Это не является каким-либо значимым ограничением. Если вам нужно больше, чем одно выражение, тогда просто используйте функцию: ничего вы не можете сделать с лямбда-выражением, которое вы не можете сделать с функцией.

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

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

Большим преимуществом использования именованной функции является, конечно, то, что когда она идет не так, вы получаете значимую трассировку стека. Вчера я укусил меня, когда получил трассировку стека, включающую лямбду, и никакой информации о том, что это была за лямбда.

...