Próbuję utworzyć reprezentację ciągu JSON wystąpienia klasy i mam trudności. Powiedzmy, że klasa jest zbudowana w następujący sposób:
class testclass:
value1 = "a"
value2 = "b"
Wywołanie json.dumps odbywa się w następujący sposób:
t = testclass()
json.dumps(t)
Nie udaje się i mówi mi, że klasa testowa nie jest serializowalna w JSON.
TypeError: <__main__.testclass object at 0x000000000227A400> is not JSON serializable
Próbowałem także użyć modułu marynowanego:
t = testclass()
print(pickle.dumps(t, pickle.HIGHEST_PROTOCOL))
I daje informacje o instancji klasy, ale nie szereguje treści instancji klasy.
b'\x80\x03c__main__\ntestclass\nq\x00)\x81q\x01}q\x02b.'
Co ja robię źle?
python
json
serialization
pickle
ferhan
źródło
źródło
s = json.dumps(obj, default=lambda x: x.__dict__)
, do zmiennych instancji serializacji obiektu (self.value1
,self.value2
...). To najprostszy i najprostszy sposób. Będzie serializować struktury obiektów zagnieżdżonych.default
Funkcja jest wywoływana, gdy dany obiekt nie jest bezpośrednio serializacji. Możesz również spojrzeć na moją odpowiedź poniżej. Znalazłem popularne odpowiedzi niepotrzebnie złożone, które prawdopodobnie były prawdziwe już dawno temu.testclass
nie ma__init__()
metody, więc wszystkie instancje będą miały te same atrybuty klasy (value1
ivalue2
) zdefiniowane w instrukcji class. Czy rozumiesz różnicę między klasą a instancją jednej?Odpowiedzi:
Podstawowym problemem jest to, że koder JSON
json.dumps()
domyślnie serializuje tylko ograniczony zestaw typów obiektów, wszystkie typy wbudowane. Wymień tutaj: https://docs.python.org/3.3/library/json.html#encoders-and-decodersJednym dobrym rozwiązaniem byłoby, aby Twoja klasa odziedziczyła,
JSONEncoder
a następnie zaimplementowaćJSONEncoder.default()
funkcję i sprawiła, że ta funkcja emituje poprawny JSON dla twojej klasy.Rozwiązanie proste byłoby zadzwonić
json.dumps()
na.__dict__
członka tej instancji. Jest to standardowy Pythondict
i jeśli twoja klasa jest prosta, będzie można serializować JSON.Powyższe podejście omówiono w tym blogu:
Serializacja dowolnych obiektów Python do JSON przy użyciu __dict__
źródło
.__init__()
funkcji metody, więc instancja klasy ma pusty słownik. Innymi słowy,{}
jest poprawnym wynikiem dla twojego przykładowego kodu.is not JSON serializable
Jest dla mnie świetny sposób, który możesz wypróbować:
json.dumps()
może przyjąć opcjonalny parametr domyślny, w którym można określić niestandardową funkcję serializatora dla nieznanych typów, która w moim przypadku wyglądaPierwsze dwa ifs dotyczą serializacji daty i godziny, a potem jest
obj.__dict__
zwracany jest dowolny inny obiekt.ostatnie połączenie wygląda następująco:
Jest to szczególnie dobre, gdy serializujesz kolekcję i nie chcesz dzwonić
__dict__
jawnie dla każdego obiektu. Tutaj zrobisz to automatycznie.Do tej pory działało tak dobrze dla mnie, czekając na twoje przemyślenia.
źródło
NameError: name 'serialize' is not defined
. Jakieś wskazówki?try: dict = obj.__dict__ except AttributeError: dict = {s: getattr(obj, s) for s in obj.__slots__ if hasattr(obj, s)} return dict
Możesz podać
default
nazwany parametr wjson.dumps()
funkcji:Wyjaśnienie:
Utwórz dokumenty ( 2.7 , 3.6 ):
(Działa na Python 2.7 i Python 3.x)
Uwaga: W tym przypadku potrzebujesz
instance
zmiennych, a nieclass
zmiennych, tak jak w przykładzie z pytania. (Zakładam, że pytający miałclass instance
być przedmiotem klasy)Nauczyłem się tego po raz pierwszy z odpowiedzi @ phihag tutaj . Okazało się, że jest to najprostszy i najczystszy sposób na wykonanie zadania.
źródło
default=lambda x: getattr(x, '__dict__', str(x))
datetime.date
jest implementacją C, dlatego nie ma__dict__
atrybutu. IMHO ze względu na ujednolicenie,datetime.date
powinno go mieć ...Po prostu robię:
To nie jest pełna odpowiedź, a jeśli masz jakąś skomplikowaną klasę obiektów, na pewno nie dostaniesz wszystkiego. Jednak używam tego do niektórych moich prostych obiektów.
Jedną z nich, na której działa naprawdę dobrze, jest klasa „options” uzyskana z modułu OptionParser. Tutaj jest wraz z samym żądaniem JSON.
źródło
Korzystanie z jsonpickle
źródło
JSON nie jest tak naprawdę przeznaczony do serializacji dowolnych obiektów Pythona. Świetnie nadaje się do szeregowania
dict
obiektów, alepickle
moduł jest naprawdę tym, czego powinieneś ogólnie używać. Dane wyjściowepickle
nie są tak naprawdę czytelne dla człowieka, ale powinny być w porządku. Jeśli nalegasz na użycie JSON, możesz sprawdzićjsonpickle
moduł, który jest interesującym podejściem hybrydowym.https://github.com/jsonpickle/jsonpickle
źródło
Oto dwie proste funkcje serializacji dowolnych niewyrafinowanych klas, nic szczególnego, jak wyjaśniono wcześniej.
Używam tego do konfiguracji typu, ponieważ mogę dodawać nowych członków do klas bez żadnych modyfikacji kodu.
źródło
Istnieje kilka dobrych odpowiedzi na temat tego, jak zacząć to robić. Ale należy pamiętać o kilku rzeczach:
__slots__
zamiast__dict__
?json-tricks to biblioteka (którą stworzyłem i do której przyczyniłem się inni), która była w stanie to zrobić od dłuższego czasu. Na przykład:
Odzyskasz instancję. Tutaj Json wygląda tak:
Jeśli lubisz tworzyć własne rozwiązania, możesz spojrzeć na źródło,
json-tricks
aby nie zapomnieć o specjalnych przypadkach (jak__slots__
).Robi także inne typy, takie jak tablice numpy, czasy danych, liczby zespolone; pozwala również na komentarze.
źródło
Python3.x
Najlepsze podejście, jakie mogłem osiągnąć dzięki mojej wiedzy, było takie.
Zauważ, że ten kod również traktuje set ().
To podejście jest ogólne, wymaga jedynie rozszerzenia klasy (w drugim przykładzie).
Zauważ, że robię to tylko dla plików, ale łatwo jest zmodyfikować zachowanie według własnego uznania.
Jest to jednak CoDec.
Przy odrobinie pracy możesz zbudować swoją klasę na inne sposoby. Zakładam, że domyślny konstruktor to instancja, a następnie aktualizuję dyktę klasową.
Edytować
Po dalszych badaniach znalazłem sposób na uogólnienie bez konieczności wywoływania metody rejestrowania SUPERCLASS za pomocą metaklasy
źródło
Uważam, że zamiast dziedziczenia, jak sugerowano w zaakceptowanej odpowiedzi, lepiej jest użyć polimorfizmu. W przeciwnym razie musisz mieć dużą instrukcję if if, aby dostosować kodowanie każdego obiektu. Oznacza to, że utwórz ogólny domyślny koder dla JSON jako:
a następnie mieć
jsonEnc()
funkcję w każdej klasie, którą chcesz serializować. na przykładPotem dzwonisz
json.dumps(classInstance,default=jsonDefEncoder)
źródło