programing

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

javajsp 2023. 3. 5. 09:30

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

아래가 실행되면 python의 json 모듈(2.6부터 포함)이 int 사전키를 문자열로 변환한다는 것을 알게 되었습니다.

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

덤프 및 로드 시 문자열을 해석할 필요 없이 키를 int로 유지할 수 있는 쉬운 방법이 있습니까?json 모듈이 제공하는 훅을 사용하면 가능할 것이라고 생각합니다만, 이것도 해석은 필요합니다.제가 간과한 논쟁이 있을까요?

서브 질문:답변 감사합니다.json이 생각대로 동작하는 것을 보고 덤프의 출력을 해석하여 키 타입을 쉽게 전달할 수 있는 방법이 있습니까?또한 덤프를 하는 코드와 서버에서 json 오브젝트를 다운로드하여 로드하는 코드는 모두 제가 작성한 것입니다.

이것은 다양한 지도 컬렉션의 미묘한 차이 중 하나입니다.JSON은 키를 문자열로 취급합니다.Python은 유형이 다른 개별 키를 지원합니다.

Python(그리고 Lua에서는 명백하게)에서 매핑 키(각각 사전 또는 테이블)는 객체 참조입니다.이거나 Python을 .__hash__method.(Lua 문서에서는 변경 가능한 객체에 대해서도 객체의 ID를 해시/키로서 자동적으로 사용하고, 같은 객체에 대응하는 문자열이 매핑되도록 문자열 인터닝에 의존하는 것을 나타내고 있습니다.

Perl, Javascript, awk 및 기타 많은 언어에서 해시, 연관 배열 또는 해당 언어에 대해 호출되는 키는 문자열(Perl에서는 "스칼라")입니다. perl 。$foo{1}, $foo{1.0}, and $foo{"1"}는 모두 같은 입니다.%foo--- 키는 스칼라로 평가됩니다!

JSON은 Javascript serialization technology로 시작되었습니다.(JSON은 JavaScript 객체 표기법의 약자입니다).당연히 매핑 시멘틱스와 일치하는 매핑 표기법을 위한 시멘틱스를 구현합니다.

만약 당신의 연재물의 양끝이 Python이라면, 당신은 피클을 사용하는 것이 더 나을 것입니다.JSON에서 네이티브 Python 객체로 변환해야 할 경우 몇 가지 선택지가 있을 것입니다. ( ( 저 (세 first first 、 [ 。try: ... except: ...사전 검색 실패 시 임의의 키를 숫자로 변환합니다.JSON은 JSON을 사용하여 JSON을 사용합니다.(그 후 Python 코드는 먼저 키 목록을 반복하여 기본 Python 개체로 인스턴스화/비직렬화하고 매핑에서 값에 액세스하기 위해 사용합니다.)

아니요, JavaScript에는 Number 키와 같은 것은 없습니다.모든 객체 속성이 String으로 변환됩니다.

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 Objects는 Python과 같은 언어에서 이해할 수 있는 적절한 매핑이 아닙니다.String이 아닌 키를 사용하면 이상해집니다.그렇기 때문에 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

이 함수는 중첩된 딕트에도 작동하며 딕트 억양을 사용합니다.

값을 캐스팅하려면 다음 명령을 사용합니다.

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로 변환

또는 사전을 [(k1,v1),(k2,v2)] 형식 목록으로 변환하고 json을 사용하여 인코딩한 후 다시 사전으로 변환할 수도 있습니다.


>>>> import json
>>>> json.dumps(releases.items())
    '[[1, "foo-v0.1"]]'
>>>> releases = {1: "foo-v0.1"}
>>>> releases == dict(json.loads(json.dumps(releases.items())))
     True
I believe this will need some more work like having some sort of flag to identify what all parameters to be converted to dictionary after decoding it back from json.

나도 같은 문제에 물렸다.다른 사람들이 지적했듯이 JSON에서는 매핑 키가 문자열이어야 합니다.당신은 두 가지 중 하나를 할 수 있습니다.정수 문자열을 허용하는 demjson과 같이 덜 엄격한 JSON 라이브러리를 사용할 수 있습니다.다른 프로그램(또는 다른 언어)이 읽을 수 없는 경우라면 문제 없습니다.또는 다른 시리얼화 언어를 사용할 수도 있습니다.피클은 추천하지 않겠습니다.읽기 어렵고 안전하도록 설계되어 있지 않습니다.대신 YAML을 추천합니다.YAML은 (거의) JSON의 슈퍼셋으로 정수 키를 사용할 수 있습니다.(적어도 PyYAML은 그렇습니다.)

여기 내 해결책이 있다!나는 사용했다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 값도 필터링합니다.

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

import ast
ast.literal_eval(string)

저는 Murmel의 답변을 매우 간단하게 확장했습니다.이것은 JSON에 의해 애초에 덤프될 수 있다고 가정한 꽤 임의의 사전(네스트 포함)에서 유효하다고 생각합니다.정수로 해석할 수 있는 키는 모두 int에 캐스트됩니다.물론 효율은 낮지만, json string에 저장 및 로딩하는 제 목적에는 효과가 있습니다.

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

원본 dict의 모든 키가 정수라고 가정할 때 int로 캐스트할 수 있으면 json으로 저장한 후 원본 사전을 반환합니다.

>>>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

[NSFW] 이 글을 쓰면json.dumps여기 djson의 예가 있습니다.encoder.py다음과 같이 사용할 수 있습니다.

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

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