2016-01-21 21 views
5

Python 3'ün json.dumps numaralı uygulamasında bazı garip davranışlar gözlemledim, yani aynı nesneyi infazdan çalıştırmaya her bıraktığımda anahtar sipariş değişiklikleri. Anahtarlar, anahtarları sıralamakla ilgilenmediğim için işe yaramadı, sadece aynı kalmasını istiyorum!JSON anahtar sırasını Python 3 json.dumps ile nasıl sabit tutarım?

$ python print_data.py 
{ 
    "groceries": [ 
    "apples", 
    "bananas", 
    "pears" 
    ], 
    "isadmin": false, 
    "nested": { 
    "value": 2153.23412, 
    "complex": true 
    }, 
    "email": "[email protected]", 
    "number": 42, 
    "name": "John Doe", 
    "balance": 235.03 
} 

Ama sonra yeniden çalıştırın ve ben olsun: Bu komut dosyasını çalıştırdığınızda

import json 

data = { 
    'number': 42, 
    'name': 'John Doe', 
    'email': '[email protected]', 
    'balance': 235.03, 
    'isadmin': False, 
    'groceries': [ 
     'apples', 
     'bananas', 
     'pears', 
    ], 
    'nested': { 
     'complex': True, 
     'value': 2153.23412 
    } 
} 

print(json.dumps(data, indent=2)) 

Ben örneğin, farklı çıkışları her zaman olsun: İşte bir örnek script

$ python print_data.py 
{ 
    "email": "[email protected]", 
    "balance": 235.03, 
    "name": "John Doe", 
    "nested": { 
    "value": 2153.23412, 
    "complex": true 
    }, 
    "isadmin": false, 
    "groceries": [ 
    "apples", 
    "bananas", 
    "pears" 
    ], 
    "number": 42 
} 

Sözlüklerin sıralanmamış koleksiyonlar olduğunu ve siparişin bir karma işlevine dayandığını; ancak Python 2'de - sipariş (her ne ise) sabittir ve yürütme başına değişmez. Buradaki zorluk, testlerimin yürütülmesi zor olmasıdır çünkü iki farklı modülün JSON çıktısını karşılaştırmam gerekiyor!

Neler olduğu hakkında bir fikrin var mı? Nasıl düzeltilir? Bir OrderedDict kullanmaktan kaçınmak veya herhangi bir sıralama yapmak istemediğimi ve önemli olanın dize gösteriminin infazlar arasında aynı kalması olduğunu belirtmek isterim. Ayrıca bu sadece test amaçlıdır ve modülümün uygulanması üzerinde herhangi bir etkisi yoktur.

+0

Siparişin Python 2'de düzeltilmesinin tek nedeninin, yanlışlıkla 'sort_keys = True' –

+0

@WayneWerner'ın kazara olmadıkça garanti edilemeyeceğini garanti edebilirim; hash fonksiyonları belirleyicidir - aşağıdaki yorumları görün, rastgele bir hash tohumu eklenmesi nedeniyle Python 3.3'ten sonra sipariş değişiklikleri. – bbengfort

+0

Eh, ben düzeltilmeyi bekliyorum! Çok ilginç. –

cevap

8

Python sözlükleri ve JSON nesneleri sırasız şeklindedir. , numarasına json.dumps() numaralı telefonu sorabilir; Bu, testi kolaylaştırmak içindir. True için sort_keys parametreyi kullanın:

print(json.dumps(data, indent=2, sort_keys=True)) 

farklı bir düzeni her zaman görmek neden olarak Why is the order in Python dictionaries and sets arbitrary? bakınız.

PYTHONHASHSEED environment variable, sözlük sırasını 'kilitlemek' için bir tamsayı değerine ayarlayabilirsiniz; Bu, yalnızca rastgele rastgele hale getirme işleminin tümünün bir saldırganın programınızı DOS programına almasını engellemek olduğu için, yalnızca testler yapmak ve üretimde değil, bunu kullanmak için kullanın.

+0

Bağlandığınız gönderiden aradığım şey şu: "Python 3.3'ten itibaren rastgele bir hash tohumu kullanıldığını ve karma çarpışmaların öngörülemeyeceğini unutmayın. belirli hizmet reddi türlerini engellemek için (bir saldırganın kitle karma çarpışmalarına neden olarak bir Python sunucusunu yanıt vermemesi durumunda). Bu, belirli bir sözlüğün sırasının, o sırada geçerli Python çağrısının rastgele hash tohuma da bağlı olduğu anlamına gelir. " – bbengfort

+0

Test amaçlı hash tohumu nasıl tamir edeceğinizi biliyor musunuz? Testlerim json.dumps işlevine fazladan argüman iletmememi gerektirir. – bbengfort

+2

@bbengfort: [PYTHONHASHSEED] ortam değişkenini (https://docs.python.org/3/using/cmdline.html#envvar-PYTHONHASHSEED) bir tamsayı değerine ayarlayabilirsiniz. –

0

Bu davranışın arkasındaki hikaye, this güvenlik açığına uygundur. Bunu önlemek için, bir PC'deki aynı karma kodların bir diğerinde farklı olması gerekir. Python 2, bu davranışı (örneğin, rastgele hale getirme) varsayılan olarak, uyumluluk nedeniyle varsayılan olarak devre dışı bırakmıştır; Python 3 muhtemelen (varsayım) uygunluğa ihtiyaç duymamıştır.

İlgili konular