JSON'u bir OrderedDict'e yükleyebilir miyim?


428

Tamam böylece içinde bir OrderedDict kullanabilirsiniz json.dump. Yani, bir OrderedDict JSON'a girdi olarak kullanılabilir.

Ama çıktı olarak kullanılabilir mi? Öyleyse nasıl? Benim durumumda loaddosyadaki anahtarların sırasını koruyabilmem için bir OrderedDict içine istiyorum .

Değilse, bir tür geçici çözüm var mı?


Asla düzeni korumaya çalışmadım, ancak bunun nasıl yararlı olacağını kesinlikle görebiliyorum.
feathj

1
Evet, benim durumumda farklı diller ve uygulamalar arasındaki boşluğu dolduruyorum ve JSON çok iyi çalışıyor. Ancak anahtarların sıralanması biraz sorun. json.loadPython Dicts yerine OrderedDicts kullanmak için işaretlemek için basit olurdu harika olurdu .
c00kiemonster

3
JSON spec, nesne türünü sırasız anahtarlara sahip olarak tanımlıyor ... belirli anahtar sırasını beklemek bir hatadır
Anentropic

3
Anahtar siparişi genellikle herhangi bir işlevsel gereksinim için değildir. Sadece insanın okuyabildiği için. Json'umun güzel yazdırılmasını istiyorsam, belge düzeninin hiçbirinin değişmesini beklemiyorum.
Turşu

5
Ayrıca büyük git diffs önlemek için yardımcı olur!
Richard Rast

Yanıtlar:


610

Evet yapabilirsin. JSONDecoderobject_pairs_hook argümanını belirterek . Aslında, bu belgelerde verilen tam örnektir.

>>> json.JSONDecoder(object_pairs_hook=collections.OrderedDict).decode('{"foo":1, "bar": 2}')
OrderedDict([('foo', 1), ('bar', 2)])
>>> 

Bu parametreyi json.loads(başka amaçlar için bir Kod Çözücü örneğine ihtiyacınız yoksa) şu şekilde geçirebilirsiniz :

>>> import json
>>> from collections import OrderedDict
>>> data = json.loads('{"foo":1, "bar": 2}', object_pairs_hook=OrderedDict)
>>> print json.dumps(data, indent=4)
{
    "foo": 1,
    "bar": 2
}
>>> 

Kullanımı json.loadaynı şekilde yapılır:

>>> data = json.load(open('config.json'), object_pairs_hook=OrderedDict)

3
Ben şaşkınım. Dokümanlar, çiftler halinde kodu çözülen her bir hazır bilgi için object_pairs_hook'un çağrıldığını söylüyor. Bu neden JSON'daki her kayıt için yeni bir OrderedDict oluşturmuyor?
Tim Keating

3
Hmm ... dokümanlar biraz belirsizce ifade ediliyor. "Tüm çiftleri deşifre etmenin tüm sonucu", object_pairs_hook"her bir çift object_pairs_hook'a geçilecek" yerine , bir liste olarak sırayla geçirileceklerdir
SingleNegationElimination 25:14

Ama giriş json orijinal sırasını kaybeder mi?
SIslam

json.loadVarsayılan olarak sipariş vermediğini görmek şaşırdı , ancak sadece json'un yaptığı şeyi yansıtıyor gibi görünüyor - {}sırasız, ancak []json'da burada açıklandığı gibi sipariş verildi
kakule

1
@RandomCertainty evet, kaynak ayrıştırılırken bir JSON nesnesiyle her karşılaşıldığında OrderedDictortaya çıkan python değerini oluşturmak için kullanılır.
SingleNegationElimination

125

Python 2.7+ için basit sürüm

my_ordered_dict = json.loads(json_str, object_pairs_hook=collections.OrderedDict)

Veya Python 2.4 ila 2.6 için

import simplejson as json
import ordereddict

my_ordered_dict = json.loads(json_str, object_pairs_hook=ordereddict.OrderedDict)

4
Ahhh, ama object_pairs_hook'u içermiyor - bu yüzden 2.6'da hala simplejson'a ihtiyacınız var. ;)
mjhm

8
Bunu not etmek ister simplejsonve ordereddictyüklemeniz gereken ayrı kütüphanelerdir.
phunehehe

2
python 2.7+ için: sistemde "içe aktarma json, koleksiyonlar", sistemde python2.6- "yetenek yükleme python-pip" ve "pip install orderdict"
ZiTAL

Bu JSONDecoder ile önceki yönteme göre çok daha kolay ve hızlı ileri.
Natim

Garip bir şekilde, pypy'de, dahil edilen json başarısız olacaktır loads('{}', object_pairs_hook=OrderedDict).
Matthew Schinckel

37

Harika haberlerimiz var! 3.6 sürümünden bu yana, cPython uygulaması sözlüklerin ekleme sırasını korumuştur ( https://mail.python.org/pipermail/python-dev/2016-September/146327.html ). Bu, json kütüphanesinin artık varsayılan olarak sipariş koruması olduğu anlamına gelir. Python 3.5 ve 3.6 arasındaki davranış farkını gözlemleyin. Kod:

import json
data = json.loads('{"foo":1, "bar":2, "fiddle":{"bar":2, "foo":1}}')
print(json.dumps(data, indent=4))

Py3.5 sürümünde ortaya çıkan sipariş tanımlanmamıştır:

{
    "fiddle": {
        "bar": 2,
        "foo": 1
    },
    "bar": 2,
    "foo": 1
}

Python 3.6'nın cPython uygulamasında:

{
    "foo": 1,
    "bar": 2,
    "fiddle": {
        "bar": 2,
        "foo": 1
    }
}

Gerçekten harika bir haber, bunun python 3.7'den (cPython 3.6+ uygulama detayının aksine) bir dil spesifikasyonu haline gelmesidir: https://mail.python.org/pipermail/python-dev/2017-December/151283 .html

Böylece sorunuzun cevabı şimdi: python 3.6'ya yükseltin! :)


1
Verilen örnekte sizinle aynı davranışı görsem de, Python 3.6.4'ün CPython uygulamasında benim için json.loads('{"2": 2, "1": 1}')olur {'1': 1, '2': 2}.
fuglede

1
@fuglede dict.__repr__, temeldeki sıralama korunurken sıralama anahtarları gibi görünür . Başka bir deyişle, json.loads('{"2": 2, "1": 1}').items()bir dict_items([('2', 2), ('1', 1)])dahi repr(json.loads('{"2": 2, "1": 1}'))olduğunu "{'1': 1, '2': 2}".
Simon Charette

@SimonCharette Hm olabilir; Aslında kendi gözlemlerimi conda'nın pkgs / main / win-64 :: python-3.6.4-h0c2934d_3 dizininde üretemiyorum, bu yüzden bunu test etmek zor olacak.
fuglede

"Yeniden adlandırma" tuşları hala anahtarların sırasını mahvedeceğinden, bu gerçekten çok yardımcı olmaz.
Hubro

7

Dikteyi boşaltmanın yanı sıra her zaman anahtar listesini yazabilir ve daha sonra OrderedDictlisteyi yineleyerek yeniden yapılandırabilirsiniz ?


1
Düşük teknolojili çözüm için +1. Bunu YAML ile aynı sorunla uğraşırken yaptım, ancak çoğaltmak zorunda kalmak, özellikle temel format düzeni koruduğunda biraz topal. Dikte olan ancak anahtar listesinden eksik olan anahtar / değer çiftlerini kaybetmekten kaçınmak da mantıklı olabilir, açıkça sipariş edilen tüm öğelerden sonra bunları takmak.
Mu Mind

2
Düşük teknoloji çözümü ayrıca dışa aktarılan formatta zorunlu olarak korunmayan içeriği de korur (IOW; birisi JSON'u görür ve üzerinde manipülasyonlar yaparsa "bu anahtarların bu sırada kalması gerektiğini" belirten hiçbir şey yoktur).
Amber

"Boşaltılan" anahtar listesinin doğru sırada olduğunu belirleyen nedir? Yuvalanmış dikte ne olacak? Görünüşe göre hem damping bunun üstesinden gelecek hem de rekonstrüksiyon OrdereDicts kullanarak tekrarlamalı olarak yapılacak .
martineau

5

Sıralı anahtar listesini sözlüğün yanına dökmenin yanı sıra, açık olma avantajına sahip başka bir düşük teknolojili çözüm, anahtar / değer çiftlerinin (sıralı) listesini dökmektir ordered_dict.items(); yükleme basittir OrderedDict(<list of key-value pairs>). Bu, JSON'un bu konsepte sahip olmamasına rağmen sıralı bir sözlüğü ele alır (JSON sözlüklerinin sırası yoktur).

jsonOrderedDict'i doğru sırayla boşaltmaktan gerçekten faydalanmak güzel . Ancak, genel olarak gereksiz derecede ağırdır ve tüm JSON sözlüklerini bir OrderedDict olarak okumak zorunda olmak zorunda değildir ( object_pairs_hookargüman aracılığıyla ), bu yüzden sadece sipariş edilmesi gereken sözlüklerin açık bir şekilde dönüştürülmesi de mantıklıdır.


4

Object_pairs_hook parametresini belirtirseniz normalde kullanılan load komutu çalışır :

import json
from  collections import OrderedDict
with open('foo.json', 'r') as fp:
    metrics_types = json.load(fp, object_pairs_hook=OrderedDict)
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.