Where and When to Use Lambda

Where and when to use Lambda?

It's true, you don't need anonymous functions (or lambdas, or whatever you want to call them). But there are a lot of things you don't need. You don't need classes—just pass all the instance variables around to ordinary functions. Then

class Foo
attr_accessor :bar, :baz
def frob(x)
bar = baz*x
end
end

would become

def new_Foo(bar,baz)
[bar,baz]
end

def bar(foo)
foo[0]
end
# Other attribute accessors stripped for brevity's sake

def frob(foo,x)
foo[0] = foo[1]*x
end

Similarly, you don't need any loops except for loop...end with if and break. I could go on and on.1 But you want to program with classes in Ruby. You want to be able to use while loops, or maybe even array.each { |x| ... }, and you want to be able to use unless instead of if not.

Just like these features, anonymous functions are there to help you express things elegantly, concisely, and sensibly. Being able to write some_function(lambda { |x,y| x + f(y) }) is much nicer than having to write

def temp(x,y)
x + f(y)
end
some_function temp

It's much bulkier to have to break off the flow of code to write out a deffed function, which then has to be given a useless name, when it's just as clear to write the operation in-line. It's true that there's nowhere you must use a lambda, but there are lots of places I'd much rather use a lambda.

Ruby solves a lot of the lambda-using cases with blocks: all the functions like each, map, and open which can take a block as an argument are basically taking a special-cased anonymous function. array.map { |x| f(x) + g(x) } is the same as array.map(&lambda { |x| f(x) + g(x) }) (where the & just makes the lambda "special" in the same way that the bare block is). Again, you could write out a separate deffed function every time—but why would you want to?

Languages other than Ruby which support that style of programming don't have blocks, but often support a lighter-weight lambda syntax, such as Haskell's \x -> f x + g x, or C#'s x => f(x) + g(x);2. Any time I have a function which needs to take some abstract behavior, such as map, or each, or on_clicked, I'm going to be thankful for the ability to pass in a lambda instead of a named function, because it's just that much easier. Eventually, you stop thinking of them as somehow special—they're about as exciting as literal syntax for arrays instead of empty().append(1).append(2).append(3). Just another useful part of the language.


1: In the degenerate case, you really only need eight instructions: +-<>[].,. <> move an imaginary "pointer" along an array; +- increment and decrement the integer in the current cell; [] perform a loop-while-non-zero; and ., do input and output. In fact, you really only need just one instruction, such as subleq a b c (subtract a from b and jump to c if the result is less than or equal to zero).

2: I've never actually used C#, so if that syntax is wrong, feel free to correct it.

How are lambdas useful?

Are you talking about lambda expressions? Like

lambda x: x**2 + 2*x - 5

Those things are actually quite useful. Python supports a style of programming called functional programming where you can pass functions to other functions to do stuff. Example:

mult3 = filter(lambda x: x % 3 == 0, [1, 2, 3, 4, 5, 6, 7, 8, 9])

sets mult3 to [3, 6, 9], those elements of the original list that are multiples of 3. This is shorter (and, one could argue, clearer) than

def filterfunc(x):
return x % 3 == 0
mult3 = filter(filterfunc, [1, 2, 3, 4, 5, 6, 7, 8, 9])

Of course, in this particular case, you could do the same thing as a list comprehension:

mult3 = [x for x in [1, 2, 3, 4, 5, 6, 7, 8, 9] if x % 3 == 0]

(or even as range(3,10,3)), but there are many other, more sophisticated use cases where you can't use a list comprehension and a lambda function may be the shortest way to write something out.

  • Returning a function from another function

      >>> def transform(n):
    ... return lambda x: x + n
    ...
    >>> f = transform(3)
    >>> f(4)
    7

    This is often used to create function wrappers, such as Python's decorators.

  • Combining elements of an iterable sequence with reduce()

      >>> reduce(lambda a, b: '{}, {}'.format(a, b), [1, 2, 3, 4, 5, 6, 7, 8, 9])
    '1, 2, 3, 4, 5, 6, 7, 8, 9'
  • Sorting by an alternate key

      >>> sorted([1, 2, 3, 4, 5, 6, 7, 8, 9], key=lambda x: abs(5-x))
    [5, 4, 6, 3, 7, 2, 8, 1, 9]

I use lambda functions on a regular basis. It took me a while to get used to them, but eventually I came to understand that they're a very valuable part of the language.

When is a lambda function better than defining?

lambda expressions are generally used to define anonymous functions where there is no need to bind the function to a (global) name. For instance, if you just need a function to pass as the key argument to sorted:

sorted(some_list, key=lambda x: x[2])

There are some people who think that the explicit assignment to a name for a short function looks better on one line than the implicit assignment performed by a def statement, but that's purely an aesthetics-based opinion with no effect on the actual code.

The biggest difference between the two is that def is a statement whose body can include arbitrary Python code, while lambda is an expression whose body must be a single expression which is implicitly returned. Given that restriction, it's usually more useful to use def, and many situations where lambda is useful are being handled by other features.

Although Python considers functions to be first-class objects, there are relatively few things you can actually do with them: you can call them, and store references to them. No other operations (such as composition or point-wise application—e.g., h=f+g meaning that h(x) = f(x) + g(x) for all x) are supported. If such operations were supported, then there would be more uses for expressions that create function objects.

Python : How to use lambda function to return a specific value?

Just use the expression you want to return before the if keyword:

df['B']=df['A'].apply(lambda x:'M' if 'M' in x else None)

The keys to understand this is that "lambda" will resolve a single expression, and return its value, and the inline " ... if ... else ..." construct in Python just evaluates to the first or the last part depending on the test expression.

If you were not using apply in a single column, but on the whole dataframe (if you'd need to check values in more than one column, for example), you have to pass the "axis=1" parameter to apply. In that case, though not needed, it would be nice to have an extra pair of parentheses around the lambda. Otherwise the burden falls on the readers of your code to determine if the "," separating the lambda body from the next argument is really a separator or part of the lambda:

df['B']=df.apply((lambda row:'M' if 'M' in row['A'] else None), axis=1)

When to not use lambdas over normal functions?

When not to use lambdas:

  1. When the function is declared in a header and implemented in a .cpp files. Can't do this with lambda.

  2. When the function is a template, and you want to be able to manually specify template arguments. Doing this with lambas requires an ugly syntax: foo.operator()<...>(...).

When to use lambdas:

  1. When the function is overloaded/templated, and you want to conveniently pass it as an argument to a different function.

  2. You want to avoid ADL.


Other than that, preferring regular functions over lambdas is just a convention.

If you want to go against this convention, you should be prepared to explain your reasoning.



Related Topics



Leave a reply



Submit