Lambda returns lambda in python

Very rarely do I come across some python code that uses an anonymous function that returns an anonymous function ...?

Unfortunately, I cannot find an example at hand, but usually it takes the form of the following:

g = lambda x,c: x**c lambda c: c+1 

Why would anyone do this? Maybe you can give an example that makes sense (I'm not sure that the one I made makes any sense).

Edit: Here is an example:

 swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])), f(y,a[x][0]),f(x,a[x][1])))() 
+8
function python anonymous
source share
7 answers

You can use this construct to perform currying:

 curry = lambda f, a: lambda x: f(a, x) 

You can use it like:

 >>> add = lambda x, y: x + y >>> add5 = curry(add, 5) >>> add5(3) 8 
+13
source share
 swap = lambda a,x,y:(lambda f=a.__setitem__:(f(x,(a[x],a[y])), f(y,a[x][0]),f(x,a[x][1])))() 

Have a look () at the end? The inner lambda is not coming back, her name is.

The function performs the equivalent

 def swap(a, x, y): a[x] = (a[x], a[y]) a[y] = a[x][0] a[x] = a[x][1] 

But suppose we want to do this in lambda. We cannot use appointments in lambda. However, we can call __setitem__ for the same effect.

 def swap(a, x, y): a.__setitem__(x, (a[x], a[y])) a.__setitem__(y, a[x][0]) a.__setitem__(x, a[x][1]) 

But for lambda we can have only one expression. But since these are function calls, we can wrap them in a tuple

 def swap(a, x, y): (a.__setitem__(x, (a[x], a[y])), a.__setitem__(y, a[x][0]), a.__setitem__(x, a[x][1])) 

However, all those __setitem__ pushing me, so let them go:

 def swap(a, x, y): f = a.__setitem__ (f(x, (a[x], a[y])), f(y, a[x][0]), f(x, a[x][1])) 

Dagnamit, I canโ€™t get away with adding another job! I know that it is permissible to use the default parameters.

 def swap(a, x, y): def inner(f = a.__setitem__): (f(x, (a[x], a[y])), f(y, a[x][0]), f(x, a[x][1])) inner() 

Good move on to lambdas:

 swap = lambda a, x, y: lambda f = a.__setitem__: (f(x, (a[x], a[y])), f(y, a[x][0]), f(x, a[x][1]))() 

Which brings us back to the original expression (plus / minus typos)

All this leads to the question: Why?

The function should have been implemented as

 def swap(a, x, y): a[x],a[y] = a[y],a[x] 

The original author has gone astray to use a lambda rather than a function. Maybe for some reason he does not like a nested function. I dont know. All I will say is its bad code. (if there is no mysterious excuse for this).

+2
source share

This may be useful for temporary placeholders. Suppose you have a factory decorator:

 @call_logger(log_arguments=True, log_return=False) def f(a, b): pass 

You can temporarily replace it

 call_logger = lambda *a, **kw: lambda f: f 

This can also be useful if indirectly returning a lambda:

 import collections collections.defaultdict(lambda: collections.defaultdict(lambda: collections.defaultdict(int))) 

It is also useful for creating callable factories in the Python console.

And just because something is possible does not mean that you should use it.

+1
source share

This can be used to pull out some common repetitive code (there are, of course, other ways to achieve this in python).

Perhaps you are writing a journal and you need to add a level to the journal line. You can write something like:

 import sys prefixer = lambda prefix: lambda message: sys.stderr.write(prefix + ":" + message + "\n") log_error = prefixer("ERROR") log_warning = prefixer("WARNING") log_info = prefixer("INFO") log_debug = prefixer("DEBUG") log_info("An informative message") log_error("Oh no, a fatal problem") 

This program displays

  INFO:An informative message ERROR:Oh no, a fatal problem 
+1
source share

I did something similar the other day to disable a test method in unittest package.

 disable = lambda fn : lambda *args, **kwargs: None @disable test_method(self): ... test code that I wanted to disable ... 

Easy to turn it back on later.

+1
source share

This is most often - at least in the code that I find, and what I write myself - used to "freeze" a variable with the value that it has at the point when the lambda function is created. Otherwise, the nonlocals variable refers to the variable in the area in which they exist, which can sometimes lead to undesirable results.

For example, if I want to create a list of ten functions, each of which will be a factor for a scalar from 0 to 9. It may be tempting to write it as follows:

 >>> a = [(lambda j: i * j) for i in range(10)] >>> a[9](10) 90 

Anyone who, if you want to use any of the other factorized functions, gets the same result:

 >>> a[1](10) 90 

This is because the variable "i" inside the lambda is not allowed when creating the lambda. Rather, Python stores the reference to "i" in the "for" expression - in the area that it created (this link is stored in the closure of the lambda function). When a lambda is executed, the variable is evaluated, and its value is final in that scope.

When you use two nested lambda, for example:

 >>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)] 

The variable "i" is evaluated as executing a "for" loop. The Itล› value is passed in "k" - and "k" is used as a non-local variable in the multiplier function, which we factorize. For each value, I will have a different instance of the enclosing lambda function and a different value for the variable "k".

Thus, one can achieve the original intention:

 >>> a = [(lambda k: (lambda j: k * j))(i) for i in range(10)] >>> a[1](10) 10 >>> a[9](10) 90 >>> 
0
source share

It can be used to achieve a continuation / trampling programming style,

See Continuation Style .

0
source share

Source: https://habr.com/ru/post/649853/


All Articles