Настройка : я хотел написать метод, который бы брал вложенный объект данных и строку пути и пытался использовать компоненты пути для разыменования местоположения внутри объекта данных.
Например, у вас был бы путь, подобный /alpha/bravo/0/charlie
, и метод вернул бы data_obj['alpha']['bravo'][0]['charlie']
, если бы это было определенное местоположение, или сделал бы что-то еще (сгенерировать исключение, записать предупреждение, вернуть None
, что угодно)если это не так.
Попытка : я чувствовал, что, возможно, был довольно простой способ сделать это, и когда я оглянулся, я нашел этот ответ ,который предлагает объединить functools.reduce
с operator.getitem
, чтобы пройти сколь угодно глубокий словарь .Я хотел приспособить это, чтобы покрыть диктовку, которая могла иметь вложенные списки, поэтому я немного поиграл и обнаружил, что вложенные вызовы getitem
работают нормально, но комбинация getitem
и reduce
приводит к запутанному типунесоответствие, как показано ниже.
Вопрос : В фрагменте кода, показанном ниже, почему вызов reduce
приводит к исключению, когда другие способы выполнения вложенных вызовов не приводят?
Мое необоснованное предположение: что-то в functools
или operator
устанавливает идентификатор getitem
, указывающий на * либо * list.__getitem__
ИЛИ dict.__getitem__
, и когда его просят играть хорошос reduce
он застревает на одном или другом и не может переключаться назад и вперед.
Код :
$ python3 -q
>>> data_obj = {
... 'alpha': {
... 'bravo': [
... {'charlie': 1},
... {'delta': 2},
... ]
... }
... }
>>>
>>> node_keys = ['alpha', 'bravo', 0, 'charlie']
>>>
>>> from functools import reduce
>>> from operator import getitem
>>>
>>> reduce(getitem, data_obj, node_keys)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: list indices must be integers or slices, not str
>>>
>>> data_obj[node_keys[0]][node_keys[1]][node_keys[2]][node_keys[3]]
1
>>> getitem(
... getitem(
... getitem(
... getitem(data_obj, node_keys[0]),
... node_keys[1]
... ), node_keys[2]
... ), node_keys[3]
... )
1
>>>
>>> data_obj.__getitem__(node_keys[0])\
... .__getitem__(node_keys[1])\
... .__getitem__(node_keys[2])\
... .__getitem__(node_keys[3])
1
>>>