Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Changing variables in multiple Python instances

Is there anyway to set the variables of all instances of a class at the same time? I've got a simplified example below:

class Object():
   def __init__(self):
       self.speed=0

instance0=Object()
instance1=Object()
instance2=Object()

#Object.speed=5 doesn't work of course

I can see it would be possible by adding all new instances to a list and iterating with isinstance(), but that's not desirable.

like image 266
UbunTom Avatar asked Feb 15 '12 22:02

UbunTom


People also ask

Can you change instance variables?

We can modify the value of the instance variable and assign a new value to it using the object reference. Note: When you change the instance variable's values of one object, the changes will not be reflected in the remaining objects because every object maintains a separate copy of the instance variable.

How do you assign multiple values to multiple variables in Python?

Python assigns values from right to left. When assigning multiple variables in a single line, different variable names are provided to the left of the assignment operator separated by a comma. The same goes for their respective values except they should be to the right of the assignment operator.

Can an object have more than one instance variable?

You already know that every object of that type can have different instance variable values.

How do you assign a value from one variable to another in Python?

The assignment operator, denoted by the “=” symbol, is the operator that is used to assign values to variables in Python. The line x=1 takes the known value, 1, and assigns that value to the variable with name “x”. After executing this line, this number will be stored into this variable.


1 Answers

One, simpler way, as the other answers put it, is to keep your attribute always as a class attribute. If it is set on the class body, and all write access to the attribute is via the class name, not an instance, that would work:

>>> class Object(object):
...     speed = 0
... 
>>> a = Object()
>>> b = Object()
>>> c = Object()
>>> 
>>> Object.speed = 5
>>> print a.speed
5
>>> 

However, if you ever set the attribute in a single instance doing it this way, the instance will have its own attribute and it will no longer change along with the other instance's:

>>> a.speed = 10
>>> Object.speed = 20
>>> print b.speed
20
>>> print a.speed
10
>>>

To overcome that, so that whenever the attribute is set in any instance, the class attribute itself is changed, the easier way is to have the object as a property - whose setter sets the class attribute instead:

class Object(object):
  _speed = 0
  @property
  def speed(self):
     return self.__class__._speed
  @speed.setter
  def speed(self, value):
     self.__class__._speed = value

Which works:

>>> 
>>> a = Object()
>>> b = Object()
>>> a.speed, b.speed
(0, 0)
>>> a.speed = 10
>>> a.speed, b.speed
(10, 10)

If you want to have independent attribute on the instances, but a special "set_all" method that would set the attribute in all instances, the way to go is to use the gc (Garbage Collector) module in standard librayr, to find and loop through all instances of the class, and set their instance attributes:

import gc

class Object(object):
    def __init__(self):
        self.speed = 0
        
    def set_all_speed(self, value):
        for instance in (obj for obj in gc.get_referrers(self.__class__):
            if isinstance(obj, self.__class__)):
                instance.speed = value

Which results in:

>>> a  =Object()
>>> b = Object()
>>> a.speed = 5
>>> b.speed = 10
>>> a.speed, b.speed
(5, 10)
>>> a.set_all_speed(20)
>>> a.speed, b.speed
(20, 20)
like image 92
jsbueno Avatar answered Sep 21 '22 13:09

jsbueno