I have a decorator for an object method:
def wrapper(func): def _wrapper(self, *a, **kw): print(self.foo) return func(self, *a, **kw) return _wrapper class Bar: foo = 1 @wrapper def baz(self): print(2) # This works as expected :) In [2]: Bar().baz() 1 2
I want to add another level of wrapping around this to allow parameters:
def wrapper(bla): def _wrapper(func): def __wrapper(self, *a, **kw): print(self.foo + bla) return func(self, *a, **kw) return __wrapper return _wrapper class Bar: foo = 1 @wrapper(1) def baz(self): print(2) # which also works great In [4]: Bar().baz() 2 2
Now, what I want to be able to do is pass a self
attribute as a wrapper parameter, i.e. call it with something like this
class Bar: def __init__(self): self._foo = 1 @wrapper(self._foo) def baz(self): pass
I see 2 options:
- make
self._foo
global - don’t pass
self._foo
, and make the decorator accessself._foo
Both are bad. (global can be changed from another place without my knowledge, and making the decorator access self._...
means the decorator knows the class it operates on)
Is there a good way to do this?
Advertisement
Answer
This example works just fine (You can pick _foo
or _bar
) and the wrapper itself knows nothing of Bar
nor its members:
def wrapper(bla): def _wrapper(func): def __wrapper(self, *a, **kw): print(getattr(self, bla)) return func(self, *a, **kw) return __wrapper return _wrapper class Bar: def __init__(self): self._foo = 1 self._bar = 2 @wrapper("_bar") # pick _foo or _bar here def baz(self): pass Bar().baz()
Output: 2
The wrapper
decorator can be located in another module, or as part of a library and Bar
as the client will be unknown to the decorator.