Programming

파이썬의 json 모듈, int 사전 키를 문자열로 변환

procodes 2020. 7. 27. 21:38
반응형

파이썬의 json 모듈, int 사전 키를 문자열로 변환


다음을 실행하면 파이썬의 json 모듈 (2.6 이후 포함)이 int 사전 키를 문자열로 변환합니다.

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

덤프 및로드시 문자열을 구문 분석 할 필요없이 키를 int로 유지하는 쉬운 방법이 있습니까? json 모듈이 제공하는 후크를 사용하는 것이 가능할 것이라고 생각하지만 여전히 구문 분석이 필요합니다. 내가 간과 한 주장이 있을까? 건배

하위 질문 : 답변 주셔서 감사합니다. 내가 두려워하는 것처럼 json이 작동하는 것을 볼 때 덤프 출력을 구문 분석하여 키 유형을 전달하는 쉬운 방법이 있습니까? 또한 덤프를 수행하는 코드와 서버에서 json 객체를 다운로드하고로드하는 코드가 모두 작성되었습니다.


이것은 당신을 물릴 수있는 다양한 매핑 컬렉션 간의 미묘한 차이점 중 하나입니다.

파이썬에서 (그리고 분명히 루아에서) 매핑에 대한 키 (각각 사전 또는 테이블)는 객체 참조입니다. 파이썬에서 그것들은 불변의 타입이거나 __hash__메소드 를 구현하는 객체 여야합니다 . Lua 문서는 가변 객체의 경우에도 객체의 ID를 해시 / 키로 자동 사용하고 동등한 문자열이 동일한 객체에 매핑되도록 문자열 인터 닝에 의존 할 것을 제안합니다.

Perl, Javascript, awk 및 기타 여러 언어에서 해시, 연관 배열 또는 주어진 언어에 대해 호출되는 키는 문자열 (또는 Perl의 "스칼라")입니다. $foo{1}, $foo{1.0}, and $foo{"1"}에서 같은 매핑에 대한 모든 참조는 %foo--- 키는 스칼라로 평가 됩니다!

JSON은 자바 스크립트 직렬화 기술로 시작되었습니다. (JSON은 [J] ava [S] cript [o] bject [n] otation]의 약자입니다.) 당연히 맵핑 시맨틱과 일치하는 맵핑 표기법의 시맨틱을 구현합니다.

직렬화의 양쪽 끝이 파이썬이 될 경우 피클을 사용하는 것이 좋습니다. JSON에서 원시 Python 객체로 다시 변환 해야하는 경우 몇 가지 선택이 필요합니다. 먼저 try: ... except: ...사전 조회 실패시 ( )를 사용하여 키를 숫자로 변환 할 수 있습니다. 또는 다른 쪽 끝 (이 JSON 데이터의 직렬화 기 또는 생성기)에 코드를 추가하면 각 키 값에 대해 JSON 직렬화를 수행하여 키 목록으로 제공 할 수 있습니다. 그런 다음 Python 코드는 먼저 키 목록을 반복하여 키를 네이티브 Python 객체로 인스턴스화 / 역 직렬화 한 다음 매핑을 통해 값에 액세스하는 데 사용합니다.


아니요, JavaScript에는 숫자 키와 같은 것이 없습니다. 모든 객체 속성이 문자열로 변환됩니다.

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'

JavaScript 객체는 Python과 같은 언어로 이해하고 문자열이 아닌 키를 사용하면 이상한 결과를 낳을 수 있으므로 실제로 적절한 매핑이 아닙니다. 그렇기 때문에 JSON은 필요하지 않은 경우에도 항상 키를 문자열로 명시 적으로 작성합니다.


또는 json을 사용하여 인코딩하는 동안 사전을 [(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
json에서 다시 디코딩 한 후 사전으로 변환 할 모든 매개 변수를 식별하는 일종의 플래그를 갖는 것과 같은 더 많은 작업이 필요하다고 생각합니다.


하위 질문에 대답하기 :

사용하여 달성 할 수 있습니다 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

이 함수는 중첩 된 dicts에도 적용되며 dict comprehension을 사용합니다.

값도 캐스트하려면 다음을 사용하십시오.

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

Which tests the instance of the values and casts them only if they are strings objects (unicode to be exact).

Both functions assumes keys (and values) to be integers.

Thanks to:

How to use if/else in a dictionary comprehension?

Convert a string key to int in a Dictionary


I've gotten bitten by the same problem. As others have pointed out, in JSON, the mapping keys must be strings. You can do one of two things. You can use a less strict JSON library, like demjson, which allows integer strings. If no other programs (or no other in other languages) are going to read it, then you should be okay. Or you can use a different serialization language. I wouldn't suggest pickle. It's hard to read, and is not designed to be secure. Instead, I'd suggest YAML, which is (nearly) a superset of JSON, and does allow integer keys. (At least PyYAML does.)


Convert the dictionary to be string by using str(dict) and then convert it back to dict by doing this:

import ast
ast.literal_eval(string)

Here is my solution! I used object_hook, it is useful when you have nested 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'}}

There is filter only for parsing json key to int. You can use int(v) if v.lstrip('-').isdigit() else v filter for json value too.


You can write your json.dumps by yourself, here is a example from djson: encoder.py. You can use it like this:

assert dumps({1: "abc"}) == '{1: "abc"}'

참고URL : https://stackoverflow.com/questions/1450957/pythons-json-module-converts-int-dictionary-keys-to-strings

반응형