Estou tentando criar uma representação de string JSON de uma instância de classe e tendo dificuldades. Digamos que a classe seja construída assim:
class testclass:
value1 = "a"
value2 = "b"
Uma chamada para o json.dumps é feita assim:
t = testclass()
json.dumps(t)
Está falhando e me dizendo que a classe de teste não é JSON serializável.
TypeError: <__main__.testclass object at 0x000000000227A400> is not JSON serializable
Eu também tentei usar o módulo pickle:
t = testclass()
print(pickle.dumps(t, pickle.HIGHEST_PROTOCOL))
E fornece informações da instância da classe, mas não um conteúdo serializado da instância da classe.
b'\x80\x03c__main__\ntestclass\nq\x00)\x81q\x01}q\x02b.'
O que estou fazendo de errado?
python
json
serialization
pickle
Ferhan
fonte
fonte
s = json.dumps(obj, default=lambda x: x.__dict__)
para as variáveis de instância serialize do objeto (self.value1
,self.value2
...). É a maneira mais simples e direta. Serializará estruturas de objetos aninhados. Adefault
função é chamada quando um determinado objeto não é diretamente serializável. Você também pode olhar para a minha resposta abaixo. Achei as respostas populares desnecessariamente complexas, que provavelmente eram verdadeiras há muito tempo.testclass
não possui__init__()
método, todas as instâncias compartilharão os mesmos dois atributos de classe (value1
evalue2
) definidos na instrução de classe. Você entende a diferença entre uma classe e uma instância de uma?Respostas:
O problema básico é que o codificador JSON
json.dumps()
sabe apenas como serializar um conjunto limitado de tipos de objetos por padrão, todos os tipos internos. Listar aqui: https://docs.python.org/3.3/library/json.html#encoders-and-decodersUma boa solução seria fazer sua classe herdar
JSONEncoder
e, em seguida, implementar aJSONEncoder.default()
função, e fazer com que essa função emita o JSON correto para sua classe.Uma solução simples seria chamar
json.dumps()
o.__dict__
membro dessa instância. Esse é um Python padrãodict
e, se sua classe for simples, será JSON serializável.A abordagem acima é discutida nesta postagem do blog:
Serializando objetos Python arbitrários para JSON usando __dict__
fonte
.__init__()
função de método, portanto, sua instância de classe possui um dicionário vazio. Em outras palavras,{}
é o resultado correto para o seu código de exemplo.is not JSON serializable
Há uma maneira que funciona muito bem para mim que você pode experimentar:
json.dumps()
pode usar um parâmetro opcional padrão, onde você pode especificar uma função serializadora personalizada para tipos desconhecidos, que no meu caso se parece comOs dois primeiros ifs são para serialização de data e hora e, em seguida, é
obj.__dict__
retornado para qualquer outro objeto.a chamada final se parece com:
É especialmente bom quando você está serializando uma coleção e não deseja chamar
__dict__
explicitamente para cada objeto. Aqui é feito automaticamente para você.Até agora funcionou tão bem para mim, ansioso por seus pensamentos.
fonte
NameError: name 'serialize' is not defined
. Alguma dica?try: dict = obj.__dict__ except AttributeError: dict = {s: getattr(obj, s) for s in obj.__slots__ if hasattr(obj, s)} return dict
Você pode especificar o
default
parâmetro nomeado najson.dumps()
função:Explicação:
Forme os documentos ( 2.7 , 3.6 ):
(Funciona em Python 2.7 e Python 3.x)
Nota: Nesse caso, você precisa de
instance
variáveis e não declass
variáveis, como o exemplo da pergunta tenta fazer. (Estou supondo que o autor da perguntaclass instance
seja um objeto de uma classe)Eu aprendi isso primeiro com a resposta de @ phihag aqui . Considerou a maneira mais simples e limpa de fazer o trabalho.
fonte
default=lambda x: getattr(x, '__dict__', str(x))
datetime.date
é uma implementação C, portanto, não possui nenhum__dict__
atributo. IMHO em nome da uniformidade,datetime.date
deve ser tê-lo ...Eu só faço:
Esta não é a resposta completa e, se você tiver algum tipo de classe de objeto complicada, certamente não receberá tudo. No entanto, eu uso isso para alguns dos meus objetos simples.
Uma que funciona muito bem é a classe "options" que você obtém do módulo OptionParser. Aqui está junto com a própria solicitação JSON.
fonte
Usando jsonpickle
fonte
JSON não é realmente destinado a serializar objetos Python arbitrários. É ótimo para serializar
dict
objetos, mas opickle
módulo é realmente o que você deve usar em geral. A saída depickle
não é realmente legível por humanos, mas deve ser bem feita. Se você insistir em usar JSON, poderá verificar ojsonpickle
módulo, que é uma abordagem híbrida interessante.https://github.com/jsonpickle/jsonpickle
fonte
Aqui estão duas funções simples para serialização de qualquer classe não sofisticada, nada sofisticado, como explicado anteriormente.
Eu uso isso para coisas do tipo de configuração porque posso adicionar novos membros às classes sem nenhum ajuste de código.
fonte
Existem algumas boas respostas sobre como começar a fazer isso. Mas há algumas coisas a serem lembradas:
__slots__
vez de__dict__
?O json-tricks é uma biblioteca (que eu criei e outros contribuímos) que foi capaz de fazer isso por um bom tempo. Por exemplo:
Você recuperará sua instância. Aqui o json fica assim:
Se você gosta de criar sua própria solução, pode procurar na fonte
json-tricks
para não esquecer alguns casos especiais (como__slots__
).Ele também faz outros tipos, como matrizes numpy, datetime, números complexos; também permite comentários.
fonte
Python3.x
A melhor abordagem que pude alcançar com meu conhecimento foi essa.
Observe que esse código também trata set ().
Essa abordagem é genérica, apenas necessitando da extensão da classe (no segundo exemplo).
Observe que estou fazendo isso apenas com arquivos, mas é fácil modificar o comportamento ao seu gosto.
No entanto, este é um CoDec.
Com um pouco mais de trabalho, você pode construir sua classe de outras maneiras. Eu assumo um construtor padrão para instância, então eu atualizo o dict de classe.
Editar
Com um pouco mais de pesquisa, encontrei uma maneira de generalizar sem a necessidade da chamada do método de registro SUPERCLASS , usando uma metaclasse
fonte
Acredito que, em vez de herança, como sugerido na resposta aceita, é melhor usar o polimorfismo. Caso contrário, você precisará ter uma grande declaração if else para personalizar a codificação de cada objeto. Isso significa criar um codificador padrão genérico para JSON como:
e, em seguida, tenha uma
jsonEnc()
função em cada classe que você deseja serializar. por exemploEntão você liga
json.dumps(classInstance,default=jsonDefEncoder)
fonte