Llamando funciones por índice de matriz en Python

Tengo un montón de funciones en Python out1, out2, out3, etc. y me gustaría llamarlas en función de un número entero que pase.

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

¿Hay una forma fácil de hacer esto?

tl; dr: escribe una función out(n) lugar de out1(), out2(), ..., outN() y no te molestes con este truco.

No puedo imaginar un escenario razonable donde esta pregunta surja en la práctica. Por favor reconsidere la architecture del problema; es probable que haya una manera mucho mejor de hacer esto (porque almacenarlos en una lista implica que no hay nada significativo sobre las funciones excepto el índice; por ejemplo, solo puedo imaginar que querría hacer esto si estuviera creando un grupo de thunks generados dinámicamente donde importa su ordenamiento temporal, o algo similar). Especialmente a los usuarios novatos que están leyendo esta respuesta, considere hacer una función más general que pueda manejar todo, o asociar a cada función más información de identificación, o incluirla como parte de una clase, etc.

Dicho esto, así es como lo harías.

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

o

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

estos son solo los siguientes dos pasos en un paso:

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

o si no tiene un registro de funciones ‘myFunc’ como el OP mencionado anteriormente, puede usar globals (), aunque es una forma extremadamente intrincada y debe evitarse (a menos que desee que esas funciones estén disponibles en el espacio de nombres de su módulo) , en cuyo caso tal vez esté bien … pero este es probablemente el caso, y probablemente from mysubmodule import * definir esas funciones en un submódulo, entonces from mysubmodule import * , lo que a su vez está ligeramente mal visto):

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

Aquí hay otras dos ideas (agregadas después de que la respuesta fue aceptada y los dos primeros comentarios):

También puedes crear un decorador como este:

 >>> 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 

y usalo asi

 >>> reg = makeRegistrar() >>> @reg ... def f1(a): ... return a+1 ... >>> @reg ... def f2(a,b): ... return a+b ... >>> reg.all {'f1': , 'f2': } 

entonces puedes llamar a reg.all [‘f1’]. Puede adaptar el decorador de reg para realizar un seguimiento de la indexación y hacer algo como:

 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 

Alternativamente, para evitar globals() , podrías definir una clase:

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

Si su número de funciones es pequeño, puede salirse con ['f1','f2','f3'][i] .

Por supuesto, sin más información, todas estas sugerencias simplemente ignoran el problema real: esta situación nunca debería surgir, y es posiblemente una señal de una falla grave en la architecture, cuando probablemente prefiera tener algo (para usar su ejemplo) como :

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

más bien que

 # what you have now def out1(): # output to 1 def out2(): # output to 2 def outN(n): # ??? 

En realidad, tengo exactamente este problema y es bastante realista: necesitaba mostrar una tabla donde cada fila requiere un método bastante diferente para componer el contenido de la celda. Mi solución fue crear una clase que devuelva un valor vacío, luego subclase e implemente diferentes métodos de valor, luego cree una instancia de cada subclase en una matriz, luego llame al método de la instancia dependiendo del número de fila. La contaminación del espacio de nombres global se limita al hacer que las subclases sean internas a la clase del generador de tablas. El código se ve algo como esto:

 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() 

Obviamente, en un ejemplo realista, cada uno de los métodos de valor de subclase sería bastante diferente. El método ‘nombre’ se incluye para indicar cómo proporcionar un título de fila, si es necesario, utilizando el nombre arbitrario de la clase interna. Este enfoque también tiene la ventaja de que se puede implementar fácilmente un método de ‘tamaño’ adecuado. Las filas aparecerán en la salida en el mismo orden en que aparecen en el código, pero esto puede ser una ventaja.

Precaución: lo anterior no es un código probado, solo un resumen de mi código real diseñado para ilustrar un enfoque.

  def array(ar=[]): ar = np.array(ar) return ar