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!

Community
  • 1
  • 1
Oniow
  • 307
  • 1
  • 12
  • 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. – RobertB Nov 03 '15 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. – Mad Physicist Nov 03 '15 at 18:23

2 Answers2

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)
RicLeal
  • 923
  • 9
  • 23
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()
Daniel
  • 42,087
  • 4
  • 55
  • 81