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.
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)
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
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.
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)
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