问题
Brand new to python, Let's say I have a dict:
kidshair = {'allkids':{'child1':{'hair':'blonde'},
'child2':{'hair':'black'},
'child3':{'hair':'red'},
'child4':{'hair':'brown'}}}
If child3 changes their hair colour regularly, I might want to write an application to speed up the data maintenance. In this example i'd use:
kidshair['allkids']['child3']['hair'] = ...
Is there any way to store this path as a variable so I can access it at my leasure? Obviously
mypath = kidshair['allkids']['child3']['hair']
results in mypath = 'red'. Is there any possible way to hard code the path itself so I could use:
mypath = 'blue'
to reperesent
kidshair['allkids']['child3']['hair'] = 'blue'
Kind thanks, ATfPT
回答1:
Depending on what you need, the easiest option may be to use tuples as dictionary keys instead of nested dictionaries:
kidshair['allkids', 'child3', 'hair']
mypath = ('allkids', 'child3', 'hair')
kidshair[mypath]
The only issue with this is that you can't get a portion of the dictionary, so, for example, you can't (easily/efficiently) access everything to do with 'child3'
. This may or may not be an appropriate solution for you depending on your usage.
An alternative with your current structure is to do something like this:
>>> from functools import partial
>>> test = {"a": {"b": {"c": 1}}}
>>> def itemsetter(item):
... def f(name, value):
... item[name] = value
... return f
...
>>> mypath = partial(itemsetter(test["a"]["b"]), "c")
>>> mypath(2)
>>> test
{'a': {'b': {'c': 2}}}
Here we make a function itemsetter()
, which (in the vein of operator.itemgetter()) gives us a function that that sets the relevant key in the given dictionary. We then use functools.partial to generate a version of this function with the key we want pre-filled. It's not quite mypath = blue
either, but it's not bad.
If you don't want to bother with making something consistent to the operator
module, you could simply do:
def dictsetter(item, name):
def f(value):
item[name] = value
return f
mypath = dictsetter(test["a"]["b"], "c")
mypath(2)
回答2:
You could create a set of functions that accesses a 'path' for a given dictionary:
def pathGet(dictionary, path):
for item in path.split("/"):
dictionary = dictionary[item]
return dictionary
def pathSet(dictionary, path, setItem):
path = path.split("/")
key = path[-1]
dictionary = pathGet(dictionary, "/".join(path[:-1]))
dictionary[key] = setItem
Usage:
>>> pathGet(kidshair, "allkids/child1/hair")
'blonde'
>>> pathSet(kidshair, "allkids/child1/hair", "blue")
>>> kidshair['allkids']['child1']
{'hair': 'blue'}
回答3:
You can save a reference to kidshair['allkids']['child3']
easily:
thiskid = kidshair['allkids']['child3']
thiskid['hair'] = 'blue'
You can't save the entire path, because the assignment changes the hair
key in the kidshair['allkids']['child3']
dictionary.
If you want to change a dictionary, you must have a reference to it, not to something it contains.
回答4:
The closest you can do with your current data structure is to get the last dict and use it directly:
child = kidshair['allkids']['child3']
child['hair'] = 'blue'
This is because in Python, assignment of the style
name = value
simply binds a new object to the "variable" name
. There is no way to overload this and the binding can't affect any other object (apart from freeing the object that was bound to this name until now).
On the other hand this:
name[key] = value
is entirely different because it performs an action (sets an item) on the object currently in name
(dict in your case).
回答5:
try to use dpath lib https://pypi.org/project/dpath/
>>> help(dpath.util.new)
Help on function new in module dpath.util:
new(obj, path, value)
Set the element at the terminus of path to value, and create
it if it does not exist (as opposed to 'set' that can only
change existing keys).
path will NOT be treated like a glob. If it has globbing
characters in it, they will become part of the resulting
keys
>>> dpath.util.new(x, 'a/b/e/f/g', "Roffle")
>>> print json.dumps(x, indent=4, sort_keys=True)
{
"a": {
"b": {
"3": 2,
"43": 30,
"c": "Waffles",
"d": "Waffles",
"e": {
"f": {
"g": "Roffle"
}
}
}
}
}
来源:https://stackoverflow.com/questions/10371732/storing-dictionary-path-in-python