Search code examples
pythonprintingstring-formattingrounding

Rounding decimals in nested data structures in Python


I have a program which deals with nested data structures where the underlying type usually ends up being a decimal. e.g.

x={'a':[1.05600000001,2.34581736481,[1.1111111112,9.999990111111]],...}

Is there a simple pythonic way to print such a variable but rounding all floats to (say) 3dp and not assuming a particular configuration of lists and dictionaries? e.g.

{'a':[1.056,2.346,[1.111,10.000],...}

I'm thinking something like pformat(x,round=3) or maybe

pformat(x,conversions={'float':lambda x: "%.3g" % x})

except I don't think they have this kind of functionality. Permanently rounding the underlying data is of course not an option.


Solution

  • This will recursively descend dicts, tuples, lists, etc. formatting numbers and leaving other stuff alone.

    import collections.abc
    import numbers
    
    def pformat(thing, formatfunc):
        if isinstance(thing, dict):
            return type(thing)((key, pformat(value, formatfunc)) for key, value in thing.items())
        if isinstance(thing, collections.abc.Container):
            return type(thing)(pformat(value, formatfunc) for value in thing)
        if isinstance(thing, numbers.Number):
            return formatfunc(thing)
        return thing
    
    def formatfloat(thing):
        return "%.3g" % float(thing)
    
    x={'a':[1.05600000001,2.34581736481,[8.1111111112,9.999990111111]],
    'b':[3.05600000001,4.34581736481,[5.1111111112,6.999990111111]]}
    
    print(pformat(x, formatfloat))
    

    If you want to try and convert everything to a float, you can do

    try:
        return formatfunc(thing)
    except Exception:
        return thing
    

    instead of the last three lines of the function.