Skip to content Skip to sidebar Skip to footer

Decorated Class Looses Acces To Its Attributes

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 fol

Solution 1:

You replaced Wrapper (which was a class) with the numericalmathfunction function object. That object doesn't have any of the class attributes, no.

In essence, the decorator does this:

classWrapper:
    # ...

Wrapper = NumericalMathFunctionDecorator(enableCache=True)(Wrapper)

so whatever the NumericalMathFunctionDecorator.__call__ method returns has now replaced the class; all references to Wrapper now reference that return value. And when you use the name Wrapper 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 via self (where the name lookup falls through to the class):

def __init__(self, where='home'):
    # Look forsetup configuration on 'Wrapper.configs[where]'.
    assert whereinself.places, "Only valid places are {}".format(self.places)
    self.__dict__.update(self.configs[where])

or

def__init__(self, where='home'):
    # Look for setup configuration on 'Wrapper.configs[where]'.
    cls = type(self)
    assert where in cls.places, "Only valid places are {}".format(cls.places)
    self.__dict__.update(cls.configs[where])

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:

def__call__(self, wrapper):
    defnumericalmathfunction(*args, **kwargs):
        func = specialfunction(wrapper(*args, **kwargs))
        """
        Do some setup to func with decorator arguments (e.g. enableCache)
        """
    numericalmathfunction.__wrapped__ = wrapper
    return numericalmathfunction

then use that reference in your __init__:

def__init__(self, where='home'):
    # Look for setup configuration on 'Wrapper.configs[where]'.
    cls = Wrapper
    whilehasattr(cls, '__wrapped__'):
        # remove any decorator layers to get to the original
        cls = cls.__wrapped__
    assert where in cls.places, "Only valid places are {}".format(cls.places)
    self.__dict__.update(cls.configs[where])

Post a Comment for "Decorated Class Looses Acces To Its Attributes"