Search code examples
pythondictionarynestedpass-by-referencepass-by-value

Modify an element in a nested dict given a "path" to it


Given a "path" of a list of indices (of an arbitrary length) and a nested Python list/dict object, how can I write to the part of the object at a list?

For example, this might be my object (it's loaded from a JSON file):

data = {"dogs":[{"tail": True, "properties":{"test":1}}]}

and my list of indices might look like ["dogs", 0, "properties"].

If I want to retrieve the value at the path, I can do something like this:

>>> data = {"dogs":[{"tail": True, "properties":{"test":1}}]}
>>> path = ["dogs", 0, "properties"]
>>> mydata = data
>>> for i in path:
...     mydata = mydata[i]
...
>>> mydata
{'test': 1}

But say I want to modify the object at the path inside the whole structure? The above code is pass-by-value, not by reference, so I don't think I can reuse that. What can I do?


Solution

  • This would be probably a good alternative option, but I find jsonpath-rw library a good way to navigate and search inside a JSON structure:

    >>> from jsonpath_rw import jsonpath, parse
    >>> 
    >>> data = {"dogs":[{"tail": True, "properties":{"test":1}}]}
    >>> 
    >>> jsonpath_expr = parse("dogs.[0].properties")
    >>> jsonpath_expr.find(data)[0].value['test'] = 2
    >>> print(data)
    {'dogs': [{'tail': True, 'properties': {'test': 2}}]}
    

    Note that you still have the "by reference" behavior in the code you've shown:

    >>> data = {"dogs":[{"tail": True, "properties":{"test":1}}]}
    >>> 
    >>> path = ["dogs", 0, "properties"]
    >>> mydata = data
    >>> for i in path:
    ...     mydata = mydata[i]
    ... 
    >>> mydata["test"] = 2
    >>> print(data)
    {'dogs': [{'tail': True, 'properties': {'test': 2}}]}