Seite 1 von 1

Wie elegant unicode key in string key umwandeln?

Verfasst: Sonntag 22. November 2009, 16:31
von Hyperion
Hallo zusammen,

ich möchte Daten in einer JSON-Datei ablegen und diese bei Bedarf laden und an eine Funktion in meinem Script übergeben und zwar als Keyword-Argument.

Mein erster Anlauf endete so:

Code: Alles auswählen

In[7]: import json

In [8]: json.loads("""{"foo": "bar"}""")
Out[8]: {u'foo': u'bar'}                

In [9]: data = json.loads("""{"foo": "bar"}""")

In [10]: def foo(**kwargs):
   ....:     print kwargs  
   ....:                   
   ....:                   

In [12]: foo(**data)
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)

/home/nelson/src/Python/snippets/jinja2builder/data/<ipython console> in <module>()

TypeError: foo() keywords must be strings
Der key des dicts muss also als String vorliegen - so weit eigentlich kein Problem.

Code: Alles auswählen

In [16]: foo(**{"foo": u"bar"})
{'foo': u'bar'}
Nur wie bringe ich das json-Modul dazu, genau das auch umzusetzen?

Mein Ansatz war spontan dieser:

Code: Alles auswählen

def to_str_dict(arg):
    """
    converts a dict with unicode-key based dict into a string-key based one.
    """
    new_dict = {}
    for key, value in arg.iteritems():
        new_dict[str(key)] = value
    return new_dict

def load(filename):
    try:
        with open(filename, "r") as in_file:
            # die converter Funktion an den object_hook binden
            data = json.load(in_file, object_hook=to_str_dict)
        return data
    except IOError, e:
        print e
Meine Frage ist nun: Geht das irgend wie eleganter? Oder gibt es einen komplett anderen Ansatz dazu?

Hintergrund ist ein kleines Script, das ein jinja2-Template mit Daten aus dieser JSON Datei füttern soll - quasi als simpler Template Test.

Verfasst: Sonntag 22. November 2009, 16:56
von DasIch
to_str_dict kann man deutlich kürzer schreiben, ansonsten geht es nicht eleganter.

Code: Alles auswählen

def to_str_dict(d):
    return dict((str(k), v) for k, v in d.iteritems())

Verfasst: Samstag 28. November 2009, 11:26
von sma
Eine generelle Lösung kann es aber nicht sein, denn in der JSON-Datei könnten Attributnamen in den Objekten verwendet werden, die keine gültigen Bezeichner in Python sind. Ich denke daher, es wäre besser, das ganze JSON-Objekt in das Template hineinzureichen und nicht nur seine Attribute. Dies hier wäre ja auch gültiges JSON: `{"":null}`.

Stefan

Verfasst: Sonntag 29. November 2009, 18:37
von Hyperion
sma hat geschrieben:Eine generelle Lösung kann es aber nicht sein, denn in der JSON-Datei könnten Attributnamen in den Objekten verwendet werden, die keine gültigen Bezeichner in Python sind.
Stimmt! Soll es aber auch nicht unbedingt. Es dient ja nur zur Simulation von Daten, die später vermutlich aus einer Datenbank stammen.
Ich denke daher, es wäre besser, das ganze JSON-Objekt in das Template hineinzureichen und nicht nur seine Attribute. Dies hier wäre ja auch gültiges JSON: `{"":null}`.
Das will ich eigentlich nicht unbedingt, da ich das Template ja schon möglichst "realistisch" gestalten will, sprich ich will ja bereits die gleiche Anzahl an Objekten übergeben wie später mit "richtigen" Datenobjekten.

Aber danke für den guten Hinweis :-)