0
class warehouse:

    def __init__(self):
        self.A={}
        self.B={}   
        self.racks={'A':self.initialize(self.A),'B':self.initialize(self.B)}        

    def initialize(self,rack):
        shelf = dict([  (items,0) for items in range(1,6)  ])
        for x in range(3):
            rack[x+1]=shelf 
        return rack 

    def store(self,_id,owner_id,colour,weigth):
        import pdb;pdb.set_trace()          
        empty_position=self.empty_positions(self.store.__name__)[0]     
        self.racks[empty_position[0]][empty_position[1]][empty_position[2]]=   {'id':_id,'owner':owner_id,'colour':colour,'weigth':weigth}          
        print self.racks
    def empty_positions(self,name):

        store_list=[]
        for rack,shelfs in self.racks.iteritems():
            for shelf_number,shelf_objects in shelfs.iteritems():
                    store_list.append([rack,shelf_number])
                    for position,value in shelf_objects.iteritems():
                        if 0==value:
                            store_list.append([rack,shelf_number,position])

        return store_list

obj=warehouse()
val=obj.store(2,34,4,44)                

It is a class warehouse I want to create a dictionary which I did by the calling the init methods of the class.Now I want to store some values into the nested dictionary using same instance of class warehouse.When I call the obj.store(2,34,4,44).It updates the dictionary and gimme the result.

{'A': {1: {1: {'colour': 4, 'id': 2, 'owner': 34, 'weigth': 44},
           2: 0,
           3: 0,
           4: 0,
           5: 0},
       2: {1: {'colour': 4, 'id': 2, 'owner': 34, 'weigth': 44},
           2: 0,
           3: 0,
           4: 0,
           5: 0},
       3: {1: {'colour': 4, 'id': 2, 'owner': 34, 'weigth': 44},
           2: 0,
           3: 0,
           4: 0,
           5: 0}},
'B': {1: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0},
      2: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0},
      3: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}
     }
 }

But I was expecting :

{'A': {1: {1: {'colour': 4, 'id': 2, 'owner': 34, 'weigth': 44},
           2: 0,
           3: 0,
           4: 0,
           5: 0},
       2: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0},
       3: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}},
 'B': {1: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0},
       2: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0},
       3: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}
      }
 }

It sets the value in all the other nested dictionary of key 'A' and 1 I try to put PDB and debuge it, but it is showing the same result. But If I do this operation in teminal then I get the result what I was expecting.

Python 2.6.6 (r266:84292, Sep 15 2010, 15:52:39) 
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> d={'A': {1: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 2: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 3: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}}, 'B': {1: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 2: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 3: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}}}
>>> d['A'][1][1]={"some_key":"some_value",}
>>> d
{'A': {1: {1: {'some_key': 'some_value'}, 2: 0, 3: 0, 4: 0, 5: 0}, 2: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 3: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}}, 'B': {1: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 2: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}, 3: {1: 0, 2: 0, 3: 0, 4: 0, 5: 0}}}

I dont know maybe I am missing something, or there is something wrong that I am not able to catch up.I am using python 2.6.6 and tried this is 2.7.1 as well .

Mahmoud Aladdin
  • 536
  • 1
  • 3
  • 13
Nishant Kashyap
  • 819
  • 2
  • 15
  • 25

2 Answers2

4

When you do:

shelf = dict([  (items,0) for items in range(1,6)  ])
for x in range(3):
    rack[x+1]=shelf 

You are creating one shelf, then putting the same shelf in the rack 3 times. The shelves aren't copies, they're one and the same.

You need to create a new shelf each time:

def initialize(self, rack):
    for x in range(3):
        rack[x+1] = dict((items,0) for items in range(1,6))
    return rack

In python 2.7, using dictionary comprehensions, this can become:

def initialize(self, rack):
    rack.update({
        x + 1 : { item : 0 for item in range(1, 6) } for x in range(3)
    })
    return rack
Eric
  • 95,302
  • 53
  • 242
  • 374
  • I showed the result above what i am getting and what I actually expecting,I tried doing the same operation on terminal. it is working fine, but not on the script.The script is working u can run it . – Nishant Kashyap Sep 24 '12 at 21:41
  • I showed the solution above - did you read it? What you did on the terminal was _not_ the same operation. – Eric Sep 24 '12 at 21:41
  • I would still use `rack[x+1]` with the dict comprehension. The nested dict comprehension seems obfuscated to me – John La Rooy Sep 24 '12 at 21:45
  • @gnibbler: I have a hard time not overusing comprehensions. Heck, I even found a [python bug](http://stackoverflow.com/questions/12259251/strange-python-traceback-in-nested-comprehensions) related to them. – Eric Sep 24 '12 at 21:50
2

Your problem is in the initialize() method, specifically rack[x+1]=shelf:

def initialize(self,rack):
    shelf = dict([  (items,0) for items in range(1,6)  ])
    for x in range(3):
        rack[x+1]=shelf 
    return rack 

rack[x+1]=shelf may seem harmless, but it isn't. rack will contain multiple references to the same shelf object, which yields strange results:

>>> a = {1: 2}
>>> b = [a for i in range(3)]
>>> b
[{1: 2}, {1: 2}, {1: 2}]
>>> b[0][1] = 3
>>> b
[{1: 3}, {1: 3}, {1: 3}]

Notice how all of the references to that single instance of a were affected when I changed one. They all point to the same object.

To fix this, change rack[x+1]=shelf to rack[x+1]=dict(shelf). Now, you're forcing Python to create a separate instance of shelf.

Blender
  • 289,723
  • 53
  • 439
  • 496