En Python, j'ai une classe de données qui contient plus d'une douzaine de membres. Je l'utilise pour créer un dict que je publie dans ElasticSearch .
Maintenant, je veux obtenir un dict à partir d'ElasticSearch et l'utiliser pour initialiser la classe de données. P >
Depuis:
J'ai pensé à ajouter une deuxième méthode init2 , qui retournera une instance de la classe de données et analysera le paramètre dict passé dans la méthode __ init __ générée automatiquement. p >
J'apprécierais votre contribution pour décider si ma solution suggérée ci-dessous est la bonne implémentation.
De plus, cette implémentation peut-elle être considérée comme un type d'usine?
Merci.
Suivi: puisque le dictionnaire JSON \ que j'obtiens de la requête ES est:
A exactement les mêmes mots-clés que la classe de données
Est plat, i.d., il n'y a pas d'objets imbriqués.
Je pourrais simplement passer les valeurs sous forme de ** dict dans la méthode __ init __ générée automatiquement.
Voir ma réponse ci-dessous pour ce cas spécifique:
from dataclasses import dataclass @dataclass class MyData: name: str age: int = 17 @classmethod def init_from_dict(cls, values_in_dict: dict): # Original line using MyData was fixed to use cls, following @ForceBru 's comment # return MyData(values_in_dict['name'], age=values_in_dict['age']) return cls(values_in_dict['name'], age=values_in_dict['age']) my_data_1: MyData = MyData('Alice') print(my_data_1) my_data_2: MyData = MyData('Bob', 15) print(my_data_2) values_in_dict_3: dict = { 'name': 'Carol', 'age': 20 } my_data_3: MyData = MyData.init_from_dict(values_in_dict_3) print(my_data_3) # Another init which uses the auto-generated __init__ works in this specific # case because the values' dict is flat and the keywords are the same as the # parameter names in the dataclass. # This allows me to do this my_data_4: MyData = MyData(**values_in_dict_3)
3 Réponses :
Il y a un bogue potentiel dans votre code. Considérez ceci:
class Thing: ... @classmethod def from_int(cls, value): return cls(value, value + 1) # Use `cls` instead of `Thing`
Maintenant, si vous exécutez AnotherOne.from_int (6)
, vous obtiendrez un objet Thing
: p >
>>> AnotherOne.from_int(6) <__main__.Thing object at 0x8f4a04c>
... alors que vous vouliez probablement créer un objet AnotherOne
!
Pour résoudre ce problème, créez l'objet comme ceci:
class Thing: def __init__(self, a, b): self.a, self.b = a, b @classmethod def from_int(cls, value): return Thing(value, value + 1) class AnotherOne(Thing): def __init__(self, a, b): self.a, self.b = a + 1, b + 2
Je pense que votre code est par ailleurs très bien: en effet, l'une des utilisations de classmethod
est de fournir d'autres moyens d'initialiser une instance d'une classe que d'utiliser __init__
.
De plus, cette implémentation peut-elle être considérée comme un type d'usine?
Oui, c'est un modèle courant pour ajouter des from_
classmethod
car python ne prend pas en charge la surcharge de méthode.
Comme je l'ai écrit dans la section de suivi de la question, la section _source de la réponse ElasticSearch a les mêmes mots-clés que les paramètres de la classe de données et est plate, ce qui signifie qu'il n'y a pas de dictionnaires imbriqués dans le JSON \ dict.
Cela me permet de mettre en œuvre ce qui suit.
La "_source" de ma réponse dans la recherche élastique ressemble à ceci
my_data = MyData(**response['_source'])
Je pourrais donc simplement faire:
response = { "_index": "env1", "_type": "_doc", "_id": "e3c85", "_score": 0.105360515, "_source": { "name": "RaamEEIL", "age": "19" } }