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_tasks
is 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