1

Some one know if its possible to get a dict inside a dict by using their keys as strings... Sorry for the bad explation i think the code would be more clear... don't know how to properly say this

s={"framework": {"challenger": {
    "logo.qvg": "50c137c8199d0a807bc31b5c384e67d6c1c0837061bd7d39ed15943b"}}}

possible_folders=["tractor","svg","framework","common",'framework["challenger"]']

print(s['framework']['challenger'])  # this line is working

print(s[possible_folders[-1]])   # here im getting keyerror-> due to the string... 

5 Answers5

3

It's not possible. s is a dict with a single key, "framework". There is no way to index s to get something deeper inside one of s's values.

You can write a function that takes a list of keys and iteratively digs into the dict, however. (Iguananaut does this with better error handling.)

def chain_lookup(s, *keys):
    d = s
    for key in keys:
        d = d[key]
    return d


result = chain_lookup(s, "framework", "challenger")
# result == {"logo.qvg": "..."}
chepner
  • 497,756
  • 71
  • 530
  • 681
3

I think what you want is a way to access nested dicts by a sequence of keys. There are many ways to do this. One I like is to define a simple function like:

def nested_get(d, *keys, *, default=None):
    for k in keys:
        try:
            d = d[k]
        except KeyError:
            return default

    return d

Then use a tuple like keys = ('framework', 'challenger'):

nested_get(d, *keys)
Iguananaut
  • 21,810
  • 5
  • 50
  • 63
  • 2
    If passing tuples isn't very fancy, you can try to pass a single string like `"framework/challenger"`, split it inside the function by `/` and access the element similarly as @Iguananaut suggested. Though of course need to pay attention not to use `/` as a part of the key, only as a delimiter – Alexey S. Larionov Jun 30 '21 at 12:32
-1

You can use the eval() function like:

s={"framework": {"challenger": {
    "logo.qvg": "50c137c8199d0a807bc31b5c384e67d6c1c0837061bd7d39ed15943b"}}}

possible_folders=["tractor","svg","framework","common",'framework["challenger"]']


def get_entry(d, k):
    
    eval_string = "d" +"".join([".get('" + i.replace('"',"").replace("[","").replace("]","") + "')" for i in k.split("[")])
    return eval(eval_string)
get_entry(s,possible_folders[-1])
Out[32]: {'logo.qvg': '50c137c8199d0a807bc31b5c384e67d6c1c0837061bd7d39ed15943b'}

I am not saying I would recommend it, but it is the only solution that works with the String Syntax in your questions. The other answers are better, however require a change in your list

FloLie
  • 1,820
  • 1
  • 7
  • 19
-1

I agree with the above answers, because they're how you do it in a good programming way. Although I have a quick fix to make your exact command work, but it is NOT a good programming way, since it uses hardcoding and also eval function.

In the first line, you are accessing with print(s['framework']['challenger']), but in second line, you are accessing like s['framework["challenger"]' (see the brackets).

You can change the possible folders from

possible_folders=["tractor","svg","framework","common",'framework["challenger"]']

to

possible_folders=["tractor","svg","framework","common",'["framework"]["challenger"]']
eval("s"+possible_folders[-1])
Tharun N
  • 1
  • 1
  • 2
-1

First of all I strongly suggest reading this - I would go that way. Having said that, below you will find the non-responsible way (using eval) of achieving this. Again, strongly suggest going that way.

possible_folders=["tractor","svg","framework","common","['framework']['challenger']"]
print(eval('s'+possible_folders[-1]))