Forcing each to the expected type while traversing makes a deep copy:
def sanitize_tree(element):
if hasattr(element, '__iter__'):
if hasattr(element, 'keys'):
return dict((k, sanitize_tree(element[k])) for k in element.keys())
else:
return list(sanitize_tree(x) for x in element)
return element
EDIT: Got rid of the unnecessary zip() and used only one keys() iterator instead of two.