I have a rather odd scenario, and I just can't wrap my head around the proper solution. I'm working on a project that has multiple functions to perform certain operations:
- These functions are interconnected and need to be able to call each other (and inherit the parameters of their parent object).
- Each operation should be extensible and be able to have new functions added.
- There should be a default function for each operation.
Let me provide a simple example. Consider a class mymath
that can perform add
and multiply
. multiply
can be performed by simple multiplication or by iteratively calling the add
function (let's pretend that the +
operator doesn't exist in order to demonstrate the requirement that the functions need to be able to call one another). Here's an example using nested classes:
class addition_N:
def add(self, obj):
result = obj.param1 + obj.param2
return result
class multiply_N:
def multiply(self, obj):
return obj.param1 * obj.param2
def mult_loop(self, obj):
param1 = obj.param1
obj.param1 = 0
for i in range(param1):
obj.param1 = getattr(mymath.addition, 'add')(self, obj=obj)
return obj.param1
class mymath:
def __init__(self, param1, param2):
self.param1 = param1
self.param2 = param2
class multiply(multiply_N):
def __new__(cls, obj, func="multiply"):
return getattr(cls, func)(cls, obj=obj)
class addition(addition_N):
def __new__(cls, obj, func="add"):
return getattr(cls, func)(cls, obj=obj)
math = mymath(param1=2, param2=3)
mult = math.multiply(math, func='multiply')
math = mymath(param1=2, param2=3)
mult_loop = math.multiply(math, func='mult_loop')
math = mymath(param1=2, param2=3)
add = math.addition(math, func='add')
print(mult)
print(mult_loop)
print(add)
(Please don't slay me for using __new__
. My actual project code has some conditional statements in there to handle different scenarios. If you have suggestions for more Pythonic alternatives, let me know - I may be able to modify them to fit my needs).
The code is more easily extended, but I have a scoping issue. To solve the scoping issue, I pass the entire object, obj
, through to each function. This works, but it is messy. (Before suggesting that I should just copy the parameters of the parent function and instantiate new objects, my actual project is quite complex, has a LOT of parameters, and that would kill performance).
What am I missing, here? I feel like there is a simple solution right under my nose, but I've been staring at my code for so long that I can't figure it out.
EDIT 2020-05-04 I removed the eval
calls from my example. I didn't know about using getattr
. I'm still not sure how to handle the scoping issue.
EDIT 2020-05-05 I broke things out into sub-classes. This more closely aligns with my end goal. Users will be provided with the _N
classes to extend, and the code will be included in my main mymath
class at runtime.
I still can't figure out a good way to get around the scoping issue with obj
, though. Thoughts?