[Python-ideas] Proposal for new-style decorators
Christophe Schlick
cschlick at gmail.com
Wed Apr 27 03:42:22 CEST 2011
More information about the Python-ideas mailing list
Wed Apr 27 03:42:22 CEST 2011
- Previous message: [Python-ideas] Proposal for new-style decorators
- Next message: [Python-ideas] Proposal for new-style decorators
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Tue, Apr 26, 2011 at 11:20 PM, Terry Reedy <tjreedy at udel.edu> wrote: > > There is no special syntax for defining decorators -- just normal nested > function or class definition syntax. To put it another way, Python does not > have decorator objects. A decorator is simply a callable (function, class, > or class instance with __call__ method) applied to a object I totally agree with that. When defining a decorating function, you don't have any syntactic element that could explain the reader of your code that this function is actually a decorator. It is only when applied on a function with the @-syntax that the mechanism becomes visible (but this is not always done in the same file). This can be considered as a strength (any function with a correct input/output is likely to later become a decorator, even if the original author did not thought about it). However, according to my own little experience, more than 9 times out of 10, you perfectly now when writting such a function that it is actually a decorator. Using the proposed @decorator idiom (hey see, I haven't written "syntax" ;-) has at least the advantage to be explicit when you want to be explicit (besides the other features it provides), > What you are actually proposing is a meta-decorator (class) whose instances > can be used as decorators because the class has a __call__ instance method. > This sort of thing is a known alternative to the nested function pattern. Yes, I know that using callable class can be an alternative to the nested function pattern. In the pattern you talk about, the __init__ method gets the decorator arguments, the __call__ method serves as a decorator making function, and a third method is used to generate the actual decorating function. As a result, the boilerplate is approximatively the same as with the nested functions idiom. But this is not what is done here, because the end-user only writes a single function, not a whole class. In my proposal, the two nested functions are avoided by the fact that (1) the decorator attributes are automatically injected as meta-attributes (this is the role of the middle nested function in the standard idiom), and (2) the decorating function is in charge to pass the whole set of arguments to the undecorated function (this is the role of the inner nested function in the standard idiom). As far as I know, I haven't seen the combination of these two elements before. > Stick with the two real problems. > > 1. The double or triple nested function pattern has a lot of boilerplate and > can be difficult to learn. Hiding boilerplate in a class makes the use > pattern simpler and easier to learn. This is a real benefit. > 2. Introspection (more comments below), which your class also addresses. OK. I'll drop the arguments on nested function, and simply focus on boilerplate and introspection. That makes sense. >> def old_style_repeat_var(n=3, trace=True): >> """docstring for decorating function""" > > Actually, this is the docstring for the decorator making function. Also agree. I've written "decorating function" by symmetry with the new idiom, but I knew that I would get some remark here ;-) >> '@wraps(func)' copies the name and the docstring from the undecorated >> function to the decorated one, in order to get some useful piece of >> information when using 'help'. However, the signature of the function >> still comes from the decorated function, not the genuine one. > > I am not sure what you mean. If the two signatures are different, then one > must use the signature of the wrapper when calling it, not the signature of > the wrappee, which is perhaps what you mean by 'the genuine > one'. The problem of generic wrappers having generic signatures (*args, > **kwds) is endemic to using generic wrappers instead of special case > wrappers. What I wanted to say is that wraps only does half of the job: it correctly copies the name and the docstring, but the signature presented by the help function is still test(*args, **keys), while it should actually be test(first=0, last=0) according to the undecorated function. The alternative proposed by the new idiom is to copy nothing at all: it simply says "OK, 'test' is a decorated function. If you want to know more look at 'test.func' to get the info about the undecorated one, and at 'test.deco' to see what the decorator has done". I prefer such a raw-but-explicit approach rather than an automatic half-baked, half-bogus one. Moreover, it is not easy with the 'functools' module to provide introspection of the decorating function, once you've got the decorated one. >> The only >> solution is to inspect the undecorated function and then use 'exec' to >> generate a wrapper with a correct signature. This is basically what is >> done in the 'decorator' package (available at PyPI) written by Michele >> Simionato. There has been a lengthy discussion in python-dev (in 2009 >> I guess, but I can't find the archive right now) whether to include or >> not this package in the standard library. > > The other solution is to not use a generic wrappers with generic signatures > but to write specific wrappers with the actual signature, which people did, > for instance, before functools and partial() were added to Python. Right again, but this overweights the boilerplate even more compared to the '@wraps' decorator, no? > I second the other recommendations to make your proposal > available on the cookbook site, etc. That sounds good... Thanks a lot, Terry!
- Previous message: [Python-ideas] Proposal for new-style decorators
- Next message: [Python-ideas] Proposal for new-style decorators
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Python-ideas mailing list