On Sun, Oct 21, 2018 at 11:04:02PM +0200, Vladimir Filipović wrote:
Sometimes I need that callable to be something very simple, but it technically can't be a lambda because it has a statement in it. Defining it as a function forces me to give it not only a name, but a place too. Defining it just before the point of use is a natural location in one sense, but it makes the visual flow of the code worse, especially if I need to make several such steps (with different almost-lambdas) in a row.
From the standard library, I can actually think of Thread:
t1 = Thread(target=(lambda: counter += 1)) t2 = Thread(target=(lambda: sum += current_quux()))
Because they include statements, it needs to be:
def inc_counter(): counter += 1 t1 = Thread(target=inc_counter)
I don't think that's a real working example. py> counter = 0 py> def f(): ... counter += 1 ... py> f() Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 2, in f UnboundLocalError: local variable 'counter' referenced before assignment You need to declare counter and sum as global variables.
def update_sum(): sum += current_quux() t2 = Thread(target=update_sum)
From one popular library:
ws = websocket.WebSocketApp( url, on_open = (lambda ws: ws.send('subscribe'); conn_counter += 1), on_message = (lambda ws, msg: print(msg); msg_counter += 1))
Because they include statements, I again need to create those functions separately. Naming isn't so much a problem here, but it would turn kludgey if I needed to make several such calls in the same scope.
Its not the naming that would make it turn kludgy, but the use of global variables. If you had three websockets, would you want them all to share the same counter?
In any case, that's a common little frustration I often put up with. I think most other languages around Python's power level don't make that a problem.
To expand that argument a bit, lambdas have access to names in their immediate context that can be more of a pain with less-local functions. For a toy example:
[(lambda a: print(x + a)) for x in l]
You've fallen straight into the classic eager versus late binding of closures Gotcha. py> l = "spam eggs cheese aardvark".split() py> funcs = [(lambda a: print(x + a)) for x in l] py> for f in funcs: ... f("") ... aardvark aardvark aardvark aardvark If your intention was to demonstrate that multi-statement lambda would be a bug-magnet, you have done an excellent job :-) -- Steve