Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calling functions by array index in Python

I have a bunch of functions in Python out1, out2, out3 etc. and would like to call them based on an integer I pass in.

def arryofPointersToFns (value):      #call outn where n = value 

Is there an easy way to do this?

like image 398
Dirk Avatar asked Apr 18 '11 19:04

Dirk


People also ask

Can I make an array of functions Python?

In Python, you can create new datatypes, called arrays using the NumPy package. NumPy arrays are optimized for numerical analyses and contain only a single data type. You first import NumPy and then use the array() function to create an array. The array() function takes a list as an input.

How do you call a function in Python?

Once we have defined a function, we can call it from another function, program, or even the Python prompt. To call a function we simply type the function name with appropriate parameters. >>> greet('Paul') Hello, Paul.

Does array have index Python?

Indexing using index arrays Numpy arrays can be indexed with other arrays or any other sequence with the exception of tuples. The last element is indexed by -1 second last by -2 and so on.


2 Answers

tl;dr: Write an out(n) function rather than out1(), out2(), ..., outN() and don't bother with this hack.

I cannot imagine a reasonable scenario where this question would come up in practice. Please reconsider the architecture of the problem; there is likely to be a much better way to do this (because storing them in a list implies there is nothing meaningful about the functions except the index; for example, I can only imagine that you'd want to do this if you were creating a bunch of dynamically-generated thunks where their temporal ordering matters, or something similar). Especially any novice users you are reading this answer, consider making a more general function that can handle everything, or associating to each function some more identifying information, or sticking it as part of a class, etc.

That said, this is how you'd do it.

myFuncs = [f0,f1,f2] myFuncs[2](...) #calls f2 

or

myFuncs = {'alice':f1, 'bob':f2} myFuncs['alice'](...) #calls f1 

this is just the following two steps in one step:

myFuncs = [f0,f1,f2] f = myFuncs[i] f(...) #calls fi 

or if you don't have a registry of functions 'myFunc' like the OP said above, you can use globals(), though it is extremely hackish form and to be avoided (unless you want those functions to be available in your module namespace, in which case maybe it's fine... but this is probably rarely the case, and you'd probably rather define those functions in a submodule then from mysubmodule import * them, which is in turn slightly frowned upon):

def fN(n):     return globals()['f'+str(n)]  def f2():     print("2 was called!")  fN(2)(...) #calls f2 

here are two other ideas (added after answer was accepted and first two comments):

You can also create a decorator like this:

>>> def makeRegistrar(): ...     registry = {} ...     def registrar(func): ...         registry[func.__name__] = func ...         return func  # normally a decorator returns a wrapped function,  ...                      # but here we return func unmodified, after registering it ...     registrar.all = registry ...     return registrar 

and use it like so:

>>> reg = makeRegistrar() >>> @reg ... def f1(a): ...  return a+1 ...  >>> @reg ... def f2(a,b): ...  return a+b ...  >>> reg.all {'f1': <function f1 at 0x7fc24c381958>, 'f2': <function f2 at 0x7fc24c3819e0>} 

then you can call reg.all['f1']. You could adapt the reg decorator to keep track of the indexing and do something like:

registry = [] index = int(re.regextofindthenumber(func.__name__)) if not index==len(registry):     raise Exception('Expected def f{} but got def f{}') else:     registry[index] = func 

Alternatively, to avoid globals(), you could define a class:

class Funcs(object):     def f1():         ...     def f2():         ...     def num(n):         [code goes here] 

If your number of functions is small, you could get away with ['f1','f2','f3'][i].

Of course without further information, all these suggestions are just ignoring the real problem: this situation should never come up, and is a possibly a sign of a serious architecture flaw, when you'd probably rather have something (to use your example) like:

# a possibly-better world def out(n):     # output to N, whatever that means 

rather than

# what you have now def out1():     # output to 1 def out2():     # output to 2 def outN(n):     # ??? 
like image 195
ninjagecko Avatar answered Sep 20 '22 20:09

ninjagecko


Actually, I have exactly this problem and it is quite realistic: I needed to display a table where each row requires a quite different method to compose the cell content. My solution was to create a class that returns an empty value, then subclass it and implement different value methods, then instantiate each subclass into an array, then call the instance's method depending on the row number. Global namespace polution is limited by making the subclasses inner to the table generator class. The code looks something like this:

class Table(object):     class Row(object):         def name(self):             return self.__class__.__name__     class Row1(Row):         def value(self):             return 'A'     class Row2(Row):         def value(self):             return 'B'     class Row3(Row):         def value(self):             return 'C'     def __init__(self):         self._rows = []         for row in self.Row.__subclasses__():             self._row.append(row())     def number_of_rows(self):         return len(self._rows)     def value(self,rownumber):         return self._rows[rownumber].value() 

Obviously, in a realistic example, each of the subclass value methods would be quite different. The 'name' method is included to indicate how to provide a row title, if needed, using the arbitrary name of the inner class. This approach also has the advantage that one can easily implement a suitable 'size' method. The rows will appear in the output in the same order they appear in the code, but this may be an advantage.

Caution: the above is not tested code, just a precis of my actual code laid out to illustrate an approach.

like image 26
hamiljf Avatar answered Sep 22 '22 20:09

hamiljf