Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python: Adding to dict of one object in a list changes all dicts of every other object in the list

So Python isn't my strong suit and I've encountered what I view to be a strange issue. I've narrowed the problem down to a few lines of code, simplifying it to make asking this question easier. I have a list of objects, this object:

class FinalRecord():
     ruid = 0
     drugs = {}

I create them in the shell like this:

finalRecords = []
fr = FinalRecord()
fr.ruid = 7
finalRecords.append(fr)
fr2 = FinalRecord()
fr2.ruid = 10
finalRecords.append(fr2)

As soon as I want to change the drugs dict on one object, it changes it for the other one too

finalRecords[0].drugs["Avonex"] = "Found"

I print out this:

finalRecords[1].drugs

and it shows:

{'Avonex':'Found'}

When I'm expecting it to actually be empty. I know I'm not completely understand how Python is working with the objects, can anyone help me out here?

like image 743
Spencer Sutton Avatar asked Oct 27 '25 06:10

Spencer Sutton


2 Answers

The reason for this is because drugs is a class attribute. So if you change it for one object it will in fact change in others.

If you are looking to not have this behaviour, then you are looking for instance attributes. Set drugs in your __init__ like this:

class FinalRecord():
    def __init__(self):
        self.ruid = 0
        self.drugs = {}

Take note of the use of self, which is a reference to your object.

Here is some info on class vs instance attributes

So, full demo illustrating this behaviour:

>>> class FinalRecord():
...     def __init__(self):
...         self.ruid = 0
...         self.drugs = {}
...
>>> obj1 = FinalRecord()
>>> obj2 = FinalRecord()
>>> obj1.drugs['stuff'] = 2
>>> print(obj1.drugs)
{'stuff': 2}
>>> print(obj2.drugs)
{}
like image 200
idjaw Avatar answered Oct 28 '25 20:10

idjaw


You define drugs as a class attribute, not an instance attribute. Because of that, you are always modifying the same object. You should instead define drugs in the __init__ method. I would also suggest using ruid as an argument:

class FinalRecord():
    def __init__(self, ruid):
        self.ruid = ruid
        self.drugs = {}

It could then be used as this:

fr = FinalRecord(7)
finalRecords.append(fr)
fr2 = FinalRecord(10)
finalRecords.append(fr2)

Or more simply:

finalRecords.append(FinalRecord(7))
finalRecords.append(FinalRecord(10))
like image 42
zondo Avatar answered Oct 28 '25 19:10

zondo