Restrictons of Python compared to Ruby: lambda's

久未见 提交于 2019-11-29 20:35:30

问题


I was going over some pages from WikiVS, that I quote from:

because lambdas in Python are restricted to expressions and cannot contain statements

I would like to know what would be a good example (or more) where this restriction would be, preferably compared to the Ruby language.

Thank you for your answers, comments and feedback!


回答1:


I don't think you're really asking about lambdas, but inline functions.

This is genuinely one of Python's seriously annoying limitations: you can't define a function (a real function, not just an expression) inline; you have to give it a name. This is very frustrating, since every other modern scripting language does this and it's often very painful to have to move functions out-of-line. It's also frustrating because I have a feeling Python bytecode can represent this trivially--it's just the language syntax that can't.

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"]()

Note that JavaScript and Lua don't have lambdas: they have no reason to exist, since inline functions cover them in a much more natural and general way.

I'd probably rate this as the single most annoying day-to-day Python limitation.




回答2:


The most commonly encountered situation regarding statements is probably Python 2.X's print statement.

For example,

say_hi = lambda name: "Hello " + name

works as expected.

But this will not compile:

say_hi = lambda name: print "Hello " + name

because print is not a proper function in Python 2.

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

The rest of the statements besides print can be found in the Python documentation online:

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

You can try the rest of these out in the REPL if you want to see them fail:

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

I'm not sure what parallels there are between Python's lambda restrictions and Ruby's proc or lambda. In Ruby, everything is a message, so you don't have keywords (okay, you do have keywords, but you don't have keywords that appear to be functions like Python's print). Off the top of my head, there's no easily-mistaken Ruby constructs that will fail in a proc.




回答3:


An example that has sometimes come up with me is something like this:

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

new_list = map(convert, old_list)

Although it is short and sweet enough, you can't convert it to a lambda without having to run expensive_op() twice (which, as the name suggests, you don't want to), i.e. you would have to do

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

because assignment (n = ...) is a statement.




回答4:


Instead of f=lambda s:pass you can do f=lambda s:None.




回答5:


lambda is simply a shortcut way in Python to define a function that returns a simple expression. This isn't a restriction in any meaningful way. If you need more than a single expression then just use a function: there is nothing you can do with a lambda that you cannot do with a function.

The only disadvantages to using a function instead of a lambda are that the function has to be defined on 1 or more separate lines (so you may lose some locality compared to the lambda), and you have to invent a name for the function (but if you can't think of one then f generally works).

All the other reasons people think they have to use a lambda (such as accessing nested variables or generating lots of lambdas with separate default arguments) will work just as well with a function.

The big advantage of using a named function is of course that when it goes wrong you get a meaningful stack trace. I had that bite me yesterday when I got a stack trace involving a lambda and no context about which lambda it was.



来源:https://stackoverflow.com/questions/2654425/restrictons-of-python-compared-to-ruby-lambdas

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!