is it possible to see if a class has a decorator ?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Dec 6 06:32:50 EST 2010


On Mon, 06 Dec 2010 22:08:33 +1100, Ben Finney wrote:

> Stef Mientki <stef.mientki at gmail.com> writes:
> 
>> I would like to know if a class definition has a decorator,
> 
> I'm not sure what this question means.
> 
> Applying a decorator to a class definition produces a normal class.
> 
> Classes don't “have” decorators; classes can be returned by a decorator
> function, but AFAIK the resulting class doesn't “have” the decorator in
> any sense.

It seems to me that a class decorator is (usually) like a class factory, 
in that it returns a class; the difference being that it takes a pre-
existing class as argument, and (probably) modifies it in place, rather 
than creates a new class from scratch.

I say "usually" and "probably" because, of course, a class decorator can 
do *anything*. Even something pointless:


>>> def decorator(cls):
...     return 1
...
>>> @decorator
... class K:
...     pass
...
>>> K
1



>> is that possible ?
> 
> The return value of a decorator isn't special in any way, AFAIK.
> 
> Any function can return a class object or a function object, and any
> function can be used as a decorator.

[pedant]
Any callable can be a decorator, provided it has an appropriate calling 
signature. But you knew that :)
[/pedant]


> The only thing that makes a function a decorator is how it is used in
> the code; but it doesn't leave a trace that I know of.

Function decorators can, because they usually wrap the input function in 
a closure, which is detectable:

>>> def decorator(func):
...     def inner():
...             return func("spam")
...     return inner
...
>>>
>>> @decorator
... def ham(s):
...     return s.upper()
...
>>> ham.__closure__
(<cell at 0xb7b76cec: function object at 0xb7b7f36c>,)
>>>
>>> def cheese(s):  # no decorator
...     return s.upper()
...
>>> cheese.__closure__
>>>

But this is only a common practice, not a guarantee, because the 
decorating function can do anything.

I think that the only way to find out what was used to decorate a class, 
or a function, is for the decorator itself to leave some sort of mark on 
the wrapped class/function. Perhaps by adding itself to the wrapped 
object as an attribute:

def decorate(cls):
    cls._decorated_by = decorate


-- 
Steven



More information about the Python-list mailing list