Если у вас есть доступ к изменению параметров JVM, добавление подробного вывода должно позволять вам видеть, какие классы загружаются из JAR.
java -verbose:class <other args>
Когда ваша программа запущена, JVM должна сбрасывать к стандартной информации, такой как:
...
[Загружено junit.framework.Assert из файла: / C: /Program%20Files/junit3.8.2/junit .jar]
...
blockquote>
Используйте reduce()
для перемещения словаря:
from functools import reduce # forward compatibility for Python 3
import operator
def getFromDict(dataDict, mapList):
return reduce(operator.getitem, mapList, dataDict)
и повторного использования getFromDict
, чтобы найти местоположение для сохранения значения для setInDict()
:
def setInDict(dataDict, mapList, value):
getFromDict(dataDict, mapList[:-1])[mapList[-1]] = value
Все, кроме последнего элемента в mapList
, необходимы, чтобы найти «родительский» словарь, чтобы добавить значение, а затем использовать последний элемент, чтобы установить значение в правую клавишу.
Демо:
>>> getFromDict(dataDict, ["a", "r"])
1
>>> getFromDict(dataDict, ["b", "v", "y"])
2
>>> setInDict(dataDict, ["b", "v", "w"], 4)
>>> import pprint
>>> pprint.pprint(dataDict)
{'a': {'r': 1, 's': 2, 't': 3},
'b': {'u': 1, 'v': {'w': 4, 'x': 1, 'y': 2, 'z': 3}, 'w': 3}}
Обратите внимание, что руководство по стилю Python PEP8 предписывает имена змеиных имен для функций . Вышеупомянутое работает одинаково хорошо для списков или комбинации словарей и списков, поэтому имена должны быть действительно get_by_path()
и set_by_path()
:
from functools import reduce # forward compatibility for Python 3
import operator
def get_by_path(root, items):
"""Access a nested object in root by item sequence."""
return reduce(operator.getitem, items, root)
def set_by_path(root, items, value):
"""Set a value in a nested object in root by item sequence."""
get_by_path(root, items[:-1])[items[-1]] = value
Как насчет проверки, а затем установить элемент dict без обработки всех индексов дважды?
Решение:
def nested_yield(nested, keys_list):
"""
Get current nested data by send(None) method. Allows change it to Value by calling send(Value) next time
:param nested: list or dict of lists or dicts
:param keys_list: list of indexes/keys
"""
last_key = keys_list.pop()
for key in keys_list:
nested = nested[key] #_dict.setdefault(key, {})
while True:
try:
nested[last_key] = yield nested[last_key]
except IndexError:
print("no index {} in {}".format(last_key, nested))
Пример рабочего процесса:
ny = nested_yield(nested_dict, nested_address)
data_element = ny.send(None)
if data_element:
# process element
...
else:
# extend/update nested data
ny.send(new_data_element)
...
ny.close()
Тест
>>> cfg= {'Options': [[1,[0]],[2,[4,[8,16]]],[3,[9]]]}
ny = nested_yield(cfg, ['Options',1,1,1])
ny.send(None)
[8, 16]
>>> ny.send('Hello!')
'Hello!'
>>> cfg
{'Options': [[1, [0]], [2, [4, 'Hello!']], [3, [9]]]}
>>> ny.close()
Чистый стиль Python без импорта:
def nested_set(element, value, *keys):
if type(element) is not dict:
raise AttributeError('nested_set() expects dict as first argument.')
if len(keys) < 2:
raise AttributeError('nested_set() expects at least three arguments, not enough given.')
_keys = keys[:-1]
_element = element
for key in _keys:
_element = _element[key]
_element[keys[-1]] = value
example = {"foo": { "bar": { "baz": "ok" } } }
keys = ['foo', 'bar']
nested_set(example, "yay", *keys)
print(example)
Выход
{'foo': {'bar': 'yay'}}
Использование сокращения является умным, но метод set OP может иметь проблемы, если родительские ключи не существуют во вложенном словаре. Поскольку это первая публикация SO, которую я видел для этого объекта в моем поиске в Google, я хотел бы немного улучшить его.
Метод set in ( Установка значения во вложенном словаре python список индексов и значение ) кажется более надежным для отсутствующих родительских ключей. Чтобы скопировать его:
def nested_set(dic, keys, value):
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
Кроме того, может быть удобно иметь метод, который обходит дерево ключей и получает все пути абсолютного ключа, для которых я создал:
def keysInDict(dataDict, parent=[]):
if not isinstance(dataDict, dict):
return [tuple(parent)]
else:
return reduce(list.__add__,
[keysInDict(v,parent+[k]) for k,v in dataDict.items()], [])
Одно из них - преобразовать вложенное дерево в pandas DataFrame, используя следующий код (при условии, что все листы во вложенном словаре имеют одинаковую глубину).
def dict_to_df(dataDict):
ret = []
for k in keysInDict(dataDict):
v = np.array( getFromDict(dataDict, k), )
v = pd.DataFrame(v)
v.columns = pd.MultiIndex.from_product(list(k) + [v.columns])
ret.append(v)
return reduce(pd.DataFrame.join, ret)
from functools import reduce
. for
. См. Цитату из Что нового в Python 3.0 . Удалено reduce()
. Используйте functools.reduce()
, если вам это действительно нужно; однако в 99% случаев явная for
петля более читаема. KeyError
) - см. ответ @ eafit для решения Итак, почему не используйте предложенный метод из вопроса kolergy для получения значения:
def getFromDict(dataDict, mapList):
for k in mapList: dataDict = dataDict[k]
return dataDict
И код из ответа @ eafit для установки значения:
def nested_set(dic, keys, value):
for key in keys[:-1]:
dic = dic.setdefault(key, {})
dic[keys[-1]] = value
Оба работают прямо в python 2 и 3
getFromDict
имеет потенциал для уничтожения dataDict
вызывающего. Сначала я хотел бы copy.deepcopy(dataDict)
. Конечно, (как написано) это поведение желательно во второй функции.
– Dylan F
13 June 2018 в 03:33
Если вы также хотите работать с произвольным json, включая вложенные списки и dicts, и хорошо обрабатывать недопустимые пути поиска, вот мое решение:
from functools import reduce
def get_furthest(s, path):
'''
Gets the furthest value along a given key path in a subscriptable structure.
subscriptable, list -> any
:param s: the subscriptable structure to examine
:param path: the lookup path to follow
:return: a tuple of the value at the furthest valid key, and whether the full path is valid
'''
def step_key(acc, key):
s = acc[0]
if isinstance(s, str):
return (s, False)
try:
return (s[key], acc[1])
except LookupError:
return (s, False)
return reduce(step_key, path, (s, True))
def get_val(s, path):
val, successful = get_furthest(s, path)
if successful:
return val
else:
raise LookupError('Invalid lookup path: {}'.format(path))
def set_val(s, path, value):
get_val(s, path[:-1])[path[-1]] = value
Эта библиотека может быть полезна: https://github.com/akesterson/dpath-python
Библиотека python для доступа и поиска словарей через / slashed / paths ala xpath
В принципе, он позволяет вам глотать словарь, как если бы он был файловой системой.
blockquote>
Вместо того, чтобы каждый раз, когда вы хотите посмотреть значение, вы получаете удар производительности, как насчет того, чтобы вы сплели словарь, а затем просто найдите ключ, например b:v:y
def flatten(mydict):
new_dict = {}
for key,value in mydict.items():
if type(value) == dict:
_dict = {':'.join([key, _key]):_value for _key, _value in flatten(value).items()}
new_dict.update(_dict)
else:
new_dict[key]=value
return new_dict
dataDict = {
"a":{
"r": 1,
"s": 2,
"t": 3
},
"b":{
"u": 1,
"v": {
"x": 1,
"y": 2,
"z": 3
},
"w": 3
}
}
flat_dict = flatten(dataDict)
print flat_dict
{'b:w': 3, 'b:u': 1, 'b:v:y': 2, 'b:v:x': 1, 'b:v:z': 3, 'a:r': 1, 'a:s': 2, 'a:t': 3}
. Таким образом, вы можете просто просмотрите элементы, используя flat_dict['b:v:y']
, которые дадут вам 1
.
И вместо того, чтобы перемещаться по словарю при каждом поиске, вы можете ускорить это, сглаживая словарь и сохраняя вывод так, чтобы что поиск с холодного старта означал бы загрузку сплющенного словаря и просто выполнение поиска ключа / значения без обхода.
Решено это с рекурсией:
def get(d,l):
if len(l)==1: return d[l[0]]
return get(d[l[0]],l[1:])
Используя ваш пример:
dataDict = {
"a":{
"r": 1,
"s": 2,
"t": 3
},
"b":{
"u": 1,
"v": {
"x": 1,
"y": 2,
"z": 3
},
"w": 3
}
}
maplist1 = ["a", "r"]
maplist2 = ["b", "v", "y"]
print(get(dataDict, maplist1)) # 1
print(get(dataDict, maplist2)) # 2
Альтернативный способ, если вы не хотите поднимать ошибки, если один из ключей отсутствует (чтобы ваш основной код мог работать без прерывания):
def get_value(self,your_dict,*keys):
curr_dict_ = your_dict
for k in keys:
v = curr_dict.get(k,None)
if v is None:
break
if isinstance(v,dict):
curr_dict = v
return v
В этом случае, если есть входных ключей нет, возвращается None, которое может использоваться как проверка вашего основного кода для выполнения альтернативной задачи.
Как насчет использования рекурсивных функций?
Чтобы получить значение:
def getFromDict(dataDict, maplist):
first, rest = maplist[0], maplist[1:]
if rest:
# if `rest` is not empty, run the function recursively
return getFromDict(dataDict[first], rest)
else:
return dataDict[first]
И установить значение:
def setInDict(dataDict, maplist, value):
first, rest = maplist[0], maplist[1:]
if rest:
try:
if not isinstance(dataDict[first], dict):
# if the key is not a dict, then make it a dict
dataDict[first] = {}
except KeyError:
# if key doesn't exist, create one
dataDict[first] = {}
setInDict(dataDict[first], rest, value)
else:
dataDict[first] = value
try:
,except (KeyError, IndexError): return default_value
вокруг текущей строкиreturn
. – Martijn Pieters♦ 11 February 2015 в 13:05