[python] Python의 json 모듈, int 사전 키를 문자열로 변환

다음이 실행될 때 파이썬의 json 모듈 (2.6 이후 포함)이 int 사전 키를 문자열로 변환한다는 것을 발견했습니다.

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

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

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



답변

이것은 당신을 물릴 수있는 다양한 매핑 컬렉션 간의 미묘한 차이점 중 하나입니다. JSON은 키를 문자열로 취급합니다. Python은 유형 만 다른 고유 키를 지원합니다.

파이썬에서 (그리고 분명히 Lua에서) 매핑에 대한 키 (각각 사전 또는 테이블)는 객체 참조입니다. Python에서는 변경 불가능한 유형이거나 __hash__메소드 를 구현하는 객체 여야합니다 . (Lua 문서는 변경 가능한 객체에 대해서도 객체의 ID를 해시 / 키로 자동으로 사용하고 동일한 문자열이 동일한 객체에 매핑되도록 문자열 인턴에 의존한다고 제안합니다.)

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

JSON은 Javascript 직렬화 기술로 시작되었습니다. (JSON은 약자 J 아바 S cript O bject N의 otation.) 물론 그것의 매핑 의미와 일치 그 매핑 표기 시맨틱을 구현한다.

직렬화의 양쪽 끝이 Python이 될 경우 피클을 사용하는 것이 좋습니다. 정말로 이것을 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'

자바 스크립트 객체는 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

이 함수는 중첩 된 딕셔너리에서도 작동하며 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

값의 인스턴스를 테스트하고 문자열 객체 인 경우에만 캐스트합니다 (정확히 유니 코드).

두 함수 모두 키 (및 값)를 정수라고 가정합니다.

덕분에 :

사전 이해에서 if / else를 사용하는 방법?

사전에서 문자열 키를 int로 변환


답변

나는 같은 문제에 물렸다. 다른 사람들이 지적했듯이 JSON에서 매핑 키는 문자열이어야합니다. 두 가지 중 하나를 수행 할 수 있습니다. 정수 문자열을 허용하는 demjson 과 같이 덜 엄격한 JSON 라이브러리를 사용할 수 있습니다 . 다른 프로그램 (또는 다른 언어로 된 다른 프로그램)이 읽을 수 없다면 괜찮습니다. 또는 다른 직렬화 언어를 사용할 수 있습니다. 피클은 권하지 않습니다. 읽기 어렵고 안전하도록 설계되지 않았습니다 . 대신, (거의) JSON의 상위 집합이며 정수 키를 허용하는 YAML을 제안합니다. (적어도 PyYAML그렇습니다 .)


답변

을 사용하여 사전을 문자열 str(dict)로 변환 한 다음 다음을 수행하여 다시 dict로 변환합니다.

import ast
ast.literal_eval(string)


답변

여기 내 해결책이 있습니다! 을 사용 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'}}

json 키를 int로 구문 분석하는 필터 만 있습니다. int(v) if v.lstrip('-').isdigit() else vjson 값에도 필터를 사용할 수 있습니다 .