Is there a way to run a method for all instances of a class in python?

邮差的信 提交于 2019-12-06 04:54:29

问题


Example code:

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

Whenever I used classes in Python previously, I just ran the method for each instance separately (see above). I was just wondering If there was a way to run the same method for all the instances of that class at once, because it could get a bit annoying, if you have 20 or so instances. I'm thinking of something like this:

>>> allinstances.power()
8
16384

Is there a way of doing this?


回答1:


Not usually. You could make your class be capable of that, however:

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]

Of course, you could also do that without baking it into the class, which is probably cleaner for most cases where you might have different sets of MyClasses:

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]



回答2:


Sure. Put the instances in a list as you create them, then iterate over the list and call the method on each instance. Also, you should change your methods to return rather than print their results, as this is much more flexible. That way you can store the results in a list, write them to a file, do further calculations with them, or print them.

instances = [MyClass(2, 3), MyClass(4, 7)]
results   = [x.power() for x in instances]



回答3:


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]

will output:

8
16384

This way you do not need any global variables or placeholders that are stored outside of the class definition.




回答4:


From your question, I believe you would want a bit of dynamism too. Something like below could help:

I have added a function called printBoth() for demonstration.

Note: Python 2.x code below

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

Output:

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

Note: The code can break on many occasions, you neeed to perform additional checks in real implementation.


The important part is here:

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

The above function is invoked upon any function call on the Test instance. What is returned is function that takes no arguments. The function runs over all the instances, and invokes the same function on every item on self.items (which is the list of all the instances you want to invoke your function on). The results are returned as a list.




回答5:


Just use a loop:

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

If you are not sure that all instances will have the method, use a hasattr check:

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



回答6:


I think all answers are valid, depending on the use case. I would argue that if this class is used in seperated parts of your app/program you wouldn't want to depend on the GLOBAL_MYCLASS_LIST declared some where before (as @amber suggested). You would want to be sure this variable exists and declare it as a Class Variable and have the compute_all as a Class method or even as a static method with @staticmethod decorator (which I think is less relevant to the specific use case.

Again, I would stress that this is a very specific use case, and not very common. so you should think about your design before doing that and not using the more straight pythonic ways offered in other answers.

I would also like to refer you to this nice video of a Pycon lecture about classes in python which does a nice job of explaining this (The decks are here.)



来源:https://stackoverflow.com/questions/20020652/is-there-a-way-to-run-a-method-for-all-instances-of-a-class-in-python

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!