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 def
fed 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 def
fed 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)
7This 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:
When the function is declared in a header and implemented in a
.cpp
files. Can't do this with lambda.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:
When the function is overloaded/templated, and you want to conveniently pass it as an argument to a different function.
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
When Is It Better to Use a Struct Rather Than a Hash in Ruby
Cannot Install Aptana Plugin on Eclipse 4.2
Redirect the "Puts" Command Output to a Log File
Sidekiq List All Jobs [Queued + Running]
Rendering Partials/View in a Rake Task/Background Job/Model in Rails 4
Ruby Unable to Parse a CSV File: CSV::Malformedcsverror (Illegal Quoting in Line 1.)
$ Bundle Exec Rake Db:Reset Command Raising Couldn't Drop Db/Development.Sqlite3
How to Generate a Random Date in Ruby
Why Are Symbols Not Frozen Strings
App Pushed to Heroku Still Shows Standard Index Page
How to Reflect in the Database a New Belongs_To and Has_Many Relationship in Ruby on Rails
Switching Between Web and Touch Interfaces on Facebook Login Using Omniauth and Rails 3
Where/How to Include Helper Methods for Capybara Integration Tests