Search code examples
pythonobjectcopyshareddeep-copy

Python Two Dictionaries within another Dictionary within another Dictionary


I'm trying to create a structure that would lend itself nicely to parse log files. I first tried setting up dictionaries as class objects, but that doesn't work since I made them class attributes.

I'm now trying the following to set up my structure:

#!/usr/bin/python
class Test:
    def __init__(self):
        __tBin = {'80':0, '70':0, '60':0, '50':0,'40':0}
        __pBin = {}
        __results = list()
        info = {'tBin'   : __tBin.copy(),
                'pBin'   : __pBin.copy(),
                'results': __results}

        self.writeBuffer = list()
        self.errorBuffer = list()

        self.__tests = {'test1' : info.copy(),
                        'test2' : info.copy(),
                        'test3' : info.copy()}

    def test(self):
        self.__tests['test1']['tBin']['80'] += 1
        self.__tests['test2']['tBin']['80'] += 1
        self.__tests['test3']['tBin']['80'] += 1
        print "test1: " + str(self.__tests['test1']['tBin']['80'])
        print "test2: " + str(self.__tests['test2']['tBin']['80'])
        print "test3: " + str(self.__tests['test3']['tBin']['80'])

Test().test()

My aim here is to create two dictionary objects (__tBin and __pBin) and making copies of them for each test (i.e. test1 test2 test3...). However, I am experiencing that test1, test2, and test3 still share the same value when I feel like I'm explicitly making copies of them. The above code also includes how I'm testing what I'm trying to accomplish.

While I expect to see 1, 1, 1 printed, I see 3, 3, 3 and I can't figure out why, especially when I explicitly do a 'copy()' on the dictionaries.

I'm on Python 2.7.4


Solution

  • For nested data structures you need to make a deep copy instead of a shallow copy. See here: http://docs.python.org/2/library/copy.html

    Import the module copy at the beginning of your file. Then replace calls like info.copy() with copy.deepcopy(info). Like so:

    #!/usr/bin/python
    
    import copy
    
    class Test:
        def __init__(self):
            ...
            info = {'tBin'   : __tBin.copy(),
                    'pBin'   : __pBin.copy(),
                    'results': __results}
            ...
            self.__tests = {'test1' : copy.deepcopy(info),
                            'test2' : copy.deepcopy(info),
                            'test3' : copy.deepcopy(info)}
    
        def test(self):
            ...
    
    ...