0

I'd like to call a function like this:

c = selion([{'title': "mytitle1",
             'my_field': 'value_1',
             'other': 'other_value'},
            {'title': "mytitle2",
             'my_field': 'value_2',
             'other': 'other_value'},])

The problem is that I would like 'my_field' to be sometimes a function to call back.

  • How to test, in the selion() function, if it's a string or a function and call it back?
  • if I want to pass in a function that is inside a class (something like self.calculate('client_x')), does it work out of the box like a normal function?

All in all I'd like this code to work:

class Test():
    def calculate_value(self):
        return 'test'

    c = self.selion([{'title': "mytitle1",
                      'my_field': self.calculate_value,
                      'other': 'other_value'},
                     {'title': "mytitle2",
                      'my_field': 'value_2',
                      'other': 'other_value'},])
Olivier Pons
  • 15,363
  • 26
  • 117
  • 213
  • 1
    Possible duplicate of [How do I detect whether a Python variable is a function?](https://stackoverflow.com/questions/624926/how-do-i-detect-whether-a-python-variable-is-a-function) – Iguananaut Jul 11 '18 at 15:16
  • I think isinstance() might work. – Rob Jul 11 '18 at 15:17
  • 2
    To clarify slightly: "a function that is inside a class" is called a *method*. If you use `callable()` as explained in the above link, it will work for callable object including methods and plain functions. – Iguananaut Jul 11 '18 at 15:17
  • you do not want the `()` after `self.calculate_value()` if you want to maintain the function and not just get None. You can test the value at that place with `type` – Easton Bornemeier Jul 11 '18 at 15:18
  • Does this work for Python2 and Python3? – Olivier Pons Jul 11 '18 at 15:18
  • @EastonBornemeier You're right, modified my question – Olivier Pons Jul 11 '18 at 15:19
  • How about you just always pass a callable and proceed to call it? If you originally had the string `'value_1'`, pass `lambda: 'value_1'`. – timgeb Jul 11 '18 at 15:19
  • Your example will work except that you will need to put `c = self.selion...` inside a method, otherwise `self` is not defined for that context. – Stuart Jul 11 '18 at 15:20
  • Also you may get better advice if you mention why you are trying to do this – Stuart Jul 11 '18 at 15:21

1 Answers1

1

Any of the following methods (process1, process2, or process3) would work to test if the field is a string or function. (Results will vary between the methods if the field is neither, e.g. an integer.)

These will work regardless of whether the field is a method or ordinary function. If you want to pass values to the function, however, that will be more complicated and you may want to organise the program differently.

class Test():
    def calculate_value(self):
        return 'test'

    def process1(self, x):
        """ Return x if it's a string or if not call it as a function """
        if isinstance(x, str):
            return x
        else:
            return x()

    def process2(self, x):
        """ Try to call x as a function and return the result, and if it doesn't work just return x """
        try:
            return x()
        except TypeError:
            return x

    def process3(self, x):
        """ Call x and return the result if it's callable, or if not just return x """
        if callable(x):
            return x()
        else:
            return x    

    def selion(self, data):
        # You can use self.process1, self.process2, or self.process3 here with
        # similar results
        return [self.process1(x['my_field']) for x in data]

    def do_stuff(self):
        c = self.selion([
            {
                'title': "mytitle1",
                'my_field': self.calculate_value,
                'other': 'other_value'
            },
            {
                'title': "mytitle2",
                'my_field': 'value_2',
                'other': 'other_value'
            },
        ])
        print(c)


test = Test()
test.do_stuff()
Stuart
  • 9,597
  • 1
  • 21
  • 30