Why don't flask signals work with lambdas?

Viewed 352

This works:

from flask import Flask, request_started

app = Flask(__name__)
app.debug = True

def echo(sender, **extra):
    return print('request_started')

request_started.connect(echo)

@app.route('/')
def index():
    return 'index page'

while this doesn't:

from flask import Flask, request_started

app = Flask(__name__)
app.debug = True

request_started.connect(lambda sender, **extra: print('request_started'))

@app.route('/')
def index():
    return 'index page'

Why is that?

the first outputs correctly while the lambda gives nothing i.e. no errors.

I'm using python 3.6

Apparently, it has nothing to do with the print function, I also tried this and it didn't work out.

request_started.connect(lambda sender, **extra: open('output', 'w').write('request_started\n'))

~ UPDATE ~

Now, this works and I'm confused !

echo = lambda sender, **extra: print('request_started')
request_started.connect(echo)
1 Answers

Flask signals are implemented using the blinker library: https://pythonhosted.org/blinker/index.html#blinker.base.Signal.connect

The signature of the connect function is:

 connect(receiver, sender=ANY, weak=True)

With the documentation saying the following about the weak parameter:

weak – If true, the Signal will hold a weakref to receiver and automatically disconnect when receiver goes out of scope or is garbage collected. Defaults to True

Since your first example uses the default parameter of True and there is no other reference to the lambda it is automatically disconnected again after the call request_started.connect(lambda sender, **extra: print('request_started')) is finished.

In the second version

echo = lambda sender, **extra: print('request_started')
request_started.connect(echo)

you keep a reference to the lambda in the variable echo so the signal is connected until echo goes out of scope (and is garbage collected)

Related