Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Lambda use case confusion

Tags:

python

I've been playing around with Celery / Django. In their example celery.py file there is the following line

app.autodiscover_tasks(lambda: settings.INSTALLED_APPS, force=True)

Where lambda:settings.INSTALLED_APPS is the actual parameter for the formal parameter packages in autodiscover_tasks(). And settings.INSTALLED_APPS is a tuple.

autodiscover_tasks() then either calls the function it was passed or directly assigns the variable it was given in one of its first lines...

packages = packages() if callable(packages) else packages

So my question is. I just don't get why this was done this way. It seems very redundant. Why not just pass settings.INSTALLED_APPS as the tuple god wanted it to be. Why pass an anonymous function that calls it instead? What am I missing here?

like image 655
Andrew Schmitt Avatar asked May 05 '16 09:05

Andrew Schmitt


Video Answer


2 Answers

Since Celery is asyncrhonous it is not fixed that settings.Installed_Apps will not change while performing other computations, so wrapping it inside a lambda encapsulates it value as a reference until it gets called.

EDIT (adding an example as commented):

setting.INSTALLED_APPS = 10
app.autodiscover_tasks(settings.INSTALLED_APPS, force=True) #is called with installed_apps = 10, so it give you an output.

now think of this, while app.autodiscover_tasksis being called and its internall computations are made some other thing is being computed, and setting.INSTALLED_APPS now = 8, since you did use the variable, your call is using 10 instead of '8', but encapsulating it into the lambda (app.autodiscover_tasks(lambda: settings.INSTALLED_APPS, force=True)) it will get the value when he needs it, synchronizing with its actual value wich should be 8.

like image 139
Netwave Avatar answered Oct 20 '22 10:10

Netwave


Adding on to Daniel's answer, here's a rather minimal example to showcase "late evaluation" by passing a callable.

>>> def foo(arg):
...     return lambda: arg() if callable(arg) else arg

This is a function that returns another function in order to fake asynchronous execution.

Build two functions:

>>> foo_arg = 3
>>> foo1 = foo(foo_arg)
>>> foo2 = foo(lambda: foo_arg)

Change foo_arg after creation of foo1 and foo2:

>>> foo_arg = 4

Call the functions:

>>> foo1()
3
>>> foo2()
4

foo1 uses the old foo_arg it was constructed with, foo2 calls the anonymous function to get the current value of foo_arg.

like image 43
timgeb Avatar answered Oct 20 '22 11:10

timgeb