Nicolas Heimann
Nicolas Heimann

Reputation: 2581

How to use a decorator of a descriptor within a sub class

I was wondering if it possible to use a descriptor's decorator within a subclass.

class Descriptor():
    def __get__(self, instance_obj, objtype):
        raise Exception('ouch.')
    def decorate(self, f):
        print('decorate', f)
        return f

class A():
    my_attr = Descriptor()

class B():
    @my_attr.decorate
    def foo(self):
        print('hey, whatsup?')

# --> NameError: name 'my_attr' is not defined

This, of course, does not work since my_attr is undefined within the class definition of B.

Next I tried:

class B():
    @A.my_attr.decorate
    def foo(self):
        print('hey, whatsup?')

# --> Exception: ouch.

But, this approach invokes the descriptor __get__ method (where the instance_obj argument is None) and therefore the test Exception is fired. To access the decorator one could check for the instance_obj to be None an return the descriptor itself:

def __get__(self, instance_obj, objtype):
    if instance_obj is None:
        return self
    raise Exception('avoid this')
# --> decorate <function B.foo at 0x1021dd7b8>

It works! But is it plausible or is there a way to use the decorator within the class definition of B?

Upvotes: 5

Views: 939

Answers (1)

Martijn Pieters
Martijn Pieters

Reputation: 1124858

You can bypass the descriptor protocol altogether by retrieving the original object from the __dict__ mapping of the class:

A.__dict__['my_attr'].decorate

or cleaner, using vars():

vars(A)['my_attr'].decorate

However, the @ decorator syntax doesn't allow for subscriptions (you are given only simpler expressions with attribute access and a single call at the end), so you'd have to extract the dictionary first:

_A_my_attr = vars(A)['my_attr']
@_A_my_attr.decorate
def foo(self):
    # ...

However, unless you must capture the binding to a class, it is better to guard for the first argument to __get__ being None, as you discovered. This is exactly what property objects or functions do.

Upvotes: 4

Related Questions