Eu descobri que, quando o seguinte é executado, o módulo json do python (incluído desde o 2.6) converte as chaves do dicionário int em strings.
>>> import json
>>> releases = {1: "foo-v0.1"}
>>> json.dumps(releases)
'{"1": "foo-v0.1"}'
Existe alguma maneira fácil de preservar a chave como int, sem a necessidade de analisar a string no dump e no load. Acredito que seria possível usar os ganchos fornecidos pelo módulo json, mas novamente isso ainda requer análise. Existe algum argumento que eu tenha esquecido? Saúde, chaz
Sub-pergunta: Obrigado pelas respostas. Vendo como json funciona como eu temia, existe uma maneira fácil de transmitir o tipo de chave, talvez analisando a saída de despejos? Também devo observar que o código que faz o dumping e o código que baixa o objeto json de um servidor e o carrega são ambos escritos por mim.
Respostas:
Essa é uma daquelas diferenças sutis entre várias coleções de mapeamento que podem morder você. JSON trata as chaves como strings; O Python suporta chaves distintas, diferindo apenas no tipo.
No Python (e aparentemente em Lua), as chaves para um mapeamento (dicionário ou tabela, respectivamente) são referências a objetos. No Python, eles devem ser tipos imutáveis ou objetos que implementam um
__hash__
método. (Os documentos de Lua sugerem que ele use automaticamente o ID do objeto como um hash / chave, mesmo para objetos mutáveis e confie na internação de cadeias para garantir que cadeias equivalentes sejam mapeadas para os mesmos objetos).No Perl, Javascript, awk e muitas outras linguagens, as chaves para hashes, matrizes associativas ou o que quer que sejam chamadas para o idioma especificado, são strings (ou "escalares" no Perl). Em perl
$foo{1}, $foo{1.0}, and $foo{"1"}
estão todas as referências ao mesmo mapeamento em%foo
--- a chave é avaliada como um escalar!JSON começou como uma tecnologia de serialização Javascript. (JSON meios J ava S cript O bject N otation.) Naturalmente que implementa semântica para a sua notação de mapeamento que são consistentes com a sua semântica de mapeamento.
Se as duas extremidades da sua serialização forem Python, é melhor usar pickles. Se você realmente precisar convertê-los novamente do JSON em objetos Python nativos, acho que você tem algumas opções. Primeiro, você pode tentar (
try: ... except: ...
) converter qualquer chave em um número no caso de uma falha na pesquisa do dicionário. Como alternativa, se você adicionar código à outra extremidade (o serializador ou gerador desses dados JSON), poderá executar uma serialização JSON em cada um dos valores de chave - fornecendo-os como uma lista de chaves. (Em seguida, seu código Python primeiro itera sobre a lista de chaves, instanciando / desserializando-as em objetos Python nativos ... e depois os utiliza para acessar os valores do mapeamento).fonte
Não, não existe uma chave numérica no JavaScript. Todas as propriedades do objeto são convertidas em String.
Isso pode levar a alguns comportamentos curiosos:
Objetos JavaScript não são mapeamentos realmente adequados, como você entenderia em linguagens como Python, e o uso de chaves que não são String resulta em estranheza. É por isso que o JSON sempre escreve explicitamente chaves como seqüências de caracteres, mesmo quando não parece necessário.
fonte
999999999999999999999
convertido para'999999999999999999999'
?Number
tipo é um valor de ponto flutuante duplo IEEE 754 : você obtém 53 bits de mantissa, para que você possa armazenar até 2⁵³ (9007199254740992) com precisão inteira; além disso, os números inteiros serão arredondados para outros valores (portanto, 9007199254740993 === 9007199254740992). 999999999999999999999 arredonda para 10000000000000000000000000, para o qual atoString
representação padrão é1e+21
.Como alternativa, você também pode tentar converter o dicionário para uma lista do formato [(k1, v1), (k2, v2)] enquanto codifica usando json e convertê-lo novamente no dicionário após decodificá-lo novamente.
Acredito que isso precisará de mais trabalho, como ter algum tipo de sinalizador para identificar quais parâmetros serão convertidos em dicionário depois de decodificá-lo novamente do json.fonte
Respondendo à sua subquestão:
Isso pode ser realizado usando
json.loads(jsonDict, object_hook=jsonKeys2int)
Essa função também funcionará para dicts aninhados e usa uma compreensão de dict.
Se você também deseja converter os valores, use:
Que testa a instância dos valores e os lança apenas se forem objetos de strings (unicode para ser exato).
Ambas as funções assumem chaves (e valores) como inteiros.
Graças a:
Como usar if / else em uma compreensão de dicionário?
Converter uma chave de string em int em um dicionário
fonte
Fui mordido pelo mesmo problema. Como outros já apontaram, no JSON, as chaves de mapeamento devem ser cadeias de caracteres. Você pode fazer uma das duas coisas. Você pode usar uma biblioteca JSON menos estrita, como demjson , que permite cadeias inteiras. Se nenhum outro programa (ou nenhum outro idioma) vai lê-lo, você deve ficar bem. Ou você pode usar uma linguagem de serialização diferente. Eu não sugeriria picles. É difícil de ler e não foi projetado para ser seguro . Em vez disso, sugiro o YAML, que é (quase) um superconjunto de JSON e permite chaves inteiras. (Pelo menos PyYAML faz.)
fonte
Converta o dicionário em string usando
str(dict)
e, em seguida, converta-o novamente em dict, fazendo o seguinte:fonte
Aqui está a minha solução! Eu usei
object_hook
, é útil quando você aninhajson
Há filtro apenas para analisar a chave json em int. Você também pode usar o
int(v) if v.lstrip('-').isdigit() else v
filtro para o valor json.fonte
Fiz uma extensão muito simples da resposta de Murmel, que acho que funcionará em um dicionário bastante arbitrário (incluindo aninhado), supondo que ele possa ser descartado pelo JSON em primeiro lugar. Quaisquer chaves que possam ser interpretadas como números inteiros serão convertidas para int. Sem dúvida, isso não é muito eficiente, mas funciona para meus propósitos de armazenar e carregar a partir de strings json.
Supondo que todas as chaves no ditado original sejam números inteiros se puderem ser convertidas para int, isso retornará o dicionário original depois de armazenado como um json. por exemplo
fonte
Você pode escrever o seu
json.dumps
sozinho, aqui está um exemplo de djson : encoder.py . Você pode usá-lo assim:fonte