-2

I'm trying to build a function that assign keys and values to a defaultdict in python3, but it fails in exec execution. Let's say that I need to pass several str variables as keys and other as values in a defaultdict inside:

Define a dd:

dict=dd(lambda: dd(lambda: dd(lambda: dd(list))))

Decide variables as keys:

keys_var = ['a', 'b', 'c', 'd']

Decide variables as values :

values_var = ['d', 'e', 'f', 'g' ]

Arrange values for keys :

key_for_dict = []
for value in keys_var :
       value_for_keys.append( '[' + str(value) + ']' )
string_insert_keys =  ''.join(key_for_dict)

it will looks like:

[a][b][c][d]

Arrange values for values insert:

values_for_dict = []
for value in values_var:
     values_for_dict.append(value)
string_for_values = ', '.join(values_for_dict)
string_insert_values = "[ " + string_for_values + " ]"

it will looks like:

    [ d, e, f, g ]

And now define a function to insert these keys and values in a loop (where a,b,c,d etc take different values and the final argument is a join of all these d, e, f, g )

I tried:

def riempie_dict_var( dizionario ) :
     exec( dizionario + string_insert_keys + ".append('___'.join( " + string_insert_columns + "))" )

but it fails with:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for +: 'collections.defaultdict' and 'str'
cccnrc
  • 1,195
  • 11
  • 27

1 Answers1

0

If you must use exec(), you should be able to do:

from collections import defaultdict as dd

prova_dizionario = dd(lambda: (dd(list)))

ciao, bao = 'ciao', 'bao'

exec("prova_dizionario[ciao][bao] = ['', '', '' ]")

But if you provide more context, it's likely that folks here will be able to help you come up with an exec-free solution.

EDIT

I'm not sure I completely understand your issues but it seems to me you have a recursive data structure which might best be handled with recursive code:

from collections import defaultdict as dd

def recursive_insert(dictionary, keys_var, values_var):
    head, *tail = keys_var

    if tail:
        recursive_insert(dictionary[head], tail, values_var)
    else:
        dictionary[head].extend(values_var)

dictionary = dd(lambda: dd(lambda: dd(lambda: dd(list))))

keys_var = ['a', 'b', 'c', 'd']

values_var = ['d', 'e', 'f', 'g']

recursive_insert(dictionary, keys_var, values_var)

print(dictionary['a']['b']['c']['d'])

OUTPUT

% python3 test.py
['d', 'e', 'f', 'g']
%
cdlane
  • 40,441
  • 5
  • 32
  • 81
  • @ccc.nrc, I've added an exec-free solution base on your expanded explanation -- let me know if I've missed the point and expand your description accordingly. – cdlane Jan 29 '19 at 20:38
  • yes I think it could work! Can you explain me a little more about how does it work? (PS: it told me that in case of single insertion, defaultdict ha no attribute extend() ) – cccnrc Jan 29 '19 at 20:56
  • @ccc.nrc, you declared your lowest level of defaultdict to have a value type of `list` so a *single insertion* should use `append()` -- otherwise, redefine your data structure as needed. At each level, we process one key, passing a subdictionary and remaining keys to the recursive call. If there is only one key left, we put the values we've been passing down into the list stored at that key. Do a search on *recursion*. – cdlane Jan 29 '19 at 21:27
  • Thanks a @cdlane ! – cccnrc Jan 29 '19 at 22:00