0

I need a Python decorator to add any number of named attributes to the decorated callable.

For example:

@attributes(foo='this', bar='exactly')  # <-- Implement this decorator!
def fun1(i):
   return i * 2

assert fun1.foo == 'this'
assert fun1.bar == 'exactly'

There exists a similar question, the answers to which deal with setting a single attribute with a fixed name. It doesn't apply here for setting an arbitrary number of attributes.

This doesn't work:

def attributes(**kwargs):
    def _inner(func):
        for k, v in kwargs.items():
            func.k = v
        return func
    return _inner
Asclepius
  • 57,944
  • 17
  • 167
  • 143

2 Answers2

2

Here is a function that implements the decorator:

def attributes(**kwargs):
    def _inner(func):
        for k, v in kwargs.items():
            setattr(func, k, v)
        return func
    return _inner

Alternatively, here is a class that implements the decorator:

class attributes:
    def __init__(self, **kwargs):
        self.kwargs = kwargs

    def __call__(self, func):
        for k, v in self.kwargs.items():
            setattr(func, k, v)
        return func
Asclepius
  • 57,944
  • 17
  • 167
  • 143
-1

func.k = v sets foo.k, not foo.foo or foo.bar. To set an attribute with a dynamic name, use setattr instead:

setattr(func, k, v)
Amadan
  • 191,408
  • 23
  • 240
  • 301