pkm
pkm

Reputation: 2783

python string to dict variable

I have a weird scenario where I need to convert the string like "data["data"]["name"][0]" into a dict variable which can be used to modify the dict variable value

so

input. - "data["data"]["name"][0]" and

output - data["data"]["name"][0]

so that I can use it modify the value of the variable.

Things that I have tried are locals() and globals() way of converting string to Variable but they seems to be failing given the string will actually be a complex dict variable.

update1:-

I was trying to get all the keys(path to keys) of a complex nested json and ended up getting that using collections and strings. so each key's path is string "data["data"]["name"][0]" but to modify the complex json I would need to interpret this as variable and assign value.

sample code

var = "data['data']['name'][0]"
data = {"data":{"name":["test","tst2"]}}
print(data['data']['name'][0])
print(var) # this prints the string
print(eval(var)) # this prints the value of string evaluted or like get method
#how to set value using var variable
#means var should be like data['data']['name'][0]

Upvotes: 0

Views: 98

Answers (1)

Lenormju
Lenormju

Reputation: 4378

It is not pretty, but it works :

def set_value(d, selector, val):
    """Follow the selector inside `d` to set the value of the last node."""
    if not selector.startswith("data"):
        raise ValueError("the query does not start with 'data'")

    # start parsing the selector
    parts = selector[len("data"):].split("]")
    if parts[-1] != "":
        raise ValueError("the query does not end with a ']'")
    parts.pop()  # remove the last part, we know it's empty
    current_node = d
    for part in parts[:-1]:  # for each part but not the last
        if (part.startswith("['") and part.endswith("'")) or \
                (part.startswith("[\"") and part.endswith("\"")):  # it's a dictionary access
            key_name = part[2:-1]
            current_node = current_node[key_name]
        elif part[1] in ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
            index_val = int(part[1:])
            current_node = current_node[index_val]
        else:
            raise ValueError(f"the query part {part[:-1]!r} is syntactically incorrect")
    # then handle the last part
    last_part = parts[-1]
    if (last_part.startswith("['") and last_part.endswith("'")) or \
            (last_part.startswith("[\"") and last_part.endswith("\"")):  # it's a dictionary access
        key_name = last_part[2:-1]
        current_node[key_name] = val
    elif last_part[1] in ("0", "1", "2", "3", "4", "5", "6", "7", "8", "9"):
        index_val = int(last_part[1:])
        current_node[index_val] = val
    else:
        raise ValueError(f"the query part {last_part!r} is syntactically incorrect")

    return d


data = {"data": {"name": ["test", "tst2"]}}

print(data)  # {'data': {'name': ['test', 'tst2']}}
data = set_value(data, 'data["data"]["name"][0]', 12)
print(data)  # {'data': {'name': [14, 'tst2']}}
data = set_value(data, "data['data']['name'][1]", -4)
print(data)  # {'data': {'name': [12, -4]}}
data = set_value(data, "data['foo']", {'bar': [5, 6]})
print(data)  # {'data': {'name': [12, -4]}, 'foo': {'bar': [5, 6]}}
data = set_value(data, "data['foo']['qux']", 'hh')
print(data)  # {'data': {'name': [12, -4]}, 'foo': {'bar': [5, 6], 'qux': 'hh'}}

Upvotes: 1

Related Questions