I have a decorator for an object method:
JavaScript
x
19
19
1
def wrapper(func):
2
def _wrapper(self, *a, **kw):
3
print(self.foo)
4
return func(self, *a, **kw)
5
return _wrapper
6
7
8
class Bar:
9
foo = 1
10
11
@wrapper
12
def baz(self):
13
print(2)
14
15
# This works as expected :)
16
In [2]: Bar().baz()
17
1
18
2
19
I want to add another level of wrapping around this to allow parameters:
JavaScript
1
20
20
1
def wrapper(bla):
2
def _wrapper(func):
3
def __wrapper(self, *a, **kw):
4
print(self.foo + bla)
5
return func(self, *a, **kw)
6
return __wrapper
7
return _wrapper
8
9
class Bar:
10
foo = 1
11
12
@wrapper(1)
13
def baz(self):
14
print(2)
15
16
# which also works great
17
In [4]: Bar().baz()
18
2
19
2
20
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
JavaScript
1
8
1
class Bar:
2
def __init__(self):
3
self._foo = 1
4
5
@wrapper(self._foo)
6
def baz(self):
7
pass
8
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:
JavaScript
1
20
20
1
def wrapper(bla):
2
def _wrapper(func):
3
def __wrapper(self, *a, **kw):
4
print(getattr(self, bla))
5
return func(self, *a, **kw)
6
return __wrapper
7
return _wrapper
8
9
class Bar:
10
def __init__(self):
11
self._foo = 1
12
self._bar = 2
13
14
@wrapper("_bar") # pick _foo or _bar here
15
def baz(self):
16
pass
17
18
19
Bar().baz()
20
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.