[Python-Dev] method decorators (PEP 318) (original) (raw)
Phillip J. Eby pje at telecommunity.com
Fri Mar 26 12:44:20 EST 2004
- Previous message: [Python-Dev] method decorators (PEP 318)
- Next message: [Python-Dev] method decorators (PEP 318)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
At 08:44 AM 3/26/04 -0800, Guido van Rossum wrote:
def foobar(self, arg): @author = AuthorInfo(author="GvR", version="1.0", copyright="GPL", ...) @deprecated = True
My only objection to that format, is that it looks like part of the function body. It might work if moved before the colon, though, and then it would need some sort of bracketing.
I find the mark-up in your example about the worst possible mark-up; in practice, these things can get quite voluminous (we're only restricting ourselves to a single item that fits on a line because we're used to giving minimal examples). I would hate it if something semantically significant like classmethod or synchronized had to compete for the user's attention with several lines of structured metadata.
I can see that. I can also see from Brad's comments that some people have a completely different idea of what "metadata" is than I do. I think of metadata as something that will be used to drive program behavior, whereas what I think you and Brad are calling metadata may be more like what I think of as "annotation". And I don't see an issue with having a separate syntax for annotation, I just don't think it's a replacement for program-controlling metadata.
A framework-supplied metaclass could easily be designed to look for function attributes set with this mechanism.
For that to be really practical, there's going to have to be at minimum a user-transparent way for metaclasses to be combined. It's hard today even for wizards.
(One could also imagine a metaclass-free hybrid approach where there's a transformer placed in the decorator list which looks for function attributes to guide its transformation.)
And yes, this could also be used to declare class and static methods (by putting something in the standard metaclass that looks for certain function attributes, e.g. @wrap=classmethod) but I still think that these "wrapper descriptors" are better served by a different syntax, one that is more integrated with the function signature.
Maybe so, although I'm still of the view (as are others) that it shouldn't break the symmetry of definition and invocation (i.e., 'def foo(...)' and 'foo(...)').
> Obviously, I'm not arguing that Python should look like Lisp. The > current decorator syntax patch is much easier to read than > wrapping an entire function definition in parentheses. But the > semantics that I think most people are asking for with decorators, > is the simple Lisp-like capability of applying transformations to a > function, but with a more Pythonic syntax. That is, one where flat > is better than nested, and readability counts. That is the use case > that decorators are intended to serve, IMO, and I believe that this > is what most other proponents of decorators are after as well.
I would like to see more examples of that use case that aren't classmethod and aren't mutually exclusing with most other examples. The PEP stops with the arg checker example, and that's not a very convincing one (because it's so clumsy for that particular goal).
Okay. A few multi-decorator idioms used in PEAK today, but rewritten using the patch syntax:
def childCountMonitor(self) [events.taskFactory, binding.Make]:
The 'events.taskFactory' means that this generator will be treated as an event-driven psuedo-thread, and will return an 'events.Task' object wrapping the generator-iterator. The 'binding.Make' means this attribute is a property whose value will be computed once, upon first reference to the attribute. Thus, using 'self.childCountMonitor' will return the "daemonic" pseudothread for this instance that monitors its child count, and it will begin running if it has not already done so.
def syntax(self) [binding.Make, binding.classAttr]:
The 'binding.Make' means that this attribute is a once-property as described above, but the 'binding.classAttr' means that it will have a value per class, rather than per-instance. In other words, the descriptor will be moved to the metaclass. (This does require support from the metaclass, to automatically create a new metaclass for the class where this decorator is used).
I haven't done an exhaustive search, but I believe these are the most common stacking decorators I use today. However, I would also note that PEAK inclines towards monolithic do-everything decorators with lots of keyword arguments, due to the current inconvenience of stacking them. For example, this is more likely the actual spelling today:
def childCountMonitor(self):
...
childCountMonitor = binding.Make(
events.taskFactory(childCountMonitor), uponAssembly=True
)
which would then read either:
def childCountMonitor(self) [
events.taskFactory, binding.Make(uponAssembly=True)
]:
or maybe even better, something like:
def childCountMonitor(self) [
events.taskFactory, binding.Make, binding.autoAssembled
]:
The uponAssembly flag indicates that the attribute should be constructed as soon as the component has become part of a complete application assembly. It might be nice to make this orthogonal to other decoration behaviors.
Anyway, taskFactory, Make, and classAttr are just a few of the decorators I use, and they get used independently quite a bit. They're just the ones that are most frequently stacked.
> Considering that both function attributes and decorators have the > same overhead today for use (i.e., put them at the end, no special > syntax available), that would suggest that the need/desire for > decorators is much greater than the need for mere metadata > annotation.
I'm not convinced. I expect that if we had good syntax for both, we would see more use of attributes than of decorators, except perhaps in meta-heavy frameworks like PEAK.
Fair enough. I'll certainly agree that using decorators today to supply attributes is easier than applying function attributes directly, in cases where either could be used to accomplish a need. And if there had been a good syntax for function attributes available, there would likely be several places where I'd have leveraged it in place of decorators, mostly to avoid the many duplicated keyword arguments among my current decorators.
I guess my main concern is that I don't want to see PEP 318 crippled by a syntax that only works (and then just barely!) for classmethod or another single-word decorator.
- Previous message: [Python-Dev] method decorators (PEP 318)
- Next message: [Python-Dev] method decorators (PEP 318)
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]