Access to the class that owns the decorated method from the decorator

I am writing a decorator for methods that should check parent methods (methods with the same name in the parents of the class in which I decorate).

Example (from the fourth example of PEP 318 ):

def returns(rtype): def check_returns(f): def new_f(*args, **kwds): result = f(*args, **kwds) assert isinstance(result, rtype), \ "return value %r does not match %s" % (result,rtype) return result new_f.func_name = f.func_name # here I want to reach the class owning the decorated method f, # it should give me the class A return new_f return check_returns class A(object): @returns(int) def compute(self, value): return value * 3 

So, I'm looking for code to enter instead of # here, I want ...

Thanks.

+4
source share
2 answers

As bobince said this , you cannot access the surrounding class, because at the time the decorator is called, the class does not exist yet. If you need access to the complete dictionary of a class and bases, you should consider metaclass :

__metaclass__

This variable can be any calling arguments for the name, base, and dict. When creating a class, the called is used instead of the built-in type ().

Basically, we will transform the returns decorator into something that just tells the metaclass to do some magic when building the class:

 class CheckedReturnType(object): def __init__(self, meth, rtype): self.meth = meth self.rtype = rtype def returns(rtype): def _inner(f): return CheckedReturnType(f, rtype) return _inner class BaseInspector(type): def __new__(mcs, name, bases, dct): for obj_name, obj in dct.iteritems(): if isinstance(obj, CheckedReturnType): # do your wrapping & checking here, base classes are in bases # reassign to dct return type.__new__(mcs, name, bases, dct) class A(object): __metaclass__ = BaseInspector @returns(int) def compute(self, value): return value * 3 

Remember that I have not tested this code, leave comments if I should update this.

There are several articles on metaclasses that are highly recommended by David Merz, which you might find interesting in this context.

+6
source

here I want to reach a class that owns the decorated method f

You cannot, because at the decoration point no class owns the f method.

 class A(object): @returns(int) def compute(self, value): return value * 3 

The same as saying:

 class A(object): pass @returns(int) def compute(self, value): return value*3 A.compute= compute 

Clearly, the returns() decorator is created before the function is assigned to the owner class.

Now, when you write a function for a class (either built-in, or explicitly like this), it becomes an unrelated method object. Now it has a link to its owner class, which you can get by saying:

 >>> A.compute.im_class <class '__main__.A'> 

So you can read f.im_class inside 'new_f, which is executed after the assignment, but not in the decorator itself.

(And even then it relies a bit ugly on the details of the CPython implementation if you don't need it. I'm not quite sure what you are trying to do, but things related to "get the owner class" are often done using metaclasses.)

+6
source

All Articles