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?
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With