Подтвердить что ты не робот

Флажок jsonify список объектов

У меня есть список объектов, которые мне нужно jsonify. Я посмотрел на флеш файлы jsonify, но я просто не понимаю.

Мой класс имеет несколько inst-vars, каждая из которых является строкой: gene_id, gene_symbol, p_value. Что мне нужно сделать, чтобы сделать сериализуемым как JSON?

Мой наивный код:

jsonify(eqtls = my_list_of_eqtls)

Результаты в:

TypeError: <__main__.EqtlByGene object at 0x1073ff790> is not JSON serializable

Предположительно, я должен сказать jsonify, как сериализовать EqtlByGene, но я не могу найти пример, который показывает, как сериализовать экземпляр класса.

Этот код теперь работает (с большим благодарением Martijn Pieters!):

class EqtlByGene(Resource):

    def __init__(self, gene_id, gene_symbol, p_value):
        self.gene_id = gene_id
        self.gene_symbol = gene_symbol
        self.p_value = p_value

class EqtlJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, EqtlByGene):
            return {
                   'gene_id'     : obj.gene_id,
                   'gene_symbol' : obj.gene_symbol,
                   'p_value'     : obj.p_value
            }
        return super(EqtlJSONEncoder, self).default(obj)

class EqtlByGeneList(Resource):
    def get(self):
        eqtl1 = EqtlByGene(1, 'EGFR', 0.1)
        eqtl2 = EqtlByGene(2, 'PTEN', 0.2)
        eqtls = [eqtl1, eqtl2]
        return jsonify(eqtls_by_gene = eqtls)

api.add_resource(EqtlByGeneList, '/eqtl/eqtlsbygene')
app.json_encoder = EqtlJSONEncoder
if __name__ == '__main__':
    app.run(debug=True)

Когда я вызываю его через curl, я получаю:

{
  "eqtls_by_gene": [
    {
      "gene_id": 1, 
      "gene_symbol": "EGFR", 
      "p_value": 0.1
    }, 
    {
      "gene_id": 2, 
      "gene_symbol": "PTEN", 
      "p_value": 0.2
    }
  ]
}
4b9b3361

Ответ 1

Дайте вашему EqltByGene дополнительный метод, который возвращает словарь:

class EqltByGene(object):
    #

    def serialize(self):
        return {
            'gene_id': self.gene_id, 
            'gene_symbol': self.gene_symbol,
            'p_value': self.p_value,
        }

затем используйте представление списка, чтобы превратить ваш список объектов в список сериализуемых значений:

jsonify(eqtls=[e.serialize() for e in my_list_of_eqtls])

Альтернативой было бы написать функцию hook для функции json.dumps(), но поскольку ваша структура довольно проста, понимание списка и метод пользовательских методов проще.

Вы также можете быть действительно авантюрным и подклассом flask.json.JSONEncoder; дайте ему метод default(), который превратит ваши экземпляры EqltByGene() в сериализуемое значение:

from flask.json import JSONEncoder

class MyJSONEncoder(JSONEncoder):
    def default(self, obj):
        if isinstance(obj, EqltByGene):
            return {
                'gene_id': obj.gene_id, 
                'gene_symbol': obj.gene_symbol,
                'p_value': obj.p_value,
            }
        return super(MyJSONEncoder, self).default(obj)

и назначьте это атрибуту app.json_encoder:

app = Flask(__name__)
app.json_encoder = MyJSONEncoder

и просто перейдите в свой список непосредственно к jsonify():

return jsonify(my_list_of_eqtls)

Ответ 2

Если вы посмотрите документы для модуля json, в нем упоминается, что вы можете подкласс JSONEncoder, чтобы переопределить его метод default и добавить поддержку типов там. Это был бы самый общий способ справиться с этим, если вы собираетесь сериализовать несколько разных структур, которые могут содержать ваши объекты.

Если вы хотите использовать jsonify, возможно, вам проще просто преобразовать объекты в простые типы заблаговременно (например, определив свой собственный метод в классе, как предполагает Мартийн).