0

Suppose a Python class has different methods, and depending on what the user specifies, a different method is carried out in the main function calculate().

In the example below the user needs to specify the keyword argument 'methodOne' or 'methodTwo'. If no or an incorrect keyword is specified it should default to 'methodOne'.

class someClass(object):
    def __init__(self,method=None):
        methodList = ['methodOne','methodTwo']
        if method in methodList:
            self.chosenMethod = method
        else:
            self.chosenMethod = self.methodOne

    def methodOne(self):
        return 1

    def methodTwo(self):
        return 2

    def calculate(self):
        return self.chosenMethod()

The above clearly does not work since method is a string and not a function. How can I select self.methedOne() or self.methedOne() based on my keyword argument method? In principle the following works:

def __init__(self,method=None):
    if method == 'methodOne':
        self.chosenMethod = self.methodOne
    elif method == 'methodTwo':
        self.chosenMethod = self.methodTwo
    else:
        self.chosenMethod = self.methodOne

But if I have more than two methods this becomes rather ugly. Is there a way to do this similar to my original code?

Forzaa
  • 1,465
  • 4
  • 15
  • 27
  • http://stackoverflow.com/questions/3061/calling-a-function-of-a-module-from-a-string-with-the-functions-name-in-python – knh170 Mar 31 '16 at 09:19
  • The answers below already show the use of `getattr`. That approach is called reflection (or introspection): code that is inspecting its own structure. However, keep in mind that if `method` is a user-provided value, you'd do well to verify that it refers to one of the intended methods. After all, a user could enter `'calculate'`, or `'__class__'`, or the name of a non-callable attribute, causing all kinds of problems (and maybe even security risks, depending on context). – Pieter Witvoet Mar 31 '16 at 09:26
  • @PieterWitvoet The `if method in methodList` clause should prevent that. – Forzaa Mar 31 '16 at 09:41
  • @Forzaa: Very well. :) – Pieter Witvoet Mar 31 '16 at 09:49

2 Answers2

1

You can use getattr to get the actual method on the class object.

class someClass(object):
    def __init__(self,method=None):
        # store it with the object so we can access it later in calculate method
        self.method = method

    def methodOne(self):
        return 1

    def methodTwo(self):
        return 2

    def calculate(self):
        # get the actual method from the string here
        # if no such method exists then use methodOne instead
        return getattr(self, self.method, self.methodOne)()


> someClass('methodOne').calculate()
# 1

> someClass('methodTwo').calculate()
# 2
AKS
  • 18,983
  • 3
  • 43
  • 54
  • For the handling of the default case you could add `getattr(self, self.method, self.methodOne)()` – Wombatz Mar 31 '16 at 09:14
1

You could use getattr() for that purpose:

class someClass(object):
    def __init__(self,method=None):
        methodList = ['methodOne','methodTwo']
        if method in methodList:
            self.chosenMethod = method
        else:
            self.chosenMethod = self.methodOne

    def methodOne(self):
        return 1

    def methodTwo(self):
        return 2

    def calculate(self):
        return getattr(self, self.chosenMethod)()

x = someClass(method='methodOne')
print x.calculate()
>>> 1
xiº
  • 4,605
  • 3
  • 28
  • 39
  • Well, two almost identical answers at the same time. Guess this is the way then :). I'll accept yours since it is more in line with my code. – Forzaa Mar 31 '16 at 09:18