Je pense qu'il existe de nombreuses situations dans lesquelles JSON est analysé lors de la liaison d'API avec des services externes en Python. Perth est ennuyeux et vous ne voulez pas passer trop de temps dans des situations comme Hackerson où la vitesse est particulièrement nécessaire. Cette fois, je vais vous montrer comment convertir facilement JSON en classe de données Python.
Le code introduit dans cet article est disponible sur GitHub. https://github.com/gaiax/quicktype-dacite-demo
Comme le titre l'indique, nous utilisons principalement les bibliothèques appelées quicktype et dacite.
quicktype Une bibliothèque qui déduit le type d'exemples de données tels que JSON et les génère dans la langue correspondante. https://github.com/quicktype/quicktype
Bien que publié sous forme de package npm, il peut également être facilement utilisé comme interface utilisateur Web. Même s'il s'agit d'une interface utilisateur Web, le processus est terminé sur le client sans passer par le serveur. [^ 1] Il est disponible sur https://app.quicktype.io/.
dacite Une bibliothèque qui convertit les dictées Python en classe de données. https://github.com/konradhalas/dacite
Normalement, cela devrait être le cas lors de la conversion de dict en dataclass.
from dataclasses import dataclass
@dataclass
class Data:
hoge: int
fuga: str
d = {"hoge": 10, "fuga": "Python"}
Data(**d)
# Data(hoge=10, fuga='Python')
Cela fonctionne bien, mais cela ne fonctionne pas bien avec les dictionnaires imbriqués.
from dataclasses import dataclass
@dataclass
class NestedData:
foo: int
bar: str
@dataclass
class Data:
hoge: int
fuga: str
nested_data: NestedData
d = {
"hoge": 10,
"fuga": "Python",
"nested_data": {
"foo": 20,
"bar": "Ruby"
}
}
Data(**d)
# Data(hoge=10, fuga='Python', nested_data={'foo': 20, 'bar': 'Ruby'})
# nested_data n'est pas la classe NestedData, elle stocke juste le dictionnaire
dacite permet de telles conversions de dictionnaire imbriquées normalement non prises en charge.
from dataclasses import dataclass
from dacite import from_dict
@dataclass
class NestedData:
foo: int
bar: str
@dataclass
class Data:
hoge: int
fuga: str
nested_data: NestedData
d = {
"hoge": 10,
"fuga": "Python",
"nested_data": {
"foo": 20,
"bar": "Ruby"
}
}
from_dict(data_class=Data, data=d)
# Data(hoge=10, fuga='Python', nested_data=NestedData(foo=20, bar='Ruby'))
# nested_data contient une instance de la classe NestedData!
Cela rend très facile la conversion de dictionnaires et de classes de données. De plus, au moment de la rédaction de l'article (2020/06/10), il existe les fonctions suivantes.
Au fait, la conversion de dataclass en dictionnaire est possible en passant une instance de dataclass à dataclasses.asdict
dans la bibliothèque standard Python.
Comme certains d'entre vous ont déjà fourni une image d'implémentation à partir de l'explication jusqu'à présent, essayons en fait de convertir JSON et la classe de données à partir de la définition de la classe de données. Ici, à titre d'exemple, convertissons la valeur de retour de l'API d'événements de connpass en dataclass.
Nous sommes un groupe appelé «Gaiax Technical Meetups» de connpass, qui organise des rencontres d'introduction et d'échange pour les ingénieurs. ~~ Publicité soudaine ~~ Cette fois, l'API se concentrera sur ce groupe et préparera les données.
Pour faciliter la lecture de l'article, nous limiterons le nombre d'événements à deux.
GET https://connpass.com/api/v1/event/?series_id=3109&count=2
connpass.json
{
"results_start": 1,
"results_returned": 2,
"results_available": 35,
"events": [
{
"event_id": 175102,
"title": "[Dialogue en ligne] Présentation de l'utilisation du script Google Apps#6",
"catch": "Dialogue en ligne avec les dernières informations et cas d'utilisation de Google Apps Script",
"description": "<h1>Campagne de réalisation du montant cible de financement du livre GAS!</h1>\n<p>M. Takahashi de Plan Notes, l'auteur de "Présentation complète de Google Apps Script" qui a réussi à financer "Je souhaite diffuser la dernière" Présentation complète de Google Apps Script "dans le monde dès que possible!" Sera sur scène.<br>\n<a href=\"https://camp-fire.jp/projects/view/249472\" rel=\"nofollow\">https://camp-fire.jp/projects/view/249472</a></p>\n<p>Pour fêter l'atteinte du montant cible, nous présenterons la première édition de "Google Apps Script Complete Introduction" à 5 personnes par tirage au sort des participants à l'événement dans le cadre d'une campagne limitée à cet événement! !! !!</p>\n<h1>détail</h1>\n<p>La 6ème édition de "Google Apps Script Utilization Meetup", qui est devenu un élément populaire et standard dans Technical Meetup, se tiendra tout en changeant le format!</p>\n<p>G Suite de Google (Google Apps) commence à être utilisé par de nombreuses entreprises. Découvrez les dernières informations et exemples d'application de Google Apps Script, un langage de script qui étend G Suite!</p>\n<p>Les entreprises informatiques migrent d'un logiciel de bureau installé directement sur leur PC vers G Suite, un logiciel de bureau de type application Web. Plusieurs personnes peuvent modifier en même temps, les fichiers sont automatiquement enregistrés dans le cloud et de nombreuses fonctions prennent en charge le style de travail requis aujourd'hui.</p>\n<p>Google Apps Script étend les fonctionnalités de G Suite. Comme il est basé sur le langage JavaScript, qui est familier à de nombreuses personnes, son histoire est courte, mais ses cas d'utilisation augmentent rapidement.</p>\n<p>※référence</p>\n<p>Veuillez consulter l'URL suivante pour les événements passés!</p>\n<p><a href=\"http://gaiax.hatenablog.com/archive\" rel=\"nofollow\">http://gaiax.hatenablog.com/archive</a></p>\n<h1>calendrier</h1>\n<ul>\n<li>19:15 Début de livraison</li>\n<li>19:30 début de conversation</li>\n<li>20:30 questions et réponses</li>\n<li>20:50 Questionnaire</li>\n<li>21:00 fermer</li>\n</ul>\n<h1>Entretien programmé</h1>\n<h3>M. Nobunari Takahashi, directeur représentant de Plan Notes Co., Ltd.</h3>\n<p>Diplômé de la division de recherche en informatique électronique de l'Université des télécommunications, il a travaillé comme saxophoniste jusqu'à l'âge de 30 ans et a connu une expérience de producteur et de marketing dans l'industrie du contenu mobile et l'industrie du livre électronique. J'ai ressenti un problème avec le style de travail, la productivité, l'utilisation informatique, etc. des hommes d'affaires au Japon et j'ai démarré une entreprise indépendante en 2015. Exceller,VBA,GSuite,GAS,Travail sur le développement d'outils système, le conseil, la formation, la rédaction, etc. en utilisant le cloud.\n Formateur du service d'apprentissage en ligne "Linked In Learning",Présidé la communauté "Skill Up Study Group for Non-Programmers".\n Un blog géré par moi-même<a href=\"https://tonari-it.com/\" rel=\"nofollow\">"Toujours un travail informatique à côté"</a>Bénéficie d'une popularité mensuelle de 960 000 PV.</p>\n<h3>Gaiax Co., Ltd. Division des solutions de médias sociaux Shogo Matsushita</h3>\n<p>Né en 1995 Né dans la préfecture de Kanagawa. RPG Tsukuru et Click au collège&Rencontrez Create et franchissez la porte de la programmation grâce à la programmation de jeux. Après cela, inscrivez-vous à Yokohama Medical Information College. Engagé dans le développement de services Web en tant que stagiaire à divers endroits tout en fréquentant l'école. A rejoint Gaiax en 2018. Actuellement, en plus du développement et de la production vidéo, il écrit des productions vidéo techniques doujinshi et doujin au sein de la division Social Media Marketing.</p>\n<p>Récemment publié un doujinshi sur AppMaker</p>\n<ul>\n<li>Booth <a href=\"https://godan.booth.pm/items/2035726\" rel=\"nofollow\">https://godan.booth.pm/items/2035726</a></li>\n<li>bookwalker <a href=\"https://bookwalker.jp/de809d7a5b-1b32-4973-a3d6-61019cf222f2/\" rel=\"nofollow\">https://bookwalker.jp/de809d7a5b-1b32-4973-a3d6-61019cf222f2/</a></li>\n</ul>\n<h1>Remarques</h1>\n<p>Le but de cet événement est de partager le savoir-faire des ingénieurs, et nous n'acceptons pas de participation dans le seul but de manger et de boire. Par conséquent, nous vous demandons d'échanger vos cartes de visite à la réception pour confirmer votre identité. Merci de votre collaboration.</p>\n<p>En ce qui concerne le recrutement LT, nous n'acceptons pas les discussions qui incluent des LT sans rapport avec le thème et une publicité excessive qui ne correspond pas au thème de cet événement (hors G Suite de Google).</p>\n<p>À la conférence pour tous les participants qui seront sur scène ou présents<a href=\"http://ja.confcodeofconduct.com/\" rel=\"nofollow\">Code de conduite(Conference Code of Conduct) </a>Veuillez respecter. Veuillez noter que si la direction de l'événement détermine qu'il s'agit d'un acte de harcèlement grave, nous prendrons toute mesure, y compris l'expulsion de l'événement.</p>",
"event_url": "https://gaiax.connpass.com/event/175102/",
"started_at": "2020-05-29T19:30:00+09:00",
"ended_at": "2020-05-29T22:00:00+09:00",
"limit": null,
"hash_tag": "Activité GAS",
"event_type": "participation",
"accepted": 45,
"waiting": 0,
"updated_at": "2020-05-08T14:09:19+09:00",
"owner_id": 28874,
"owner_nickname": "xtetsuji",
"owner_display_name": "OGATA Tetsuji",
"place": "en ligne",
"address": "en ligne",
"lat": null,
"lon": null,
"series": {
"id": 3109,
"title": "Gaiax Technical Meetups",
"url": "https://gaiax.connpass.com/"
}
},
{
"event_id": 173835,
"title": "[Pour les débutants] Introduction à Flutter Online Hands-on",
"catch": "Événement pratique pour ceux qui veulent toucher Flutter",
"description": "<h1>À propos de la tenue en ligne</h1>\n<p>Cette fois, il se tiendra en ligne. Le jour de l'événement, nous vous enverrons par e-mail l'URL de participation en ligne.</p>\n<h1>détail</h1>\n<p>iPhone/Flutter qui vous permet de développer des applications Andriod dans un seul environnement. Bien que le nombre de cas ait augmenté petit à petit, je pense qu'il y a beaucoup de gens qui ne l'ont pas encore abordé.</p>\n<p>Par conséquent, les ingénieurs qui développent et publient des applications natives à l'aide de Flutter expliqueront comment créer des applications simples pour les débutants, en se concentrant sur le codage en direct!</p>\n<p>※référence</p>\n<p>Veuillez consulter l'URL suivante pour les événements passés!</p>\n<p><a href=\"http://gaiax.hatenablog.com/archive\" rel=\"nofollow\">http://gaiax.hatenablog.com/archive</a></p>\n<h1>Rejoignez-nous si vous aimez ça</h1>\n<ul>\n<li>Je suis intéressé à connaître Flutter (j'en ai entendu parler)</li>\n<li>iPhone/Intéressé par le développement Android</li>\n<li>Swift /J'ai de l'expérience en développement avec kotlin et je veux connaître Flutter</li>\n<li>Avoir une certaine expérience du développement tel que le service WEB</li>\n</ul>\n<h1>calendrier</h1>\n<ul>\n<li>19:15 réception</li>\n<li>19:30 mains sur le départ</li>\n<li>21:30 Questionnaire</li>\n</ul>\n<h1>Ce que nous voulons que les participants préparent</h1>\n<ul>\n<li>Ceux qui veulent bouger leurs mains ensemble<ul>\n<li>Veuillez préparer l'environnement en vous référant à l'article Qiita suivant, etc.</li>\n<li><a href=\"https://qiita.com/tomy0610/items/896dc8ec9ba95c33194f\" rel=\"nofollow\">https://qiita.com/tomy0610/items/896dc8ec9ba95c33194f</a></li>\n</ul>\n</li>\n</ul>\n<h1>Expérience requise / ensemble de compétences</h1>\n<p>Il est destiné aux personnes ayant une certaine expérience du développement.\n Il n'y a aucune explication sur la création d'un environnement de développement, d'un langage de programmation ou d'un mécanisme de base.</p>\n<h1>Remarques</h1>\n<p>Le but de cet événement est de partager le savoir-faire des ingénieurs, et nous n'acceptons pas les exposés qui incluent des LT qui ne sont pas liés au thème ou une publicité excessive qui ne correspond pas au thème de cet événement.</p>\n<p>Veuillez noter que nous l'utiliserons comme un matériel tel que des photos et des vidéos de la scène de tenue afin de publier le rapport de l'événement sur les blogs et divers médias.</p>\n<p>Pour tous les participants qui seront sur scène ou assisteront à la conférence, à la conférence<a href=\"https://ja.confcodeofconduct.com/\" rel=\"nofollow\">Code de conduite(Conference Code of Conduct)</a>Veuillez suivre le. Veuillez noter que si la direction de l'événement détermine qu'il s'agit d'un acte de harcèlement grave, nous prendrons toute mesure, y compris l'expulsion de l'événement.</p>",
"event_url": "https://gaiax.connpass.com/event/173835/",
"started_at": "2020-05-07T19:30:00+09:00",
"ended_at": "2020-05-07T22:00:00+09:00",
"limit": null,
"hash_tag": "Flutter mains sur",
"event_type": "participation",
"accepted": 106,
"waiting": 0,
"updated_at": "2020-05-07T21:44:47+09:00",
"owner_id": 11134,
"owner_nickname": "norinux",
"owner_display_name": "norinux",
"place": "en ligne",
"address": "en ligne",
"lat": null,
"lon": null,
"series": {
"id": 3109,
"title": "Gaiax Technical Meetups",
"url": "https://gaiax.connpass.com/"
}
}
]
}
Cette fois, je veux l'essayer facilement, je vais donc définir une classe de données dans l'interface utilisateur Web. Accédez à https://app.quicktype.io/ et collez les données JSON que vous avez préparées précédemment dans le champ de saisie sur la gauche.
Si vous sélectionnez Python et cochez Classes only
, le résultat de la conversion devrait s'afficher automatiquement sur le côté droit.
Vérifiez également Transformer les noms de propriétés en Pythonic
pour une conversion ultérieure avec dacite.
Au fait, si vous désactivez Classes only
, cela définira également la méthode to_dict ()
et ainsi de suite. Cependant, il est nécessaire de réécrire chaque méthode chaque fois qu'un changement de colonne se produit.
En laissant dacite gérer ces conversions, vous pouvez alléger la charge de codage.
De plus, quicktype est bien fait et ajoutera «Facultatif» aux propriétés qui peuvent ou non être incluses dans le tableau. Essayez de supprimer la colonne ʻevent_id` de l'un des deux événements du JSON sur quicktype.
Par défaut, le nom de classe de la classe de données générée est "Welcome", changez-le en conséquence. Dans cet article, nous l'appellerons «Connpass».
Enfin, copiez la classe de données convertie dans son intégralité et enregistrez-la en tant que fichier.
Ici, enregistrez-le dans connpass.py
en fonction du nom de classe de la classe de données.
Maintenant que nous avons défini la classe de données, utilisons dacite pour convertir de JSON en classe de données.
En supposant que le JSON d'origine est enregistré dans un fichier sous le nom connpass.json
, le code sera le suivant.
main.py
import json
from dataclasses import dataclass
from datetime import datetime
from dacite import Config, from_dict
from connpass import Connpass
def run():
with open("connpass.json", "r") as f:
data = json.load(f)
connpass = from_dict(Connpass, data, Config({datetime: datetime.fromisoformat}))
print(connpass.events)
if __name__ == "__main__":
run()
La conversion réelle est effectuée sur cette ligne.
connpass = from_dict(Connpass, data, Config({datetime: datetime.fromisoformat}))
Config
effectue une conversion de type en utilisant la fonction cast de dacite.
Je passe datetime.fromisoformat
via une propriété dont le type est datetime
.
Si vous n'écrivez pas ceci, vous passerez str
à la propriété de datetime
et dacite.exceptions.WrongTypeError
sera renvoyé.
connpass = from_dict(Connpass, data)
# dacite.exceptions.WrongTypeError: wrong value type for field "events.started_at" - should be "datetime" instead of value "2020-05-29T19:30:00+09:00" of type "str"
__post_init__ ()
Au fait, cette fois, le cast était suffisant, mais si le processus de conversion est différent selon la propriété même s'il s'agit du même type, vous pouvez l'accepter avec Union et le convertir manuellement avec __post_init__ ()
.
post_init_example.py
# {"text": "hello world", "created_at": "Thu Jun 04 11:27:06 +0900 2020", "timestamp": 1591237626}
from typing import Union
from datetime import datetime
@dataclass
class Sample:
text: str
created_at: Union[str, datetime]
timestamp: Union[int, datetime]
def __post_init__(self):
self.__convert_created_at()
self.__convert_timestamp()
def __convert_created_at(self):
if type(self.created_at) is str:
self.created_at =datetime.strptime(self.created_at, "%a %b %d %H:%M:%S %z %Y")
def __convert_timestamp(self):
if type(self.timestamp) is int:
self.timestamp = datetime.fromtimestamp(self.timestamp)
Appeler connpass = from_dict (Connpass, data, Config ({datetime: datetime.fromisoformat}))
à chaque fois est pénible, nous déplaçons donc le processus de conversion vers la classe Connpass
.
connpass.py
from dataclasses import asdict, dataclass
from datetime import datetime
from typing import Any, Dict, List
from dacite import Config, from_dict
#réduction
@dataclass
class Connpass:
results_start: int
results_returned: int
results_available: int
events: List[Event]
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> "Connpass":
return from_dict(cls, data, config=Config({datetime: datetime.fromisoformat}))
def to_dict(self) -> Dict[str, Any]:
return asdict(self)
Ensuite, vous pouvez l'appeler comme ça. C'est plus simple à utiliser.
connpass = Connpass.from_dict(data)
exported_data = connpass.to_dict()
Jusqu'à présent, j'ai présenté comment implémenter facilement la conversion JSON et de classe de données à l'aide de dacite et quicktype.
Le référentiel publié sur GitHub comprend également un exemple de mise en place d'un serveur simple et de vérification de son fonctionnement. https://github.com/gaiax/quicktype-dacite-demo
La complémentation fonctionnera également, donc l'expérience de développement s'est considérablement améliorée par rapport à l'utilisation d'un dictionnaire simple. Je suis heureux.
Recommended Posts