Adam Mitchell Adam Mitchell - 1 month ago 6
Python Question

Why is are the dicts in this list of dicts empty?

As the title implies; I'm unsure as to why the dictionaries in this list of dictionaries are empty. I print the dictionaries out before I append them to the list and they all have 4 keys/values.

Please ignore the 'scrappiness' of the code- I always go through a process of writing it out basically and then refining!

Code:

import ntpath, sys, tkFileDialog, Tkinter
import xml.etree.ElementTree as ET

class Comparison:
def __init__(self, file):
self.file = ET.parse(file)
self.filename = self.get_file_name(file)
self.root = self.file.getroot()
self.file_length = len(self.root)
self.data_dict = dict()
self.master_list = list()
self.parse_xml(self.root)
print self.master_list

def get_file_name(self, file):
filename_list = list()
for char in ntpath.basename(str(file)):
filename_list.append(char)
if ''.join(filename_list[-4:]) == '.xml':
return ''.join(filename_list)

def parse_xml(self, tree):
for child in tree:
if tree == self.root:
self.step_number = child.attrib['id']
self.data_dict['Step'] = self.step_number
if len(child.tag) > 0:
self.data_dict['Tag'] = child.tag
else:
self.data_dict['Tag'] = ""
if len(child.attrib) > 0:
self.data_dict['Attrib'] = child.attrib
else:
self.data_dict['Attrib'] = ""
if child.text is not None:
self.data_dict['Text'] = child.text
else:
self.data_dict['Text'] = ""
print self.data_dict
print "Step: "+str(self.data_dict['Step'])
try:
print "Tag: "+str(self.data_dict['Tag'])
except:
pass
try:
for key,value in self.data_dict['Attrib'].iteritems():
print "Attrib: "+str(key)
print "Attrib Value: "+str(value)
except:
pass
try:
if len(str(self.data_dict['Text'])) > 0:
print "Text Length: "+str(len(str(self.data_dict['Text'])))
print "Text: "+str(self.data_dict['Text'])
except:
pass
print ""
print len(self.data_dict)
self.master_list.append(self.data_dict)
print self.data_dict
self.data_dict.clear()
if len(child) > 0:
self.parse_xml(child)

if __name__ == "__main__":
root = Tkinter.Tk()
root.iconify()
if sys.argv[1] != "":
file_a = Comparison(sys.argv[1])
else:
file_a = Comparison(tkFileDialog.askopenfilename())

Answer

I presume you mean this:

 print len(self.data_dict)
 self.master_list.append(self.data_dict)
 print self.data_dict
 self.data_dict.clear()

The dict is empty because you clear it. Everything is a reference in Python.

>>> d = {k:v for k,v in zip(range(5),'abcde')}
>>> id(d)
140199719344392
>>> some_list = []
>>> some_list.append(d)
>>> some_list
[{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}]
>>> id(some_list[0])
140199719344392
>>> d.clear()
>>> some_list
[{}]
>>> 

If you want a copy to be appended, then you need to explicitely copy it. If a shallow copy will do, then simply use your_dict.copy():

>>> d = {k:v for k,v in zip(range(5),'abcde')}
>>> d
{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}
>>> id(d)
140199686153480
>>> some_list = []
>>> some_list.append(d.copy())
>>> id(some_list[0])
140199719344392
>>> d.clear()
>>> some_list
[{0: 'a', 1: 'b', 2: 'c', 3: 'd', 4: 'e'}]
>>>