0

I have seen some SO questions on making dictionaries which reference other parts of the same dictionary, but they all seem to be for static returns whenever the dictionary is first created. Is there a way to do this and stay dynamic?

Like so:

# Lets just say we have a barn with lots of animals
# and the pigs always eat 2 chickens, so there has to always be 2 chickens per pig
def make_barn():
    barn = {'pig': 0, 'cow': 0, 'chicken': 2*barn['pig']}
    return barn

Such that this:

barn['pig'] = 3
print barn

will print this:

{'pig':3, 'chicken':6, 'cow':0}

I tried using lambda functions or classes, but I am trying to pickle this as a HUGE dictionary for the purpose of passing in between processes in the multiprocessing module and that module didn't seem to like lambda or class structures.

Edit:

I tried using the answer given in a multiprocessing script and it appears that it isn't picklable:

import multiprocessing as mp
import random
from UserDict import UserDict

class Barn(UserDict):
    '''Barn automatically sets correct values for chickens.
    TBD: What to do if chickens get changed?'''
    def __init__(self, *args, **kw):
        UserDict.__init__(self, *args, **kw)
        pigs = self.data.get('pigs', None)
        if pigs is not None:
            self.data['chicken'] = pigs * 2

    def __setitem__(self, name, value):
        if name == 'pigs':
            self.data['chicken'] = value * 2
        self.data[name] = value

def count_animals(barn_record):
    for animal in random.randrange(0,10,1):
        barn_record['pigs'] = animal

# We need this to 'if __name__ == '__main__':' business to avoid having too many farms created continuously
# See here : https://stackoverflow.com/questions/1923706/multiprocessing-launching-too-many-instances-of-python-vm
if __name__ == '__main__':
    manager = mp.Manager()
    barn_record = manager.dict({'pigs':3,'cows':2})
    farm = mp.Process(target = count_animals, args=(manager,))
    farm.start()
    print barn_record
Community
  • 1
  • 1
chase
  • 3,592
  • 8
  • 37
  • 58
  • Why is this a dictionary and not a class? – Falmarri Nov 22 '13 at 22:23
  • I need it to be a data type that can be passed between processes easily in a pipe or through a manager. I actually made my whole program in an OO way, and then found out after it was done how incredibly slow and limited it was in use, so I am trying to make it multiprocessed now. My thought was to make a big dictionary (of dictionaries of dictionaries..etc.) that held the objects as keys and their properties as values, which I could alter and then use in the functions in the processes. If this is a bad idea, I am open to hear better designs, but that made the most sense to me so far. – chase Nov 22 '13 at 22:31
  • 1
    it's really not clear what you want here. it's trivial to write `barn = {'pig': 0, 'cow': 0}; barn['chicken'] = 2*barn['pig']` but presumably that's not what you want (and doesn't involve references anyway - the last entry is just zero)... – andrew cooke Nov 22 '13 at 23:08
  • I would like for it to be _dynamic_. Such that whenever you execute `barn['pig'] = 4`, then `print barn` will return `{'pig':4, 'cow':0, 'chicken':8}` I edited the question to help display this – chase Nov 22 '13 at 23:18

1 Answers1

3

Something like this perhaps? Tested with Python 2.7.

from UserDict import UserDict

class Barn(UserDict):
    '''Barn automatically sets correct values for chickens.
    TBD: What to do if chickens get changed?'''
    def __init__(self, *args, **kw):
        UserDict.__init__(self, *args, **kw)
        pigs = self.data.get('pigs', None)
        if pigs is not None:
            self.data['chicken'] = pigs * 2

    def __setitem__(self, name, value):
        if name == 'pigs':
            self.data['chicken'] = value * 2
        self.data[name] = value

if __name__ == '__main__':
    b = Barn(cows=1, pigs=2)
    print b
    b['pigs'] = 3
    print b

Running that should produce something like this:

{'cows': 1, 'chicken': 4, 'pigs': 2}
{'cows': 1, 'chicken': 6, 'pigs': 3}
Heikki Toivonen
  • 30,964
  • 11
  • 42
  • 44
  • Wow! I had not seen this in the documentation, that's fantastic. Hopefully it will pickle well, which would make sense since it is a dictionary. – chase Nov 23 '13 at 01:28