Zauważyłem, że po uruchomieniu poniższego modułu json w języku Python (dołączony od wersji 2.6) konwertuje klucze słownika int na ciągi.
>>> import json
>>> releases = {1: "foo-v0.1"}
>>> json.dumps(releases)
'{"1": "foo-v0.1"}'
Czy istnieje prosty sposób na zachowanie klucza jako int, bez konieczności analizowania ciągu przy zrzucie i załadowaniu. Uważam, że byłoby to możliwe przy użyciu haków dostarczonych przez moduł json, ale znowu wymaga to analizy. Czy jest jakiś argument, który przeoczyłem? okrzyki, chaz
Pytanie podrzędne: Dziękuję za odpowiedzi. Biorąc pod uwagę, że json działa tak, jak się obawiałem, czy istnieje łatwy sposób na przekazanie typu klucza poprzez może analizę danych wyjściowych zrzutów? Powinienem również zauważyć, że kod wykonujący zrzut i kod pobierający obiekt json z serwera i ładujący go, są napisane przeze mnie.
Odpowiedzi:
To jedna z tych subtelnych różnic między różnymi kolekcjami map, które mogą cię ugryźć. JSON traktuje klucze jako ciągi znaków; Python obsługuje różne klucze różniące się tylko typem.
W Pythonie (i najwyraźniej w Lua) kluczami do mapowania (odpowiednio słownika lub tabeli) są odwołania do obiektów. W Pythonie muszą być typami niezmiennymi lub muszą być obiektami implementującymi
__hash__
metodę. (Dokumentacja Lua sugeruje, że automatycznie używa identyfikatora obiektu jako skrótu / klucza nawet dla obiektów podlegających zmianom i polega na internowaniu ciągów, aby zapewnić, że równoważne ciągi są mapowane na te same obiekty).W Perlu, Javascript, awk i wielu innych językach klucze do skrótów, tablic asocjacyjnych lub czegokolwiek, co się nazywa w danym języku, to łańcuchy (lub „skalary” w Perlu). W perlu
$foo{1}, $foo{1.0}, and $foo{"1"}
są wszystkie odniesienia do tego samego mapowania w%foo
--- klucz jest oceniany jako skalar!JSON powstał jako technologia serializacji JavaScript. (JSON oznacza J Ava S CRIPT O bject N otation). Naturalnie realizuje semantyki dla jego zapis mapowania, które są zgodne z jego semantyki mapowania.
Jeśli oba końce serializacji mają być w Pythonie, lepiej byłoby użyć pikli. Jeśli naprawdę potrzebujesz przekonwertować je z powrotem z JSON na natywne obiekty Pythona, myślę, że masz kilka możliwości. Najpierw możesz spróbować (
try: ... except: ...
), aby przekonwertować dowolny klucz na liczbę w przypadku niepowodzenia wyszukiwania w słowniku. Alternatywnie, jeśli dodasz kod na drugim końcu (serializator lub generator tych danych JSON), możesz zlecić wykonanie serializacji JSON na każdej z wartości klucza - dostarczając je jako listę kluczy. (Następnie twój kod Pythona najpierw iteruje listę kluczy, tworząc instancję / deserializując je w natywne obiekty Pythona ... a następnie użyje ich do uzyskania dostępu do wartości poza mapowaniem).źródło
Nie, w JavaScript nie ma czegoś takiego jak klawisz numeryczny. Wszystkie właściwości obiektu są konwertowane na String.
Może to prowadzić do dziwnych, pozornych zachowań:
Obiekty JavaScript nie są tak naprawdę poprawnymi odwzorowaniami, jak można to rozumieć w językach takich jak Python, a używanie kluczy, które nie są ciągami znaków, prowadzi do dziwności. Dlatego JSON zawsze jawnie zapisuje klucze jako ciągi, nawet jeśli nie wydaje się to konieczne.
źródło
999999999999999999999
konwertowany na'999999999999999999999'
?Number
Typ jest IEEE 754 podwójna wartość zmiennoprzecinkowa: masz 53 bitów mantysy, dzięki czemu można przechowywać do 2⁵³ (9007199254740992) z dokładnością do liczby całkowitej; poza tą liczbą całkowitą zaokrągli się do innych wartości (stąd 9007199254740993 === 9007199254740992). 999999999999999999999 zaokrągla liczbę do 1000000000000000000000, dla której domyślnątoString
reprezentacją jest1e+21
.Alternatywnie możesz również spróbować przekonwertować słownik na listę formatu [(k1, v1), (k2, v2)] podczas kodowania go przy użyciu json i przekonwertować go z powrotem do słownika po zdekodowaniu.
Uważam, że będzie to wymagało trochę więcej pracy, na przykład posiadania jakiejś flagi, aby zidentyfikować wszystkie parametry, które mają zostać przekonwertowane na słownik po zdekodowaniu z powrotem z json.źródło
Odpowiadając na Twoje pytanie:
Można to osiągnąć za pomocą
json.loads(jsonDict, object_hook=jsonKeys2int)
Ta funkcja będzie również działać w przypadku poleceń zagnieżdżonych i używa rozumienia dyktowania.
Jeśli chcesz również rzutować wartości, użyj:
Który testuje instancję wartości i rzuca je tylko wtedy, gdy są one obiektami łańcuchowymi (dokładnie w formacie Unicode).
Obie funkcje przyjmują, że klucze (i wartości) są liczbami całkowitymi.
Dzięki:
Jak używać if / else w rozumieniu słownikowym?
Przekonwertuj klucz ciągu na int w słowniku
źródło
Ugryzł mnie ten sam problem. Jak zauważyli inni, w JSON klucze mapowania muszą być ciągami. Możesz zrobić jedną z dwóch rzeczy. Możesz użyć mniej rygorystycznej biblioteki JSON, takiej jak demjson , która zezwala na ciągi liczb całkowitych. Jeśli żadne inne programy (lub żadne inne programy w innych językach) nie będą go czytać, wszystko powinno być w porządku. Możesz też użyć innego języka serializacji. Nie sugerowałbym marynaty. Jest trudny do odczytania i nie jest zaprojektowany jako bezpieczny . Zamiast tego sugerowałbym YAML, który jest (prawie) nadzbiorem JSON i dopuszcza klucze całkowite. (A przynajmniej PyYAML .)
źródło
Przekonwertuj słownik na ciąg przy użyciu,
str(dict)
a następnie przekonwertuj go z powrotem na dict, wykonując następujące czynności:źródło
Oto moje rozwiązanie! Użyłem
object_hook
, jest to przydatne, gdy masz zagnieżdżonejson
Istnieje filtr tylko do analizowania klucza json do int. Możesz również użyć
int(v) if v.lstrip('-').isdigit() else v
filtru dla wartości json.źródło
Zrobiłem bardzo proste rozszerzenie odpowiedzi Murmela, które, jak sądzę, będzie działać na dość arbitralnym słowniku (w tym zagnieżdżonym), zakładając, że może zostać zrzucone przez JSON w pierwszej kolejności. Wszystkie klucze, które można zinterpretować jako liczby całkowite, zostaną rzutowane na int. Bez wątpienia nie jest to zbyt wydajne, ale działa na potrzeby przechowywania i ładowania z ciągów json.
Zakładając, że wszystkie klucze w oryginalnym dict są liczbami całkowitymi, jeśli można je rzutować na int, to zwróci oryginalny słownik po zapisaniu jako json. na przykład
źródło
Możesz napisać swój
json.dumps
samodzielnie, oto przykład z djson : encoder.py . Możesz go używać w ten sposób:źródło