How can I avoid code repetition when overriding many properties in a child class in the same way?

Question:

I have a class in which I have properties that are returning arrays. For simplicity, let’s consider them constant:

import numpy as np

class MyClass:
    def __init__(self):
        self._time = np.array([0, 1, 2, 3])
        self._a = np.array([0, 1, 2, 3])
        self._b = np.array([4, 5, 6, 7])

    @property
    def a(self):
        return self._a

    @property
    def b(self):
        return self._b

Now, I have another class which is inheriting MyClass and it is interpolating the data, for example:

class Interpolator(MyClass):
    def __init__(self, vector):
        super().__init__()
        self._vector = np.array(vector)

    @property
    def a(self):
        return np.interp(self._vector, self._time, self._a)

    @property
    def b(self):
        return np.interp(self._vector, self._time, self._b)

Now, the issue is that I have 2 classes like MyClass and each one of them consists of ~30 properties.

Is there a way to override all properties without doing it one by one? I was having a look also at this solution but I am not sure if/how I can apply it to my problem.

Asked By: mauro

||

Answers:

Refactor your superclass to "proxy"/"trampoline" those properties via a function you can override in a subclass:

import numpy as np


class MyClass:
    def __init__(self):
        self._time = np.array([0, 1, 2, 3])
        self._a = np.array([0, 1, 2, 3])
        self._b = np.array([4, 5, 6, 7])

    def _get_property(self, v):
        return v

    @property
    def a(self):
        return self._get_property(self._a)

    @property
    def b(self):
        return self._get_property(self._b)


class Interpolator(MyClass):
    def __init__(self, vector):
        super().__init__()
        self._vector = np.array(vector)

    def _get_property(self, v):
        return np.interp(self._vector, self._time, v)
Answered By: AKX

A bit different approach, perhaps useful if you need to control which properties should actually be interpolatable

import numpy as np

def interpolatable(f):
    setattr(f, "interpolatable", True)
    return f

class MyClass:
    def __init__(self):
        self._time = np.array([0, 1, 2, 3])
        self._a = np.array([0, 1, 2, 3])
        self._b = np.array([4, 5, 6, 7])
        self._c = np.array([1,2,3,4])

    @property
    @interpolatable
    def a(self):
        return self._a

    @property
    @interpolatable
    def b(self):
        return self._b

    @property
    def c(self):
        return self._c


class Interpolator(MyClass):
    def __init__(self, vector):
        super().__init__()
        self._vector = np.array(vector)

    def _interpolate(self, target):
        print("Interpolating")
        return np.interp(self._vector, self._time, target)

    def __getattribute__(self, __name: str):
         v = super().__getattribute__(__name)
         a = getattr(type(self), __name, None)
         if type(a) == property and getattr(getattr(a, "fget", None), "interpolatable", False):
             return self._interpolate(v)
         return v

Answered By: Adam
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.