Convierta Python decimal a cadena en una lista profundamente anidada e impredecible

Estoy tratando de recorrer cada valor en una lista profundamente anidada / mixta y convertir cualquier instancia decimal en una cadena para poder almacenarlas en mongo.

Mi bash de recursión alcanzó la máxima profundidad. Me gustaría resolver esto de manera iterativa o de manera performante.

Esto no parece funcionar pero es mi último bash:

def convert_decimals(root_obj): objs_to_convert = [root_obj] while objs_to_convert: obj = objs_to_convert.pop(0) for k, v in enumerate(obj): if len(v): objs_to_convert.append(v) elif isinstance(v, Decimal): obj[k] = str(v) 

Entrada de muestra:

 [ { 'Payments': { 'Payment': Decimal('495.64'), 'IsCapped': True, 'OtherFees': Decimal('0'), 'CapCostTotal': Decimal('27900'), 'Name': 'TestData', 'Program': { 'ProgramName': u'AST', 'Description': None }, 'Rate': Decimal('0.0254'), 'APR': Decimal('2.54'), 'AppliedIds': [ ], 'Tax': Decimal('0') } } ] 

Después de la conversión, las instancias decimales deben ser cadenas

Para convertir Decimal durante json.dump() usando default parámetro default :

 import json import sys from decimal import Decimal def default(obj): if isinstance(obj, Decimal): return str(obj) else: raise TypeError(obj) # convert during dump json.dump(data, sys.stdout, indent=2, default=default) 

Para modificar los data lugar:

 import json import sys from collections import MutableMapping, MutableSequence from decimal import Decimal def convert_decimal(json_data): stack = [json_data] while stack: json_data = stack.pop() if isinstance(json_data, MutableMapping): # json object it = json_data.items() elif isinstance(json_data, MutableSequence): # json array it = enumerate(json_data) else: # scalar data continue for k, v in it: if isinstance(v, Decimal): json_data[k] = str(v) else: stack.append(v) # convert inplace convert_decimal(data) json.dump(data, sys.stdout, indent=2) 

Ambos scripts producen el mismo resultado:

 [ { "Payments": { "OtherFees": "0", "APR": "2.54", "Rate": "0.0254", "IsCapped": true, "Name": "TestData", "Program": { "Description": null, "ProgramName": "AST" }, "AppliedIds": [], "CapCostTotal": "27900", "Tax": "0", "Payment": "495.64" } } ] 

Podría simplificar convert_decimal() si usa una función genérica get_items() :

 def convert_decimal(json_data): stack = [json_data] while stack: json_data = stack.pop() for k, v in get_items(json_data): if isinstance(v, Decimal): json_data[k] = str(v) else: stack.append(v) 

¿Desea convertir decimales en cadenas, pero aplicar de forma recursiva el contenido de las listas y los valores de los diccionarios, de lo contrario devolverá los objetos sin modificar? Entonces haz eso:

 def strip_decimals(o): if type(o) == Decimal: return str(o) elif type(o) == list: return map(strip_decimals, o) elif type(o) == dict: return dict([(k, strip_decimals(v)) for k, v in o.iteritems()]) else: return o 

Resultados en:

 [{'Payments': {'APR': '2.54', 'AppliedIds': [], 'CapCostTotal': '27900', 'IsCapped': True, 'Name': 'TestData', 'OtherFees': '0', 'Payment': '495.64', 'Program': {'Description': None, 'ProgramName': u'AST'}, 'Rate': '0.0254', 'Tax': '0'}}]