पायथन के जसन मॉड्यूल, इंट डिक्शनरी कीज़ को स्ट्रिंग्स में परिवर्तित करता है


130

मैंने पाया है कि जब निम्नलिखित चलाया जाता है, तो पायथन का जोंस मॉड्यूल (2.6 के बाद से शामिल) इंट डिक्शनरी कीज़ को स्ट्रिंग्स में परिवर्तित करता है।

>>> import json
>>> releases = {1: "foo-v0.1"}
>>> json.dumps(releases)
'{"1": "foo-v0.1"}'

क्या डंप और लोड पर स्ट्रिंग को पार्स करने की आवश्यकता के बिना, एक इंट के रूप में कुंजी को संरक्षित करने का कोई आसान तरीका है। मेरा मानना ​​है कि यह जसन मॉड्यूल द्वारा प्रदान किए गए हुक का उपयोग करके संभव होगा, लेकिन फिर भी इसके लिए पार्सिंग की आवश्यकता होती है। क्या संभवतः एक तर्क है जिसकी मैंने अनदेखी की है? चीयर्स, चेज़

उप-प्रश्न: उत्तर के लिए धन्यवाद। जब तक मुझे डर लगता है, तब तक डंप के आउटपुट को पार्स करके मुख्य प्रकार को व्यक्त करने का एक आसान तरीका है? इसके अलावा, मुझे डंपिंग करने वाले कोड को नोट करना चाहिए और सर्वर से जन्स ऑब्जेक्ट को डाउनलोड करने और उसे लोड करने का कोड, दोनों मेरे द्वारा लिखे गए हैं।


23
json कीज़ को स्ट्रिंग्स होना चाहिए
tonfa

जवाबों:


86

यह विभिन्न मानचित्रण संग्रहों में उन सूक्ष्म अंतरों में से एक है जो आपको काट सकते हैं। JSON स्ट्रिंग्स के रूप में कुंजियों का व्यवहार करता है; पायथन केवल प्रकार में भिन्न होने वाली अलग-अलग कुंजी का समर्थन करता है।

पायथन में (और स्पष्ट रूप से लूआ में) क्रमशः मानचित्रण (शब्दकोश या तालिका) की कुंजी वस्तु संदर्भ हैं। अजगर में वे अपरिवर्तनीय प्रकार के होने चाहिए, या वे ऐसी वस्तुएं होनी चाहिए जो एक __hash__विधि को लागू करती हैं। (लुआ डॉक्स का सुझाव है कि यह स्वचालित रूप से ऑब्जेक्ट की आईडी को हैश / कुंजी के रूप में भी उत्परिवर्तित वस्तुओं के लिए उपयोग करता है और यह सुनिश्चित करने के लिए स्ट्रिंग इंटर्न पर निर्भर करता है कि समान वस्तुओं के लिए समान स्ट्रिंग मैप्स)।

पर्ल, जावास्क्रिप्ट, awk और कई अन्य भाषाओं में हैश, एसोसिएटिव सरणियों या जो भी उन्हें दी गई भाषा के लिए कहा जाता है, वे स्ट्रिंग (या पर्ल में "स्केलर) हैं। पर्ल $foo{1}, $foo{1.0}, and $foo{"1"}में सभी समान मैपिंग के संदर्भ हैं %foo--- कुंजी का मूल्यांकन स्केलर के रूप में किया जाता है!

JSON एक जावास्क्रिप्ट सीरियलाइजेशन तकनीक के रूप में शुरू हुआ। (JSON का अर्थ है J ava S cript O bject N otation ।) स्वाभाविक रूप से यह अपने मानचित्रण संकेतन के लिए शब्दार्थ को लागू करता है जो इसके मानचित्रण शब्दार्थ के अनुरूप होते हैं।

यदि आपके क्रमांकन के दोनों सिरे पायथन हो रहे हैं तो आप अचार का उपयोग करना बेहतर समझेंगे। यदि आपको वास्तव में JSON से इन मूल देशी वस्तुओं में वापस बदलने की आवश्यकता है, तो मुझे लगता है कि आपके पास कुछ विकल्प हैं। पहले आप try: ... except: ...किसी शब्दकोश की विफलता की स्थिति में किसी भी कुंजी को संख्या में बदलने की कोशिश कर सकते हैं । वैकल्पिक रूप से, यदि आप दूसरे छोर पर कोड (इस JSON डेटा के क्रमिक या जनरेटर) को जोड़ते हैं, तो आप इसे कुंजी मानों की प्रत्येक सूची पर JSON क्रमांकन कर सकते हैं --- जो उन्हें कुंजी की सूची के रूप में प्रदान करते हैं। (तब आपका पायथन कोड सबसे पहले कुंजी की सूची पर पुनरावृति करेगा, उन्हें देशी पायथन ऑब्जेक्ट में त्वरित / डिसेररलाइज़ करना ... और फिर मैपिंग से मानों को एक्सेस करने के लिए उपयोग करें)।


1
उसके लिए धन्यवाद। दुर्भाग्य से मैं अचार का उपयोग नहीं कर सकता, लेकिन सूची के साथ आपका विचार बहुत अच्छा है। लागू होगा कि अब, विचार के लिए चीयर्स।
चार्ल्स रिची

1
(संयोग से, पायथन 1, 1 एल (लंबे पूर्णांक), और 1.0 मैप एक ही कुंजी के लिए; लेकिन "1" (एक स्ट्रिंग) 1 (पूर्णांक) या 1.0 (फ्लोट) या 1 एल (लंबे पूर्णांक) के समान नहीं है )।
जिम डेनिस

5
अचार का उपयोग करने की सिफारिश के साथ सतर्क रहें। अचार के परिणामस्वरूप मनमाने ढंग से कोड निष्पादन हो सकता है, इसलिए यदि आपके द्वारा डिस्क्राइबलाइज़ किए जा रहे डेटा का स्रोत स्वाभाविक रूप से भरोसेमंद नहीं है, तो आपको JSON की तरह "सुरक्षित" क्रमांकन प्रोटोकॉल से चिपके रहना चाहिए। यह भी ध्यान रखें कि जैसे-जैसे परियोजनाओं का दायरा विस्तृत होता है, कभी-कभी आपके द्वारा अपेक्षित कार्य केवल विश्वसनीय इनपुट प्राप्त करने लगते हैं, जो उपयोगकर्ता को इनपुट प्रदान करते हैं, और सुरक्षा कारणों पर हमेशा ध्यान नहीं दिया जाता है।
अनुस्वार

56

नहीं, जावास्क्रिप्ट में नंबर कुंजी जैसी कोई चीज नहीं है। सभी ऑब्जेक्ट गुण स्ट्रिंग में कनवर्ट किए जाते हैं।

var a= {1: 'a'};
for (k in a)
    alert(typeof k); // 'string'

यह कुछ जिज्ञासु-व्यवहार को जन्म दे सकता है:

a[999999999999999999999]= 'a'; // this even works on Array
alert(a[1000000000000000000000]); // 'a'
alert(a['999999999999999999999']); // fail
alert(a['1e+21']); // 'a'

जावास्क्रिप्ट ऑब्जेक्ट वास्तव में उचित मैपिंग नहीं हैं जैसा कि आप इसे पायथन जैसी भाषाओं में समझेंगे, और उन कुंजियों का उपयोग कर सकते हैं जो अजीबता में स्ट्रिंग परिणाम नहीं हैं। यही कारण है कि JSON हमेशा स्पष्ट रूप से कुंजी को स्ट्रिंग्स के रूप में लिखता है, यहां तक ​​कि जहां यह आवश्यक नहीं दिखता है।


1
में 999999999999999999999परिवर्तित क्यों नहीं किया जाता है '999999999999999999999'?
पायोत्र डोब्रोगोस्ट

4
@PiotrDobrogost जावास्क्रिप्ट (कई भाषाओं की तरह) मनमाने ढंग से बड़ी संख्या में संग्रहीत नहीं किया जा सकता है। Numberप्रकार एक है आईईईई 754 डबल चल बिन्दु मूल्य: आप अपूर्णांश के 53 बिट्स मिलता है, तो आप 2⁵³ (9007199254740992) पूर्णांक सटीकता के साथ तक जमा कर सकते हैं; इसके अलावा पूर्णांक अन्य मानों (इसलिए 9007199254740993 === 9007199254740992) पर आधारित होगा। 999999999999999999999 1000000000000000000000 के लिए गोल, जिसके लिए डिफ़ॉल्ट toStringप्रतिनिधित्व है 1e+21
bobince

22

वैकल्पिक रूप से आप डिक्शनरी को [(k1, v1), (k2, v2)] की सूची में परिवर्तित कर सकते हैं, जबकि इसे जौन का उपयोग करके एन्कोडिंग करते हैं, और इसे वापस डिकोड करने के बाद इसे डिक्शनरी में परिवर्तित करते हैं।


>>>> import json
>>>> json.dumps(releases.items())
    '[[1, "foo-v0.1"]]'
>>>> releases = {1: "foo-v0.1"}
>>>> releases == dict(json.loads(json.dumps(releases.items())))
     True
मेरा मानना ​​है कि इसे कुछ और काम करने की आवश्यकता होगी जैसे कि किसी तरह के झंडे को पहचानने के लिए कि इसे जोंस से वापस डिकोड करने के बाद सभी मापदंडों को डिक्शनरी में कैसे बदला जाए।


नेस्टेड तानाशाह वस्तुओं के बिना प्रमुख वस्तुओं के लिए अच्छा समाधान!
टॉम यू

15

अपने अधीन होने का उत्तर देना:

इसका उपयोग करके पूरा किया जा सकता है json.loads(jsonDict, object_hook=jsonKeys2int)

def jsonKeys2int(x):
    if isinstance(x, dict):
            return {int(k):v for k,v in x.items()}
    return x

यह फ़ंक्शन नेस्टेड डाइक्ट्स के लिए भी काम करेगा और एक तानाशाही समझ का उपयोग करेगा।

यदि आप मान भी डालना चाहते हैं, तो उपयोग करें:

def jsonKV2int(x):
    if isinstance(x, dict):
            return {int(k):(int(v) if isinstance(v, unicode) else v) for k,v in x.items()}
    return x

जो मूल्यों के उदाहरण का परीक्षण करता है और उन्हें केवल तभी कास्ट करता है यदि वे स्ट्रिंग ऑब्जेक्ट्स (यूनिकोड सटीक होने के लिए) हैं।

दोनों फ़ंक्शन पूर्णांक होने के लिए कुंजियाँ (और मान) मान लेते हैं।

करने के लिए धन्यवाद:

शब्दकोश में / और कैसे उपयोग करें?

एक शब्दकोश में int के लिए एक स्ट्रिंग कुंजी परिवर्तित करें


यह बहुत अच्छा था। मेरे मामले में अचार का उपयोग नहीं किया जा सकता है, इसलिए मैं JSON का उपयोग करके किसी ऑब्जेक्ट की हिम्मत को बाइट_अरे में रूपांतरण के माध्यम से सहेज रहा हूं ताकि मैं संपीड़न का उपयोग कर सकूं। मुझे मिश्रित कुंजियाँ मिली हैं, इसलिए मैंने आपके उदाहरण को एक ValueError की अनदेखी करने के लिए आपके उदाहरण को संशोधित किया जब कुंजी एक int
minillinim

11

मैं एक ही समस्या से काट लिया है। जैसा कि दूसरों ने बताया है, JSON में, मैपिंग कीज़ को स्ट्रिंग्स होना चाहिए। आप एक दो काम कर सकते हैं। आप डेमोसन की तरह कम सख्त JSON लाइब्रेरी का उपयोग कर सकते हैं , जो पूर्णांक तार की अनुमति देता है। यदि कोई अन्य कार्यक्रम (या अन्य भाषाओं में कोई अन्य) इसे पढ़ने नहीं जा रहा है, तो आपको ठीक होना चाहिए। या आप एक अलग क्रमांकन भाषा का उपयोग कर सकते हैं। मैं अचार का सुझाव नहीं दूंगा। यह पढ़ना मुश्किल है, और सुरक्षित होने के लिए डिज़ाइन नहीं किया गया है । इसके बजाय, मैं सुझाव देता हूं कि YAML, जो JSON का सुपरसेट है (लगभग) और पूर्णांक कुंजियों की अनुमति देता है। (कम से कम PyYAML करता है।)


2

डिक्शनरी को बदलकर स्ट्रिंग करें str(dict)और फिर इसे ऐसा करके वापस डिक्टेंड में बदल दें:

import ast
ast.literal_eval(string)

1

यहाँ मेरा समाधान है! मैंने उपयोग किया object_hook, यह तब उपयोगी है जब आपने नेस्ट किया होjson

>>> import json
>>> json_data = '{"1": "one", "2": {"-3": "minus three", "4": "four"}}'
>>> py_dict = json.loads(json_data, object_hook=lambda d: {int(k) if k.lstrip('-').isdigit() else k: v for k, v in d.items()})

>>> py_dict
{1: 'one', 2: {-3: 'minus three', 4: 'four'}}

इंट के लिए केवल पार्सिंग जोंस कुंजी के लिए फिल्टर है। आप int(v) if v.lstrip('-').isdigit() else vjson value के लिए भी फ़िल्टर का उपयोग कर सकते हैं ।


1

मैंने मुर्मल के उत्तर का एक बहुत ही सरल विस्तार किया, जो मुझे लगता है कि एक सुंदर मनमाने ढंग से शब्दकोश (नेस्टेड सहित) पर काम करेगा, यह मानते हुए कि इसे पहले स्थान पर JSON द्वारा डंप किया जा सकता है। पूर्णांक के रूप में व्याख्या की जा सकने वाली कोई भी कुंजी इंट में डाली जाएगी। इसमें कोई संदेह नहीं है कि यह बहुत कुशल नहीं है, लेकिन यह मेरे कार्य के उद्देश्य से काम करता है और जन्स स्ट्रिंग्स से लोड होता है।

def convert_keys_to_int(d: dict):
    new_dict = {}
    for k, v in d.items():
        try:
            new_key = int(k)
        except ValueError:
            new_key = k
        if type(v) == dict:
            v = _convert_keys_to_int(v)
        new_dict[new_key] = v
    return new_dict

यह मानते हुए कि मूल तानाशाही में सभी कुंजियाँ पूर्णांक हैं यदि उन्हें इंट में डाला जा सकता है, तो यह एक शब्दकोश के रूप में संग्रहीत करने के बाद मूल शब्दकोश वापस कर देगा। जैसे

>>>d = {1: 3, 2: 'a', 3: {1: 'a', 2: 10}, 4: {'a': 2, 'b': 10}}
>>>convert_keys_to_int(json.loads(json.dumps(d)))  == d
True

-1

आप अपने हिसाबjson.dumps से लिख सकते हैं , यहाँ djson से एक उदाहरण है : encoder.py । आप इसे इस तरह से उपयोग कर सकते हैं:

assert dumps({1: "abc"}) == '{1: "abc"}'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.