0

I am wondering if the following strategy is a proper/pythonic way to create a dynamic function within a method. The goal is to have a class that can calculate a value based on a complex model defined by FUN(), but I want to be able to change that model within a script without rewriting it, or creating a bunch of different types of classes (since this function is the only thing that I expect to change).

I also read in a response to this question that the way I have it structured may end up being slower? I intend to call setupFunction() 1 to 3 times a simulation (changing the model) and call FUN many thousands of times.

Pseudocode...

class MyClass:
 def __init__(self, model = 'A'):
 self.setupFunction(model)
 # Other Class Stuff...
 def setupFunction(self, _model):
 if _model == 'A':
 def myFunc(x):
 # Do something with x, store in result
 return result
 else:
 def myFunc(x):
 # Do something different with x
 return result
 self.FUN = myFunc
 # Other Class Methods... some of which may call upon self.FUN
Model1 = MyClass('A')
Model2 = MyClass('B')
print(Model1.FUN(10))
print(Model2.FUN(10))

I have done some minor tests and the above seems to not break upon first glance. I know I could also do something similar by doing the following instead, but then it will have to test for the model on each call to FUN() and I will have many different model cases in the end:

class MyClass():
 def __init__(self, model = 'A'):
 def FUN(self, x):
 if self.model == 'A':
 # result = Stuff
 else:
 # result = Other Stuff
 return result

Still new to python, so thanks for any feedback!

asked Nov 3, 2015 at 18:16
2
  • 2
    Sure, this is fine. Functions and by extension methods are first class objects so you can assign them dynamically to your heart's content. It is up to you whether this makes your code more maintainable or just more confusing. But on the surface this is fine. Commented Nov 3, 2015 at 18:21
  • 1
    I'm voting to close this question as off-topic because it should be on the Stack Exchange Code Review site. Commented Nov 3, 2015 at 18:23

2 Answers 2

1

Not sure if I understood your question... What about something like this?

class MyClass():
 model_func = {'A' : funca, 'B' : funcb}
 def __init__(self, model):
 self.func = self.model_func[model]
 def funca():
 pass
 def funcb():
 pass
a = MyClass('A')
a.func()
b = MyClass('B')
b.func()

Other option might be something like this (better separation of concerns):

class Base(object):
 def __new__(cls, category, *arguments, **keywords):
 for subclass in Base.__subclasses__():
 if subclass.category == category:
 return super(cls, subclass).__new__(subclass, *arguments, **keywords)
 raise Exception, 'Category not supported!'
class ChildA(Base):
 category = 'A'
 def __init__(self, *arguments, **keywords):
 print 'Init for Category A', arguments, keywords
 def func(self):
 print 'func for Category A'
class ChildB(Base):
 category = 'B'
 def func(self):
 print 'func for Category B'
if __name__ == '__main__':
 a = Base('A')
 a.func()
 print type(a)
 b = Base('B')
 b.func()
 print type(b)
answered Nov 3, 2015 at 18:32
Sign up to request clarification or add additional context in comments.

3 Comments

I think this will end up being the best solution. Thank you!
got NameError: name 'funca' is not defined :-/
Just invert the order of funca and funcb. Put theme before model_func = {'A' : funca, 'B' : funcb}.
1

You can use __new__, to return different subclasses:

class MyClass():
 def __new__(self, model):
 cls = {'A': ClassA, 'B': ClassB}[model]
 return object.__new__(cls)
class ClassA(MyClass):
 def func():
 print("This is ClassA.func")
class ClassB(MyClass):
 def func():
 print("This is ClassB.func")
a = MyClass('A')
a.func()
b = MyClass('B')
b.func()
answered Nov 3, 2015 at 18:42

1 Comment

Thanks for your response!

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.