admin管理员组

文章数量:1291309

I am writing a method that can update any item in a nested dictionary. The method takes the path, json, and value:

from functools import reduce
import operator

json_test = {'request_version': 'v1.0',
 'fields': [{'team': [{'name': 'Real Madrid', 'colour': 'white'}],
   'location': {'type': 'Feature',
    'geometry': {'type': 'Point', 'coordinates': [0, 53]}},
   'query': {'filter': '2024/25'},
   'player': 'Bellingham'}]}

def update_attribute(element, json, new_value):
    *path, last = element.split('.')
    target = reduce(operator.getitem, path, json)
    target[last] = new_value
    return json

update_attribute('fields.player', json_test, 'Mbappe')

However, this method won't work as there is a list in the dictionary.

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[114], line 1
----> 1 update_attribute("fields.player", json_name_ab_asr, "test")

Cell In[111], line 3, in update_attribute(element, json, new_value)
      1 def update_attribute(element, json, new_value):
      2     *path, last = element.split('.')
----> 3     target = reduce(operator.getitem, path, json)
      4     target[last] = new_value
      5     return json

TypeError: list indices must be integers or slices, not str

Any workarounds?

I am writing a method that can update any item in a nested dictionary. The method takes the path, json, and value:

from functools import reduce
import operator

json_test = {'request_version': 'v1.0',
 'fields': [{'team': [{'name': 'Real Madrid', 'colour': 'white'}],
   'location': {'type': 'Feature',
    'geometry': {'type': 'Point', 'coordinates': [0, 53]}},
   'query': {'filter': '2024/25'},
   'player': 'Bellingham'}]}

def update_attribute(element, json, new_value):
    *path, last = element.split('.')
    target = reduce(operator.getitem, path, json)
    target[last] = new_value
    return json

update_attribute('fields.player', json_test, 'Mbappe')

However, this method won't work as there is a list in the dictionary.

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In[114], line 1
----> 1 update_attribute("fields.player", json_name_ab_asr, "test")

Cell In[111], line 3, in update_attribute(element, json, new_value)
      1 def update_attribute(element, json, new_value):
      2     *path, last = element.split('.')
----> 3     target = reduce(operator.getitem, path, json)
      4     target[last] = new_value
      5     return json

TypeError: list indices must be integers or slices, not str

Any workarounds?

Share Improve this question asked Feb 13 at 20:02 praynerprayner 4252 silver badges11 bronze badges 3
  • Are you attempting to parse this specific dictionary or are you looking for a generalized solution – smallpepperz Commented Feb 13 at 20:05
  • 1 Why would you expect it to work? fields, being a list, doesn't have a player attribute. – Scott Hunter Commented Feb 13 at 20:07
  • 1. Generalising a solution, this is just a reprex. 2. I meant to write fields.0.player. – prayner Commented Feb 13 at 20:27
Add a comment  | 

1 Answer 1

Reset to default 1

Convert numeric components of path to integers. Then add the subscript to the element string when calling the function

from functools import reduce
import operator

json_test = {'request_version': 'v1.0',
             'fields': [{'team': [{'name': 'Real Madrid', 'colour': 'white'}],
                         'location': {'type': 'Feature',
                                      'geometry': {'type': 'Point',
                                                   'coordinates': [0, 53]}},
                         'query': {'filter': '2024/25'},
                         'player': 'Bellingham'}]}

def update_attribute(element, json, new_value):
    *path, last = element.split('.')
    path = [int(item) if item.isdigit() else item for item in path]
    target = reduce(operator.getitem, path, json)
    target[last] = new_value
    return json

update_attribute('fields.0.player', json_test, 'Mbappe')

This isn't perfect, as it won't work if you have a dictionary whose keys are numeric strings.

本文标签: pythonUpdate item in nested dictionary containing listStack Overflow