¿Hay una manera de ejecutar un método para todas las instancias de una clase en python?

Código de ejemplo:

>>> class MyClass(object): def __init__(self, x, y): self.x = x self.y = y def power(self): print(self.x**self.y) def divide(self): print(self.x/self.y) >>> foo = MyClass(2, 3) >>> bar = MyClass(4, 7) >>> >>> foo.power() 8 >>> bar.divide() 0.5714285714285714 

Siempre que utilicé clases en Python anteriormente, simplemente ejecuté el método para cada instancia por separado (ver arriba). Me preguntaba si había una manera de ejecutar el mismo método para todas las instancias de esa clase a la vez, porque podría ser un poco molesto, si tienes 20 o más instancias. Estoy pensando en algo como esto:

 >>> allinstances.power() 8 16384 

¿Hay alguna forma de hacer esto?

No Usualmente. Sin embargo, podrías hacer que tu clase sea capaz de eso:

 GLOBAL_MYCLASS_LIST = [] class MyClass(object): def __init__(self, x, y): GLOBAL_MYCLASS_LIST.append(self) self.x = x self.y = y def power(self): print(self.x**self.y) def divide(self): print(self.x/self.y) a = MyClass(2, 3) b = MyClass(4, 7) all_powers = [i.power() for i in GLOBAL_MYCLASS_LIST] 

Por supuesto, también puede hacer eso sin integrarlo en la clase, lo que probablemente sea más limpio para la mayoría de los casos en los que podría tener diferentes conjuntos de MyClass :

 myclass_list = [] class MyClass(object): def __init__(self, x, y): self.x = x self.y = y def power(self): print(self.x**self.y) def divide(self): print(self.x/self.y) myclass_list.append(MyClass(2, 3)) myclass_list.append(MyClass(4, 7)) all_powers = [i.power() for i in myclass_list] 

Por supuesto. Coloque las instancias en una lista a medida que las crea, luego repita la iteración sobre la lista y llame al método en cada instancia. Además, debe cambiar sus métodos para devolver en lugar de imprimir sus resultados, ya que esto es mucho más flexible. De esa manera, puede almacenar los resultados en una lista, escribirlos en un archivo, hacer más cálculos con ellos o imprimirlos.

 instances = [MyClass(2, 3), MyClass(4, 7)] results = [x.power() for x in instances] 
 class MyClass(object): instancelist = [] def __init__(self, x, y): self.x = x self.y = y self.instancelist.append(self) def power(self): print(self.x ** self.y) def divide(self): print(self.x / self.y) foo = MyClass(2, 3) bar = MyClass(4, 7) [instance.power() for instance in MyClass.instancelist] 

saldrá:

 8 16384 

De esta manera, no necesita ninguna variable global o marcador de posición que se almacene fuera de la definición de clase.

Por tu pregunta, creo que también querrías un poco de dinamismo. Algo como a continuación podría ayudar:

He añadido una función llamada printBoth() para la demostración.

Nota: código de Python 2.x abajo

 class MyClass(object): def __init__(self, x, y): self.x = x self.y = y def power(self): print "power",self.x**self.y def divide(self): print "divide", self.x/self.y def printBoth(self): print "x: ", self.x print "y: ", self.y class Test: def __init__(self, items): self.items = items def __getattr__(self, key): def fn(): return [getattr(x,key)() for x in self.items] return fn foo = MyClass(2, 3) bar = MyClass(4, 7) t = Test([foo,bar]) t.power() t.divide() t.printBoth() 

Salida:

 power 8 power 16384 divide 0 divide 0 x: 2 y: 3 x: 4 y: 7 

Nota: el código se puede romper en muchas ocasiones, no es necesario realizar comprobaciones adicionales en la implementación real.


La parte importante está aquí:

 def __getattr__(self, key): def fn(): return [getattr(x,key)() for x in self.items] return fn 

La función anterior se invoca en cualquier llamada de función en la instancia de Test . Lo que se devuelve es una función que no toma argumentos. La función se ejecuta en todas las instancias e invoca la misma función en cada elemento de self.items (que es la lista de todas las instancias en las que desea invocar su función). Los resultados se devuelven como una lista.

Sólo tiene que utilizar un bucle:

 foo = MyClass(2, 3) bar = MyClass(4, 7) for i in [foo, bar]: i.power() 

Si no está seguro de que todas las instancias tengan el método, utilice una comprobación de hasattr :

 for i in list_of_instances: if hasattr(i, 'power'): i.power() 

Creo que todas las respuestas son válidas, dependiendo del caso de uso. Yo diría que si esta clase se usa en partes separadas de su aplicación / progtwig, no querrá depender de la GLOBAL_MYCLASS_LIST declarada en algún lugar anterior (como sugirió @amber). Querría estar seguro de que esta variable existe y declararla como una Variable de clase y tener el compute_all como un método de Clase o incluso como un método estático con @staticmethod decorator (que creo que es menos relevante para el caso de uso específico.

Una vez más, quisiera enfatizar que este es un caso de uso muy específico y no muy común. así que debes pensar en tu diseño antes de hacerlo y no utilizar las formas pythonicas más directas que se ofrecen en otras respuestas.

También me gustaría referirte a este bonito video de una conferencia de Pycon sobre las clases en python que hace un buen trabajo explicando esto (las cubiertas están aquí ).