2013-03-18 11 views
33

Ich habe die folgende Zeichenfolgeeinen JSON-String für ein Objekt in Python Deserialize

{"action":"print","method":"onData","data":"Madan Mohan"} 

ich zu einem Objekt der Klasse deserialisieren Will

class payload 
    string action 
    string method 
    string data 

ich verwende Python 2.6 und 2.7

+0

Mögliche doppelte: http://stackoverflow.com/questions/6578986/how-to-convert-json-data-into-a-python-object –

Antwort

70
>>> j = '{"action": "print", "method": "onData", "data": "Madan Mohan"}' 
>>> import json 
>>> 
>>> class Payload(object): 
...  def __init__(self, j): 
...   self.__dict__ = json.loads(j) 
... 
>>> p = Payload(j) 
>>> 
>>> p.action 
'print' 
>>> p.method 
'onData' 
>>> p.data 
'Madan Mohan' 
+0

thnx für die Antwort nicht in der Lage json –

+0

@madanmohan, das json-Modul importieren ist Standard in [Python2.6 +] (http://docs.python.org/2.6/library/json.html). Überprüfen Sie Ihre Python-Version –

+0

hai es funktioniert für mich Vielen Dank Ich habe es am Anfang der Datei –

25

Um auf Samis Antwort zu erarbeiten:

Von the docs:

class Payload(object): 
    def __init__(self, action, method, data): 
     self.action = action 
     self.method = method 
     self.data = data 

import json 

def as_payload(dct): 
    return Payload(dct['action'], dct['method'], dct['data']) 

payload = json.loads(message, object_hook = as_payload) 

Mein Einwand gegen die

.__dict__ 

Lösung ist, dass, während sie die Arbeit erledigt und prägnant ist, wird die Payload-Klasse total generische - es dokumentiert nicht seine Felder.

Wenn beispielsweise die Payload-Nachricht ein unerwartetes Format hatte, wurde bei der Erstellung der Payload kein Fehler ausgegeben, sondern ein Fehler, bis die Payload verwendet wurde.

7

Wenn Sie Codezeilen speichern möchten, und lassen Sie die flexibelste Lösung, können wir die JSON-String zu einem dynamischen Objekt deserialisieren:

p = lambda:None 
p.__dict__ = json.loads('{"action": "print", "method": "onData", "data": "Madan Mohan"}') 


>>>> p.action
Ausgang: u'print '

>>>> p.method
output: u'onData'

+3

Dies ist verlockend nahe, aber nicht mit verschachtelten JSON. 'p .__ dict__ = json.loads ('{" parent ": {" child ": {" name ":" henry "}}}') erfordert immer noch den Zugriff auf das Kind wie ein Diktat. – MarkHu

3

Ich bevorzuge es, eine Überprüfung der Felder hinzuzufügen, z. so können Sie Fehler wie zu fangen, wenn Sie ungültige json bekommen, oder nicht die json Sie erwartet hatten, so habe ich namedtuples:

from collections import namedtuple 
payload = namedtuple('payload', ['action', 'method', 'data']) 
def deserialize_payload(json): 
    kwargs = dict([(field, json[field]) for field in payload._fields]) 
    return payload(**kwargs) 

dies wird Ihnen schöne Fehler geben lassen, wenn die json Sie Parsen die Sache nicht überein Sie möchten, dass es analysiert

>>> json = {"action":"print","method":"onData","data":"Madan Mohan"} 
>>> deserialize_payload(json) 
payload(action='print', method='onData', data='Madan Mohan') 
>>> badjson = {"error":"404","info":"page not found"} 
>>> deserialize_payload(badjson) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in deserialize_payload 
KeyError: 'action' 

Wenn Sie verschachtelte Beziehungen analysieren möchten, z '{"parent":{"child":{"name":"henry"}}}' können Sie immer noch die namedtuples verwenden, und sogar eine wiederverwendbare Funktion Sie

Person = namedtuple("Person", ['parent']) 
Parent = namedtuple("Parent", ['child']) 
Child = namedtuple('Child', ['name']) 
def deserialize_json_to_namedtuple(json, namedtuple): 
    return namedtuple(**dict([(field, json[field]) for field in namedtuple._fields])) 

def deserialize_person(json): 
    json['parent']['child'] = deserialize_json_to_namedtuple(json['parent']['child'], Child) 
    json['parent'] = deserialize_json_to_namedtuple(json['parent'], Parent) 
    person = deserialize_json_to_namedtuple(json, Person) 
    return person 

geben

>>> deserialize_person({"parent":{"child":{"name":"henry"}}}) 
Person(parent=Parent(child=Child(name='henry'))) 
>>> deserialize_person({"error":"404","info":"page not found"}) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 2, in deserialize_person 
KeyError: 'parent' 
3

Wenn Sie die Art Hinweise in Python 3 umarmen.6, können Sie es wie folgt tun:

def from_json(data, cls): 
    annotations: dict = cls.__annotations__ if hasattr(cls, '__annotations__') else None 
    if issubclass(cls, List): 
     list_type = cls.__args__[0] 
     instance: list = list() 
     for value in data: 
      instance.append(from_json(value, list_type)) 
     return instance 
    elif issubclass(cls, Dict): 
      key_type = cls.__args__[0] 
      val_type = cls.__args__[1] 
      instance: dict = dict() 
      for key, value in data.items(): 
       instance.update(from_json(key, key_type), from_json(value, val_type)) 
      return instance 
    else: 
     instance : cls = cls() 
     for name, value in data.items(): 
      field_type = annotations.get(name) 
      if inspect.isclass(field_type) and isinstance(value, (dict, tuple, list, set, frozenset)): 
       setattr(instance, name, from_json(value, field_type)) 
      else: 
       setattr(instance, name, value) 
     return instance 

die dann können Sie typisierte Objekte wie diese instanziiert tun:

class Bar: 
    value : int 

class Foo: 
    x : int 
    bar : List[Bar] 


obj : Foo = from_json(json.loads('{"x": 123, "bar":[{"value": 3}, {"value": 2}, {"value": 1}]}'), Foo) 
print(obj.x) 
print(obj.bar[2].value) 

Diese Syntax Python erfordert 3.6 obwohl und deckt nicht alle Fälle - zum Beispiel, Unterstützung für tipping.Any ... Aber zumindest verschmutzt es nicht die Klassen, die mit zusätzlichen init/tojson-Methoden deserialisiert werden müssen.

Verwandte Themen