1

So this is more of a trivial problem of writing a clean Python3 code. Let's say I have a class function which can create many function types based on the user input.

import numpy as np

class functions(object):

    def __init__(self, typeOfFunction, amplitude, omega, start = None, stop = None,
                 pulsewidth = None):
        self.typeOfFunction = typeOfFunction
        self.amplitude = amplitude
        self.omega = omega
        self.period = 2 * np.pi/omega
        self.start = start
        self.stop = stop
        self.pulsewidth = pulsewidth

    def sine_function(self, t):
        func = self.amplitude * np.sin(self.omega*t)
        return func

    def cosine_function(self, t):
        func = self.amplitude * np.cos(self.omega*t)
        return func

    def unit_step_function(self, t):
        func = self.amplitude * np.where(t > self.start, 1, 0)
        return func

Now my question is let us say we want to write 3 other functions:

  • Differentiation
  • Integration
  • Evaluation at a given time.

Now my problem is that in each of these function I have to put conditions such as these:

    def evaluate_function(self, time):
        if(self.typeOfFunction == 'sine'):
            funcValue = self.sine_function(time)
        elif(self.typeOfFunction == 'cosine'):
            funcValue = self.cosine_function(time)
        elif(self.typeOfFunction == 'unit_step_function'):
            funcValue = self.unit_step_function(time)

I want to do it only once in the __init__ method and at subsequent steps just pass the arguments instead of writing if-else:

def __init__(self, typeOfFunction, amplitude, omega, start = None, stop = None,
                 pulsewidth = None):
        self.typeOfFunction = typeOfFunction
        self.amplitude = amplitude
        self.omega = omega
        self.period = 2 * np.pi/omega
        self.start = start
        self.stop = stop
        self.pulsewidth = pulsewidth

        #DO SOMETHING THAT MAKES THE TYPE OF FUNCTION EMBEDDED
         IN THE CLASS IN A CLASS VARIABLE

And then:

def evaluate_function(self, time):
      value = self.doSomething(time)
      return value

How can this be done? If duplicate question exists please inform me in the comments.

apaderno
  • 28,547
  • 16
  • 75
  • 90
DuttaA
  • 903
  • 4
  • 10
  • 24
  • 1
    You can either use polymorphism to have an abstract `Function` class and then child classes like `Sine` and `Cosine`, which have member functions like `evaluate` and `integrate`. — Or you have a *closure* which wraps the actual function. But I don't think that this is going to work as differentiation is different for all of them. — Use something like SymPy which gives you differentiation directly. Or perhaps something like Autograd. – Martin Ueding Feb 24 '19 at 09:12
  • Check if this: https://stackoverflow.com/questions/4246000/how-to-call-python-functions-dynamically the answer to your question – ozlevka Feb 24 '19 at 09:14
  • @MartinUeding SYmPy is problematic, I could not figure out the bug but for higher precision it is giving variable results for different runs. Its like you are clicking the run button and every-time and the graph is changing, even though you do not have a random function anywhere. – DuttaA Feb 24 '19 at 09:31

2 Answers2

2

You can use the method getattr(CLASS_OBJECT, METHOD_ORVARIABLE_NAME) like this:

method = getattr(self, self.typeOfFunction)

and then call method:

method()

or for short:

getattr(self, self.typeOfFunction)()

Also you can check if the attribute you are getting exist or not:

if hasattr(self, self.typeOfFunction):
    getattr(self, self.typeOfFunction)()
Abbas Dehghan
  • 381
  • 4
  • 12
2

I think you want a mapping with a dict.

Something like this:

class functions(object):

    def evaluate_function(self, which, time):
        mapping = {'sine': self.sine_function,
                   'cosine': self.cosine_function,
                   # ...more functions here...
                  }
        return mapping[which](time)

    # rest of class here...
gmds
  • 19,325
  • 4
  • 32
  • 58