Anonymous functions for decorators

I've been working with decorators to make a design by contract library. This has gotten me thinking about decorators and anonymous functions. The two use cases I'll target are callbacks and decorating descriptors. i.e. (from the twisted tutorial): class FingerProtocol(basic.LineReceiver): def lineReceived(self, user): self.factory.getUser(user ).addErrback(lambda _: "Internal error in server" ).addCallback(lambda m: (self.transport.write(m+"\r\n"), self.transport.loseConnection())) currently this can be modified to (ab)use a decorator: ... def lineReceived(self, user): @self.factory.getUser(user).addCallback def temp(_): return "Internal error in server" ... This is an abuse of decorators because it doesn't actually decorate the function temp, it registers it as a callback for the class FingerProtocol. And this use of decorators, which I mimic for my design by contract library. (Guido recently posted a patch on python-dev that would allow the property to be used in the following way): class C(object): x = property(doc="x coordinate") @x.setter def x(self, x): self.__x = x @x.getter def x(self): return self__x There was some concern voiced on the list about repeating the variable name both in the decorator and the function definition. In other languages, these use cases are handled by anonymous functions or blocks. Python also has an anonymous function, lambda, but it's limited to a single expression. There are parsing and readability issues with making lambda multi-line. My proposal would be to use a special syntax, perhaps a keyword, to allow decorators to take an anonymous function. @self.factory.getUser(user).addCallback def temp(_): return "Internal error in server" would become: @self.factory.getUser(user).addCallback do (_): return "Internal error in server" and: @x.setter def x(self, x): self.__x = x would become: @x.setter do (self, x): self.__x = x In general: @DECORATOR do (..args...): ..function would be the same as: def temp(..args..): ..function DECORATOR(temp) del temp The decorators should be stackable, as well so: @DEC2 @DEC1 do (..args..) ..function would be the same as: def temp(..args..): ..function DEC2(DEC1(temp)) del temp Other uses/abuses Perhaps this new 'do' block could be used to implement things like the following: @repeatUntilSuccess(times=10) do (): print "Attempting to connect." socket.connect() with repeatUntilSuccess implemented as: def repeatUntilSuccess(times=None): if times is None: def repeater(func): while True: try: func() break except Exception: continue else: def repeater(func): for i in range(times): try: func() break except Exception: continue return repeater @fork do (): time.sleep(10) print "This is done in another thread." thing.dostuff() with fork implemented as: def fork(func): t = threading.Thread(target=func) t.start() Open Issues: ~~~~~~~~~~~~ Doing a google search shows that the word 'do' is occasionally used as a function/method name. Same for synonyms act and perform. Reusing def would probably not be a good idea, because it could be easily confused with a normal decorator and function. This is still somewhat an abuse of the decorator syntax, it isn't adding annotations to the anonymous function, so it isn't really 'decorating' it. I do think it's better than using a function that returns None as a decorator. While scanning source, the 'do' keyword may be easily confused with def func. I'm not really sure what would work better, suggestions are welcome. Perhaps I'm going down the wrong path by reusing decorator syntax. Other possible keywords instead of 'do': anonymous, function, act, perform. I first thought of reusing the keyword lambda, but I think the semantics of lambda are too different to be used in this case. Similarly, the keyword with has different semantics, as well. Thanks, -- ===== --Ryan E. Freckleton

I don't think def temp(...) is so terrible. Perhaps it's slightly inelegant, but adding a new keyword just so decorator syntax can be used in a decidedly non-decoratorish way to save a small amount of typing doesn't seem like something that would be accepted. If we were adding anonymous functions, I should think we'd make them more powerful while we're at it; it would at least be good to have them be first-class expressions, so you could do: DECORATOR(def (...args...): ...function...) #or whatever the syntax for anonymous functions would end up being and all the other useful things that come with anonymous functions and closures. I think I suggested a while ago that we allow that syntax -- def (args): ...statements... -- to be used as an expression, and also allow it to span multiple lines like a normal Python function definitions, but I was told that this would complicate parsing of indentation. I'm not sure why that is, but I'm not familiar with the internals of Python's parser. In any case, you can currently do @DECORATOR def temp(...args...): ...function... (as you are already doing in your Twisted example) and all you'll end up with is a name called "temp" bound to None. Not too bad. I really don't think inhibiting the assignment of some Nones is worth a new keyword and such. On 25 Dec 2007, at 18:33, Ryan Freckleton wrote:

I don't think def temp(...) is so terrible. Perhaps it's slightly inelegant, but adding a new keyword just so decorator syntax can be used in a decidedly non-decoratorish way to save a small amount of typing doesn't seem like something that would be accepted. If we were adding anonymous functions, I should think we'd make them more powerful while we're at it; it would at least be good to have them be first-class expressions, so you could do: DECORATOR(def (...args...): ...function...) #or whatever the syntax for anonymous functions would end up being and all the other useful things that come with anonymous functions and closures. I think I suggested a while ago that we allow that syntax -- def (args): ...statements... -- to be used as an expression, and also allow it to span multiple lines like a normal Python function definitions, but I was told that this would complicate parsing of indentation. I'm not sure why that is, but I'm not familiar with the internals of Python's parser. In any case, you can currently do @DECORATOR def temp(...args...): ...function... (as you are already doing in your Twisted example) and all you'll end up with is a name called "temp" bound to None. Not too bad. I really don't think inhibiting the assignment of some Nones is worth a new keyword and such. On 25 Dec 2007, at 18:33, Ryan Freckleton wrote:
participants (2)
-
Adam Atlas
-
Ryan Freckleton