
Just one more opinion here, but I'm with Bob on this one. Sure, many of the uses I envision are "declarative" in the sense that they just associate metadata with the function. But many other uses I envision would alter the function's behavior.
I'm really curious what these uses might be. Folks keep saying this kind of thing, but when you dig in IMHO most of these actually seem to be design-time things, statements *about* the intent or use of the function (relative to the language runtime itself, e.g. classmethod and so forth, or relative to a framework, such as registering a function, or relative to some tool, e.g. for extended documentation purposes or type-checking, etc.) rather than e.g. runtime modifications to its behavior. I wouldn't keep pushing on this except that I'm entirely puzzled about what these legitimate "runtime" applications might be that aren't already more easily and clearly accomplished with existing mechanisms: arguments, lexical scope, and higher-order functions. I'm all for decorations as a mechanism for declaring things *about* the function as above, but I'm at a loss re: rationale for "decorations" that do more than declaratively and immutably *decorate* the function. Given that my distinctions between declarative and imperative uses of decorators and design- vs. run-time seem to have confused more than they've illuminated, perhaps a series of questions, scenarios, and thoughts might help clarify the areas of my concern. (1) Does a function have access to its own decorators? I expect the answer here should be "yes." We should be careful, though, that this does not introduce a mutable container for state. We've already got one such thing: object instances. We don't need another. (2) Do decorators define literal constant values at design-time or do they define a scope of mutable bindings? The PEP gives this example: def mymethod(f) [attrs(versionadded="2.2", author="Guido van Rossum")]: ... That seems fine, but what about this: x = "Guido van Rossum" def mymethod(f) [attrs(versionadded="2.2", author=x)]: Danger, Will Robinson! ;-) Even worse: x = "Guido van Rossum" def mymethod(f) [attrs(versionadded="2.2", author=x)]: oldAuthor = someHandleToMyDecorators.atts.author someHandleToMyDecorators.atts.author = "Eric Idle" IMHO, the RHS of an "assignment" in a decorator should only be some value that can be known at "compile" time, which probably means it's either a reference to a singly-assigned constant value or a literal. If you allow arbitrary variables or attributes in decorators to be assigned, then you limit the utility of decorators for many of their intended purposes such as e.g. type-checking. Furthermore, if you can "assign" a decorator's attribute more than once --- particularly if the decorated thing (function, method, object, whatever) can access those bindings --- then you've simply re-invented objects with an alternate and idiosyncratic syntax. (3) Should it be possible to conditionally evaluate decorators based on run-time state? The following, IMHO, is truly scary and inhibits many of the intended uses of decorators. This shouldn't be legal, ever: if foo = 3: [someDecoratorThatModifiesBarsRuntimeBehavior] else: [someOtherDecorator] def bar(...): ... If you're going to do that, just use callables, nested scopes, first-order functions, currying, etc. jb