2017-11-06 2 views
0

Ich habe die Dokumentation durchforstet und die Hilfe vieler Teammitglieder benutzt, bin aber nicht in der Lage herauszufinden, wie man ein Wörterbuch durch Werte ersetzt, die als Kwargs (in meinem Fall) zur Verfügung gestellt werden Testfunktion:Python 3 benutze kwargs, um geschachtelte Wörterbuchwerte zu ersetzen

Template-Wörterbuch:

{ 
    "id": "id_1234", 
    "integer_value": 1234, 
    "level_one": { 
     "id": 1234, 
     "foo": "true", 
     "list_one": [], 
     "list_two": [ 
      522 
     ], 
     "url": "http://google.com", 
     "level_two": { 
      "thing_one": { 
       "yes": "false", 
       "no": "false" 
      }, 
      "thing_two": { 
       "yes": "false", 
       "no": "false" 
      } 
     }, 
     "another_field": "true", 
     "bar": 15000 
    } 
} 

rekursive Wörterbuch-Funktion:

def update_dictionary(template_dict, **kwargs): 
for k, v in kwargs.items(): 
    print(v) 
    print(isinstance(v, collections.Mapping)) 
    if isinstance(v, collections.Mapping): 
     print("This is the k value") 
     print(k) 
     template_dict[k] = update_dictionary(template_dict.get(k, {}), v) 
    else: 
     print("We're going into the else now") 
     template_dict[k] = v 
return template_dict 

ich habe die obige Funktion aus einem anderen Forum hier, aber es funktioniert scheint nicht zu funktionieren, wenn man Kwargs passiert. Für alle Felder, die sich nicht in der ersten Ebene des verschachtelten Wörterbuchs befinden, erweist sich die Instanzprüfung von instance als False. Jede Hilfe wird geschätzt!

Linie in Test, bei dem der kwargs übergeben werden:

new_dict = update_dictionary(template_dict, another_field = 'false', integer_value=12345) 
+1

Keys wird nie eine Instanz von 'collections.Mapping', zumindest nicht, bis Sie eine hashable Mapping implementieren. Du meinst wahrscheinlich 'isinstance (v, collections.Mapping)' –

+0

Ah, ja, das war ein Tippfehler für mich. (v, collections.Mapping) gibt in diesem Fall auch False für alle verschachtelten Wörterbuchschlüssel zurück. – cityofbombaylylove

+0

Außerdem müssen Sie die 'Kwargs' weiterreichen .... –

Antwort

0

So müssen Sie die kwargs vorbei zu halten, sonst alles über die erste Ebene wird nichts zu ersetzen! Hier ist eine schnelle und unsaubere Demonstration:

def update_dict(d, **kwargs): 
    new = {} 
    for k, v in d.items(): 
     if isinstance(v, dict): 
      new[k] = update_dict(v, **kwargs) 
     else: 
      new[k] = kwargs.get(k, v) 
    return new 

In Aktion:

In [16]: template 
Out[16]: 
{'id': 'id_1234', 
'integer_value': 1234, 
'level_one': {'another_field': 'true', 
    'bar': 15000, 
    'foo': 'true', 
    'id': 1234, 
    'level_two': {'thing_one': {'no': 'false', 'yes': 'false'}, 
    'thing_two': {'no': 'false', 'yes': 'false'}}, 
    'list_one': [], 
    'list_two': [522], 
    'url': 'http://google.com'}} 

In [17]: update_dict(template, another_field = 'false', integer_value=12345) 
Out[17]: 
{'id': 'id_1234', 
'integer_value': 12345, 
'level_one': {'another_field': 'false', 
    'bar': 15000, 
    'foo': 'true', 
    'id': 1234, 
    'level_two': {'thing_one': {'no': 'false', 'yes': 'false'}, 
    'thing_two': {'no': 'false', 'yes': 'false'}}, 
    'list_one': [], 
    'list_two': [522], 
    'url': 'http://google.com'}} 

Und wieder:

In [19]: update_dict(template, another_field = 'false', integer_value=12345, no='FOO') 
Out[19]: 
{'id': 'id_1234', 
'integer_value': 12345, 
'level_one': {'another_field': 'false', 
    'bar': 15000, 
    'foo': 'true', 
    'id': 1234, 
    'level_two': {'thing_one': {'no': 'FOO', 'yes': 'false'}, 
    'thing_two': {'no': 'FOO', 'yes': 'false'}}, 
    'list_one': [], 
    'list_two': [522], 
    'url': 'http://google.com'}} 

Hinweis, diese Implementierung eine völlig neue dict zurück, das ist was ich vermute, dass Sie wollten, seit template ist eine Vorlage, und Sie haben geschrieben:

new_dict = update_dictionary(template_dict, another_field = 'false', integer_value=12345) 

Aber wenn Sie tatsächlich an Ort und Stelle ändern möchten, können Sie einfach ändern:

def update_dict(d, **kwargs): 
    for k, v in d.items(): 
     if isinstance(v, dict): 
      update_dict(v, **kwargs) 
     else: 
      d[k] = kwargs.get(k, v) 

ich mit dem Nicht-in-Place-Version ... Hinweis gehen würde, können Sie tut dies mit einem frechen Einzeiler, obwohl ich es nicht empfehlen würde:

def update_dict(d, **kwargs): 
    return {k:update_dict(v, **kwargs) if isinstance(v, dict) else kwargs.get(k,v) for k,v in d.items()} 
+0

Vielen Dank SO VIEL! Ich muss tatsächlich in-place ändern, also habe ich Ihren Vorschlag verwendet und (v, dict) durch (v, collections.Mapping) ersetzt, da ich einige andere Datentypen habe, die ebenfalls geändert werden müssten. Ich habe die ganze Zeit gegen die Kwarts gecheckt, anstatt das Vorlagenwörterbuch! Es macht jetzt alles Sinn – cityofbombaylylove

Verwandte Themen