I implemented a decorator that worked like a charm until I added attributes to the decorated class. When I instantiate the class, it cannot acces the calss attributes. Take the following minimal working example :
from module import specialfunction
class NumericalMathFunctionDecorator:
def __init__(self, enableCache=True):
self.enableCache = enableCache
def __call__(self, wrapper):
def numericalmathfunction(*args, **kwargs):
func = specialfunction(wrapper(*args, **kwargs))
"""
Do some setup to func with decorator arguments (e.g. enableCache)
"""
return numericalmathfunction
@NumericalMathFunctionDecorator(enableCache=True)
class Wrapper:
places = ['home', 'office']
configs = {
'home':
{
'attr1': 'path/at/home',
'attr2': 'jhdlt'
},
'office':
{
'attr1': 'path/at/office',
'attr2': 'sfgqs'
}
}
def __init__(self, where='home'):
# Look for setup configuration on 'Wrapper.configs[where]'.
assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
self.__dict__.update(Wrapper.configs[where])
def __call__(self, X):
"""Do stuff with X and return the result
"""
return X ** 2
model = Wrapper()
When I instantiate the Wrapper class (#1), I get the following error :
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-5-a99bd3d544a3> in <module>()
15 assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
16
---> 17 model = Wrapper()
<ipython-input-5-a99bd3d544a3> in numericalmathfunction(*args, **kwargs)
5 def __call__(self, wrapper):
6 def numericalmathfunction(*args, **kwargs):
----> 7 func = wrapper(*args, **kwargs)
8 return numericalmathfunction
9
<ipython-input-5-a99bd3d544a3> in __init__(self, where)
13 def __init__(self, where='home'):
14 # Look for setup configuration on 'Wrapper.configs[where]'.
---> 15 assert where in Wrapper.places, "Only valid places are {}".format(Wrapper.places)
16
17 model = Wrapper()
AttributeError: 'function' object has no attribute 'places'
I guess that with the decorator, Wrapper becomes a function that looses acces to its attributes...
Any ideas of how I can solve this ? Maybe there is a workaround
You replaced
Wrapper
(which was a class) with thenumericalmathfunction
function object. That object doesn't have any of the class attributes, no.In essence, the decorator does this:
so whatever the
NumericalMathFunctionDecorator.__call__
method returns has now replaced the class; all references toWrapper
now reference that return value. And when you use the nameWrapper
in the__init__
method, you are referencing that global, not the original class.You can still access the current class with
type(self)
, or just reference those attributes viaself
(where the name lookup falls through to the class):or
In both cases you can end up with referencing an attribute on a subclass if you ever did subclass
Wrapper
(which you cannot do in this case anyway as you would have to fish the class out of the decorator closure).Alternatively, you could store the original class as an attribute on the returned function:
then use that reference in your
__init__
: