JSON nesnesindeki öğeler “json.dumps” kullanılarak düzgün değil mi?


157

json.dumpsGibi json dönüştürmek için kullanıyorum

countries.append({"id":row.id,"name":row.name,"timezone":row.timezone})
print json.dumps(countries)

Sahip olduğum sonuç:

[
   {"timezone": 4, "id": 1, "name": "Mauritius"}, 
   {"timezone": 2, "id": 2, "name": "France"}, 
   {"timezone": 1, "id": 3, "name": "England"}, 
   {"timezone": -4, "id": 4, "name": "USA"}
]

Anahtarları şu sırayla almak istiyorum: id, isim, saat dilimi - ama bunun yerine saat dilimi, id, isim var.

Bunu nasıl düzeltmeliyim?

Yanıtlar:


244

Hem Python dict(Python 3.7'den önce) hem de JSON nesnesi sıralanmamış koleksiyonlardır. sort_keysAnahtarları sıralamak için parametre iletebilirsiniz :

>>> import json
>>> json.dumps({'a': 1, 'b': 2})
'{"b": 2, "a": 1}'
>>> json.dumps({'a': 1, 'b': 2}, sort_keys=True)
'{"a": 1, "b": 2}'

Belirli bir siparişe ihtiyacınız varsa; Eğer verebilir kullanmakcollections.OrderedDict :

>>> from collections import OrderedDict
>>> json.dumps(OrderedDict([("a", 1), ("b", 2)]))
'{"a": 1, "b": 2}'
>>> json.dumps(OrderedDict([("b", 2), ("a", 1)]))
'{"b": 2, "a": 1}'

Python 3.6'dan beri , anahtar kelime bağımsız değişken sırası korunur ve yukarıdakiler daha güzel bir sözdizimi kullanılarak yeniden yazılabilir:

>>> json.dumps(OrderedDict(a=1, b=2))
'{"a": 1, "b": 2}'
>>> json.dumps(OrderedDict(b=2, a=1))
'{"b": 2, "a": 1}'

Bkz. PEP 468 - Anahtar Kelime Bağımsız Değişken Sırasını Koruma .

Girişinizi JSON olarak verilirse o zaman (almak düzeni korumak için OrderedDict), sen geçebileceği object_pair_hook, @Fred Yankowski önerdiği gibi :

>>> json.loads('{"a": 1, "b": 2}', object_pairs_hook=OrderedDict)
OrderedDict([('a', 1), ('b', 2)])
>>> json.loads('{"b": 2, "a": 1}', object_pairs_hook=OrderedDict)
OrderedDict([('b', 2), ('a', 1)])

2
OrderedDict'in init gerçekten çirkin
jean

3
@jean: başlangıç ​​değerinin bir ilgisi yoktur OrderedDict(), bir ' dicte OrderedDict()iletebilirsiniz, sipariş edilen çiftlerin bir listesini de iletebilirsiniz dict()- ancak bu her iki durumda da sipariş kaybedilir.
jfs

Yani sipariş korumak zaman init, birçok '(' ve ')' yazılması gerekiyor
jean

@jean: vardır ordereddict_literalsgelen codetransformerpaket (alfa kalite)
jfs

25
Ayrıca, JSON'u kullanarak yüklerseniz d = json.load(f, object_pairs_hook=OrderedDict), daha sonra json.dump(d)orijinal öğelerin sırası korunur.
Fred Yankowski

21

Diğerlerinin de belirttiği gibi, altta yatan diksiyon sırasızdır. Ancak python'da OrderedDict nesneleri vardır. (Son pitonlarda inşa edilmişlerdir veya bunu kullanabilirsiniz: http://code.activestate.com/recipes/576693/ ).

Yeni pitonlar json uygulamalarının yerleşik OrderedDicts'te doğru şekilde işlediğine inanıyorum, ancak emin değilim (ve teste kolay erişimim yok).

Eski pitonlar simplejson uygulamaları OrderedDict nesnelerini iyi işlemezler ve bunları çıkarmadan önce düzenli diktelere dönüştürürler ... ancak aşağıdakileri yaparak bunun üstesinden gelebilirsiniz:

class OrderedJsonEncoder( simplejson.JSONEncoder ):
   def encode(self,o):
      if isinstance(o,OrderedDict.OrderedDict):
         return "{" + ",".join( [ self.encode(k)+":"+self.encode(v) for (k,v) in o.iteritems() ] ) + "}"
      else:
         return simplejson.JSONEncoder.encode(self, o)

şimdi bunu kullanarak elde:

>>> import OrderedDict
>>> unordered={"id":123,"name":"a_name","timezone":"tz"}
>>> ordered = OrderedDict.OrderedDict( [("id",123), ("name","a_name"), ("timezone","tz")] )
>>> e = OrderedJsonEncoder()
>>> print e.encode( unordered )
{"timezone": "tz", "id": 123, "name": "a_name"}
>>> print e.encode( ordered )
{"id":123,"name":"a_name","timezone":"tz"}

Hangi hemen hemen istediğiniz gibi.

Başka bir alternatif, kodlayıcıyı doğrudan satır sınıfınızı kullanacak şekilde uzmanlaştırmak olabilir ve daha sonra herhangi bir ara dikte veya UnorderedDict'a ihtiyacınız olmaz.


5
JSON nesnelerinin yine de sırasız olduğunu unutmayın ; bir JSON istemcisi nesne tanımını okuyabilir ve anahtarların sırasını tamamen yok sayabilir ve RFC ile tamamen uyumlu olabilir.
Martijn Pieters

4
Martijn doğrudur, bu RFC uyumluluğunu etkilemez, ancak JSON'unuz için tutarlı bir biçime sahip olmak istiyorsanız kesinlikle değerli olabilir (Örneğin, dosya sürüm kontrolü altındaysa veya bir insan okuyucunun daha kolay olmasını sağlamak için giriş siparişini belgelerinizle eşleştirmeyi öğrenin.)
Michael Anderson

3
Bu durumda sadece set sort_keysiçin Trueçağrılırken json.dumps(); sipariş kararlılığı için (test, kararlı önbellekleme veya VCS taahhütleri için) sıralama anahtarları yeterlidir.
Martijn Pieters

7

Bir sözlüğün sırasının, tanımlandığı sıra ile herhangi bir ilişkisi yoktur. Bu, yalnızca JSON'a dönüştürülmüş olanlar için değil, tüm sözlükler için geçerlidir.

>>> {"b": 1, "a": 2}
{'a': 2, 'b': 1}

Gerçekten, sözlük bile ulaşmadan önce "baş aşağı" çevrildi json.dumps:

>>> {"id":1,"name":"David","timezone":3}
{'timezone': 3, 'id': 1, 'name': 'David'}

6

hey bu cevap için çok geç olduğunu biliyorum ama sort_keys ekleyin ve aşağıdaki gibi yanlış atayın:

json.dumps({'****': ***},sort_keys=False)

bu benim için çalıştı


4

json.dump (), sözlüğünüzün sırasını koruyacaktır. Dosyayı bir metin düzenleyicide açın, göreceksiniz. Bir OrderedDict gönderip göndermemenize bakılmaksızın siparişi koruyacaktır.

Ancak, Json.load (), yukarıda belirtilen JFSebastian komutunda belirtilen object_pairs_hook parametresiyle yapılan bir OrderedDict () öğesine yüklemesini söylemediğiniz sürece kaydedilen nesnenin sırasını kaybedecektir.

Aksi takdirde sıra kaybedilir, çünkü normal işlem altında, kaydedilen sözlük nesnesini düzenli bir diksiyona yükler ve düzenli bir diksiyon verilen öğelerin sırasını korumaz.


Bu aslında daha iyi bir çözümdür, çünkü yükteki siparişin korunması damping time siparişini halleder. Bu cevap için teşekkürler.
Arun R

2

JSON'da, Javascript'te olduğu gibi, nesne anahtarlarının sırası anlamsızdır, bu yüzden hangi sırayla gösterildikleri önemli değildir, aynı nesnedir.


(ve aynı şey standart bir Python için de geçerlidir dict)

12
ancak JSON ayrıştırılana kadar bir dize temsilidir, dize karşılaştırmaları (doctests gibi) yine de sipariş gerektirebilir. Bu yüzden asla önemli olmadığını söylemem.
Michael Scott Cuthbert

1
Bu Javascript (ECMA betiği) standardı için geçerli olsa da, tüm uygulamalar (dize) anahtarları kaynak düzeninde tutar.
thebjorn

1
@Paulpro gerçekten mi? hangisi? Chrome'un buradaki standardı bir kez izlemeye çalıştığını biliyorum, ancak gönderime gönderildi ( code.google.com/p/v8/issues/detail?id=164 ). Bundan sonra kimsenin aynı şeyi deneyeceğini sanmıyordum ...
thebjorn

2
@paulpro OP'nin sorusunu doğru bir şekilde ele alıyorsunuz. Bununla birlikte, düzeni korumak için meşru kullanımların olduğunu eklemek istiyorum. Örneğin, JSON yazan, bazı dönüştürme uygulayan ve sonuçları geri yazan bir komut dosyası yazılabilir. Farklı bir aracın değişiklikleri açıkça göstermesi için siparişin korunmasını istersiniz.
Paul Rademacher
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.