(1) Does a function have access to its own decorators? I expect the answer here should be "yes."
I don't expect it to have access to the decorators, or even to the results of running them -- at least, not any more than I expect a function to have access to its own name. Conceptually,
def funcname(args): ...
is (almost) just a nicer way to write
In either case, a function object is created, and then "decorated" by binding a name to it. By analogy,
[wrap1()] def funcname(args): ...
means (almost) the same thing as
def funcname(args): ... funcname=wrap1(funcname)
Functions have no direct access to their own name, or their decorators, or even the affects of these decorators. Recursion works anyhow, because it looks the name up in the enclosing namespace. [The actual lookup may be short-circuited for efficiency.]
Decorators may add attributes, or even replace a function object entirely with something else. (In Barry's example, that something else then delegates back to the original object.) This doesn't mean that the function itself needs direct access to those attributes (that name), let alone to the decorators that created them.
(2) Do decorators define literal constant values at design-time or do they define a scope of mutable bindings?
Not either really. They do post-processing on a function (or class?) object before binding a name to it. This may or may not add attributes which may or may not be constants. It may or may not create a new object with new scopes.
That seems fine, but what about this:
x = "Guido van Rossum" def mymethod(f) [attrs(versionadded="2.2", author=x)]:
attrs is evaluated before the body of mymethod. Part of that evaluation is to properly bind its own author parameter. This resolves to a constant string, but I agree that using a dictionary could allow confusion -- in exactly the same way that mutable default arguments do today.
(3) Should it be possible to conditionally evaluate decorators based on run-time state?
At first I misunderstood. Conditional upon state when the function *definition* is evaluated, yes (though maybe not in the first version). But that is compile-time.
Conditional upon the call-time state -- no. The decorators themselves may well have been garbage collected by then.
Note that this does not forbid a decorator that *replaces* the original function with another callable object that happens to include conditional logic. The decorator itself would still be evaluated only once.