#NEWLINE# def update_in( d , keys , func , default = None , factory = dict ) : #NEWLINE# #INDENT# ' Update value in a (potentially) nested dictionary\n\n    inputs:\n    d - dictionary on which to operate\n    keys - list or tuple giving the location of the value to be changed in d\n    func - function to operate on that value\n\n    If keys == [k0,..,kX] and d[k0]..[kX] == v, update_in returns a copy of the\n    original dictionary with v replaced by func(v), but does not mutate the\n    original dictionary.\n\n    If k0 is not a key in d, update_in creates nested dictionaries to the depth\n    specified by the keys, with the innermost value set to func(default).\n\n    >>> inc = lambda x: x + 1\n    >>> update_in({\'a\': 0}, [\'a\'], inc)\n    {\'a\': 1}\n\n    >>> transaction = {\'name\': \'Alice\',\n    ...                \'purchase\': {\'items\': [\'Apple\', \'Orange\'],\n    ...                             \'costs\': [0.50, 1.25]},\n    ...                \'credit card\': \'5555-1234-1234-1234\'}\n    >>> update_in(transaction, [\'purchase\', \'costs\'], sum) # doctest: +SKIP\n    {\'credit card\': \'5555-1234-1234-1234\',\n     \'name\': \'Alice\',\n     \'purchase\': {\'costs\': 1.75, \'items\': [\'Apple\', \'Orange\']}}\n\n    >>> # updating a value when k0 is not in d\n    >>> update_in({}, [1, 2, 3], str, default="bar")\n    {1: {2: {3: \'bar\'}}}\n    >>> update_in({1: \'foo\'}, [2, 3, 4], inc, 0)\n    {1: \'foo\', 2: {3: {4: 1}}}\n    ' #NEWLINE# assert ( len ( keys ) > 0 ) #NEWLINE# ( k , ks ) = ( keys [ 0 ] , keys [ 1 : ] ) #NEWLINE# if ks : #NEWLINE# #INDENT# return assoc ( d , k , update_in ( ( d [ k ] if ( k in d ) else factory ( ) ) , ks , func , default , factory ) , factory ) #NEWLINE# #UNINDENT# else : #NEWLINE# #INDENT# innermost = ( func ( d [ k ] ) if ( k in d ) else func ( default ) ) #NEWLINE# return assoc ( d , k , innermost , factory )