1

I have following function where I build dict of dicts dynamically (here DoD is created statically for simplicity):

import json
def fun(dummyArg1, dummyArg2):
  DoD = {'a': {'aa':1, 'ab':2}, 'b': {'ba':3, 'bb':4}, 'c': '5'}
  print json.dumps(DoD, sort_keys=True, indent=4)
  # FURTHER CODE THAT WILL WORK WITH DoD VARIABLE GOES HERE

In [1]: fun(1,2)
Out[1]:
{
    "a": {
        "aa": 1,
        "ab": 2
    },
    "b": {
        "ba": 3,
        "bb": 4
    },
    "c": "5"
}

Is it possible to specify particular DoD element content during function call? I would like to have something like:

fun(dummyArg1, dummyArg2, DoD["b"]["ba"] = "New Value")

I know that it is possible e.g. via passing list where 0th position is new value, 1st position is "outer" dict key and 2nd position is "inner" dict key:

import json
lst = ["New Value", "b", "ba"]
def fun(arg1, arg2, additionalParams):
  DoD = {'a': {'aa':1, 'ab':2}, 'b': {'ba':3, 'bb':4}, 'c': '5'}
  DoD[additionalParams[1]][additionalParams[2]] = additionalParams[0]
  print json.dumps(DoD, sort_keys=True, indent=4)
  # FURTHER CODE THAT WILL WORK WITH DoD VARIABLE GOES HERE

In [1]: fun(1,2,lst)
Out[1]:
{
    "a": {
        "aa": 1,
        "ab": 2
    },
    "b": {
        "ba": "New Value",
        "bb": 4
    },
    "c": "5"
}

But as you can see it is not very robust (changing value under key 'c' requires rewriting the function code) nor elegant. Is there better approach?

Bonus question: Why in last example after assignment "ba" contains ["New Value"] instead of "New Value"?

PS: Even if DoD will be created dynamically there will always be DoD["b"]["ba"] element.

Wakan Tanka
  • 7,542
  • 16
  • 69
  • 122
  • 1
    I can answer your bonus question - You set DOD['b']['ba'] = [ additionalParams[0] ]. additionalParams[0] is a string, [additionalParams[0]] is the same string enclosed in a list. With regard to the rest of your question, I'm not sure I understand what you're trying to do. Can you elaborate on what you want your function to do? What is its input, what is the desired output? – BHawk Apr 29 '16 at 21:00
  • @BHawk Thank you it was a typo. Desired input is something like this: `fun(dummyArg1, dummyArg2, DoD["b"]["ba"] = "New Value")` And desired output you can see on last code snippet. – Wakan Tanka Apr 29 '16 at 21:05
  • You can put that additional param into string, and do eval. In other cases assignment will be executed... DoD is not defined in that scope, so that would fail. Adding it into the scope wouldn't help much you need to define whole DoD, and pass it as a parameter. – Michał Zaborowski Apr 29 '16 at 21:37

2 Answers2

0

You can use **kwargs and check root, i.e.:

import json

def fun(arg1, arg2, root, **additionalParams):
  DoD = {'a': {'aa':1, 'ab':2}, 'b': {'ba':3, 'bb':4}, 'c': '5'}

  if root:
    DoD[root][additionalParams.keys()[0]] = additionalParams.values()[0]
  else:
    DoD[additionalParams.keys()[0]] = additionalParams.values()[0]

  print json.dumps(DoD, sort_keys=True, indent=4)

test1:

fun(1,2, root="b", ba = "new value")

Output:

{
    "a": {
        "aa": 1, 
        "ab": 2
    }, 
    "b": {
        "ba": "new value", 
        "bb": 4
    }, 
    "c": "5"
}

test2:

fun(1,2, root=None, c = "new value")

Output:

{
    "a": {
        "aa": 1, 
        "ab": 2
    }, 
    "b": {
        "ba": 3, 
        "bb": 4
    }, 
    "c": "new value"
}

NOTE: You can pass root in **additionalParams but you should consider not preserved the order in keyword arguments passed to the function.

Community
  • 1
  • 1
Javier Clavero
  • 445
  • 5
  • 13
0

This is a weird way to set up a program, but assuming you have your reasons I think you might be looking for splat arguments [*args] or [**kwargs]. With a splat argument you can have your "formal arguments" aka "required arguments" to the function (dummyArg1, dummyArg2 in this case) then your splat arg. So your def would be

def fun(dummyArg1,dummyArg2,*args):

Your call would be

fun(1,2,'abc','def',4,'etc')

and inside your code args would be represented as a tuple = ('abc','def',4,'etc')

Then you can use your tuple to sort out your dictionary walk:

l = len(args)
if l == 3:
  DoD[args[1]][args[2]] = args[0]
elif l == 2:
  DoD[args[1]] = args[0]

Of course this could become cumbersome if you have exceptionally deep dictionaries in which case you might want to look at more complex walking methods.

Community
  • 1
  • 1
BHawk
  • 2,382
  • 1
  • 16
  • 24