3 ms·
Multi-Line Lambdas in Python Using the With Statement
- njharman 17y agoFirst I don't see how naming a function '_' translates into calling it a lambda. Also, i18n much? Doesn't like this def handle_click(self): foo = self.flim() if foo: self.flam(foo) onClick(handle_click) And thinks this mess is better with onClick(): def _(self): foo = self.flim() if foo: self.flam() My problems with 2nd include 1) it's ugly, convulted and I'd argue misusing with, 2) by no longer having a name for flimflamfunc you loose documentation, 3) hard to reuse flimflamfunc, 4) hard to decorate, mock, dynamically replace flimflamfunc. Author's main dislike about first code block is "we're required to define the function body before the place where it will be actually used." Which I think is preferable but accept that's my opinion. They're ways to solve that which are easier, cleaner, and more pythonic than author's proposed solution. def callback(onFoo): def inner(func): onFoo(func) return func return inner @callback(onClick) def handle_click(self): pass There might be good reasons for multi-line lambdas, but I don't see any presented here. And if we assume multi-line lambdas are awesome, this is not an acceptable implimentation.
- defunkt 17y agoTotally agree. I think, more importantly than being 'ugly' or hard to mock, your second example is hard to understand. It took me too long to realize it was identical to your first example.
- scott_s 17y agoTo be fair, I believe problems 2), 3), 4) and your preference to define the function before it's used would all apply to an in-language multiline lambda as well.
- abecedarius 17y agoAbout these problems point by point: 1) Agreed. I'd never want to see this technique in my programs. 2) What stops you from giving it a name? 3) Putting code inline is presumably a conscious decision not to extract it into a wider scope. 4) How's it hard to decorate? For mocking and dynamically replacing, again, that goes for any inline code. Objections 3 and 4 have to argue against functions appearing in non-global scopes in general.
- abecedarius 17y agoSeems like you can write code in this style, if that's the style you like, without the magical and error-prone stack/environment inspection. Like, this example: with bmap([1,2,3]) as foo: def _(x): return (float(x) + 1) / 2 print foo # [1.0, 1.5, 2.0] could be done with decorators: def flip(f, x): # from Haskell's standard library return lambda y: f(y, x) @flip(map, [1,2,3]) def result(x): return (float(x) + 1) / 2 print result # [1.0, 1.5, 2.0] though the way 'result' is bound is, er, unconventional.
- apgwoz 17y agoA while back I used a similar technique to build out a "sinatra"-esque way to declare handlers in python http://sigusr2.net/2009/Mar/04/dispatching-with-with.html http://sigusr2.net/2009/Mar/04/dispatching-with-with.html
- jcsalterego 17y agoSpeaking of Sinatra and Python, have you seen http://github.com/breily/juno http://github.com/breily/juno?
- apgwoz 17y agoI've not. While I'm a fan of decorators in practice, I'm not a fan of the syntax. Part of what makes Sinatra so interesting to me is the way you define your resources, which is what I was going for. I never actually built anything more than a small proof of concept demo, since ultimately the value of the technique is pretty minimal.
- llimllib 17y agoneat hack!
- jaekwon 17y agoThis is cool, I've always wondered whether Ruby blocks could be implemented in Python, and it looks like you can get there 99% of the way. You'd still need to implement a feature to check to see if the defined function is a generator, and do something different for generators.
- jaekwon 17y agonm. i must be confused.