views:

297

answers:

5

Hi,

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!

+5  A: 

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.

Mark Rushakoff
Thank you for your time to write this one out!
Shyam
+1  A: 

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.

balpha
`new_list = map(lambda v: tuple(x.next() + y for x, y in zip(*(itertools.tee([expensive_op(v)]), (0, 1)))), old_list)` Not that you'd *ever* write anything like that, of course...
Ignacio Vazquez-Abrams
@Ignacio: Well, I *was* thinking about adding such an alternative to the answer. But even thinking about it hurt ;-)
balpha
`new_list = [(r, r+1) for r in (expensive_op(v) for v in old_list)]` - this is run once and the internal expression is lazy, so it gets evaluates and creates a tuple as needed - only the external list is actually created.
viraptor
@viraptor Good point; yes, that works. In the general case, though, there are uses of lambdas that cannot be replaced with list comprehensions and generator expressions (take `reduce` instead of `map` for example).
balpha
+1  A: 

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.

Duncan
You should get context in backtraces for lambdas, just like functions.
Glenn Maynard
You do, but in this case the stack trace was complaining that it couldn't pickle the lambda so the lambda wasn't actually part of the call stack. If it had been a local function I'd at least have had a name.You get a similar problem if you have the wrong arguments when trying to call something: the backtrace doesn't include any context for the callable that generated the TypeError.
Duncan
+2  A: 

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" => Proc.new { },
                "stop" => Proc.new { },
        },
}
responses["resp1"]["start"].call()

Python:

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

Ruby's mechanism for dealing with this is an ugly hack (it's not a real function), but at least it exists. JavaScript and Lua do this trivially; it's just a natural part of their syntax.

Also 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.

Glenn Maynard
..this is an ugly hack.. << do you have links that point this out?
Shyam
I gave an example of Ruby's second-class "inline function" mechanism.
Glenn Maynard
@Glenn, Ruby doesn't have functions at all, it only has methods. Ruby's anonymous functions (lambda functions) are actually functors. And there is nothing ugly or hack-like about them. It's simply a consequence of message-passing OO. Scala does the same thing, so does Smalltalk.
banister
@banister: It's abysmally ugly; first-class functions are a basic part of any modern high-level language. Comparing Ruby to Smalltalk and Scala definitely doesn't help its case.
Glenn Maynard
@Glenn, the definition of 'first-class function' on wikipedia is the following: "this means that the language supports constructing new functions during the execution of a program, storing them in data structures, passing them as arguments to other functions, and returning them as the values of other functions." Ruby's lambda's support exactly this. What appears to be bothering you is that Ruby's function objects require a 'call' to be invoked. This is just syntax and is required because Ruby doesn't allow () to be overloaded, as parentheses are optional. Anyway (continued in next post)
banister
(continued from previous post) This argument that Ruby does not have 'first-class' functions has been debated and discussed ad nauseum. The point of the matter is that Ruby doesn't have FUNCTIONS at all (due to it being a pure message-passing OO system) but nonetheless lambda functions and procs support ALL of the use-cases required for first-class-functionness, even if they are function 'objects' (functors) rather than 'real' functions.
banister
Also your syntax for defining an anonymous function in Ruby is very ugly, no one uses `Proc.new { }`, use `lamba { }` or `proc { }` instead.Your Ruby (1.9) code should be rewritten as:`responses = { "resp1" => { "start" => lambda { }, "stop" => lambda { }, },}responses["resp1"]["start"].()`
banister
@banister: If you don't see the ugliness of what Ruby does, then by all means, stick with Ruby. I'll use Python, where functions, methods and functors can all be passed around, stored and called in a consistent way. (And please don't complain about ad nauseum while posting *three paragraphs of comments* onto my answer.)
Glenn Maynard
@Glenn, I wasn't stating your commentary was ad nauseum, i was referring to the general commentary on Ruby in the Python community. And it's not that i don't see the 'ugliness of what Ruby does' it's more that you do not understand Ruby. I could comment on the ugliness of the mandatory 'self' parameter in Python, but i'd only do that if i didn't understand Python. They implement different object models. They are both good languages and reasonably consistent within their own paradigms.
banister
A: 

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

bdforbes