Search code examples
pythondecorator

Decorator for many properties in Python


Is it possible to write a decorator that creates many properties at once?

Like instead of writing

class Test:
    @property
    def a(self):
        return self.ref.a
    @property
    def b(self):
        return self.ref.b

I'd like to write

class Test:
    @properties("a", "b")
    def prop(self, name):
        return getattr(self.ref, name)

Is it possible? Do you recommend it?


Solution

  • Recall that a decorator

    @decorator(dec_args)
    def foo(args):
        pass
    

    is just syntactic sugar for writing

    def foo(args):
        pass
    foo = decorator(dec_args)(foo)
    

    So it is not possible for a method decorator to result in more than one method (or property, etc.) to be added to a class.

    An alternative might be a class decorator that injects the properties:

    def multi_property(prop, *names):
        def inner(cls):
            for name in names:
                setattr(cls, name, property(lambda self, name=name: prop(self, name)))
        return inner
    
    @multi_property(prop, 'a', 'b')
    class Test:
        pass
    

    However it'd usually be clearer to have each property present within the body of the class:

    a = forward_property('ref', 'a')
    b = forward_property('ref', 'b')
    

    where forward_property returns a property object as appropriate implementing the descriptor protocol. This is friendlier to documentation and other static analysis tools, as well as (usually) the reader.