Problem is, at the time the decorated
decorator is called, there is no object Blah
yet: the class object is built after the class body finishes executing. Simplest is to have decorated
stash the info "somewhere else", e.g. a function attribute, then a final pass (a class decorator or metaclass) reaps that info into the dictionary you desire.
Class decorators are simpler, but they don't get inherited (so they wouldn't come from a parent class), while metaclasses are inherited -- so if you insist on inheritance, a metaclass it will have to be. Simplest-first, with a class decorator and the "list" variant you have at the start of your Q rather than the "dict" variant you have later:
import inspect
def classdecorator(aclass):
decorated = []
for name, value in inspect.getmembers(aclass, inspect.ismethod):
if hasattr(value, '_decorated'):
decorated.append(name)
del value._decorated
aclass.decorated = decorated
return aclass
def decorated(afun):
afun._decorated = True
return afun
now,
@classdecorator
class Blah(object):
def one(self):
pass
@decorated
def two(self):
pass
gives you the Blah.decorated
list you request in the first part of your Q. Building a dict instead, as you request in the second part of your Q, just means changing decorated.append(name)
to decorated[name] = value
in the code above, and of course initializing decorated
in the class decorator to an empty dict rather than an empty list.
The metaclass variant would use the metaclass's __init__
to perform essentially the same post-processing after the class body is built -- a metaclass's __init__
gets a dict corresponding to the class body as its last argument (but you'll have to support inheritance yourself by appropriately dealing with any base class's analogous dict or list). So the metaclass approach is only "somewhat" more complex in practice than a class decorator, but conceptually it's felt to be much more difficult by most people. I'll give all the details for the metaclass if you need them, but I'd recommend sticking with the simpler class decorator if feasible.