mardi 6 octobre 2015

Inférence entre dictionnaire et paramètres nommés

Cas pratique
J'ai un cas pratique où je veux recharger des données depuis un fichier json (une fois chargé, j'ai une liste de dictionnaire) PUIS les injecter dans une DB à l'aide de sqlAlchemy.
In [57]: d[0]
Out[57]: 
{'actif': 'Y',
 'libe': 'Le carbone lorraine',
 'name': '0200',
 'pnet': 50.0,
 'sync_id': 1.0}

In [58]: d[1]
Out[58]: 
{'actif': 'Y',
 'libe': 'BUSELURES',
 'name': '0201',
 'pnet': 50.0,
 'sync_id': 2.0}

Dans sqlAlchemy, j'ai définit un modèle pour mes tables.
En utilisant ce modèle (ici family_table), l'insertion est relativement simple:

q = family_table.insert()
q.execute( actif='Y', libe= 'Le carbone lorraine', name= '0200', pnet= 50.0, sync_id= 1.0 )

Mais ce qui serait vraiment cool, c'est appeler execute() directement avec le dictionnaire d[0], d[1], ...et se passer de la tache fastidieuse décrite ci-dessus. Comme sqlAlchemy utilise **kwargs, nous pouvons faire de l'inférence :-)

q = family_table.insert()
dic = d[0] # récuperer un dictionnaire
# La ligne suivante dit que dic doit être passé directement
# en tant que paramètre **kwargs de la fonction 
q.execute( **dic ) 

**KWargs - comment ça marche?
Définissons la fonction printkw() pour afficher les valeurs disponibles dans le paramètre **kwargs.
En fait, kwargs est un dictionnaire qui contient les paramètres nommés sous forme clé = valeur. Comme kwargs n'est pas un mot clé (mais une convention de nommage), on utilise le signe ** pour identifier kwargs (et ses propriétés extraordinaires) dans la déclaration de la fonction printkw()
Vous pourriez fort bien appeler ce paramètre **dico_des_parametre_nommes , mais il est préférable de respecter les conventions.

def printkw( **kwargs ):
   for k,v in kwargs.items():
      print( '%s = %r' % (k,v) )

Maintenant, si nous appelons la fonction printkw() avec des paramètres nommés, nous avons:

>>>printkw( name='hello', value=12, value2='test me' )
value2 = 'test me'
name = 'hello'
value = 12

Dans notre fonction printkw() nous pourrions facilement récupérer une valeur donnée avec l'instruction le_nom = kwargs['name']
Cela nous fournirait la valeur du paramètre "name".

Mais le plus intéressant, selon moi, réside au passage des paramètres par l'intermédiaire d'un dictionnaire. Il devient alors très facile de:
  • Passer de nombreuses valeurs d'une fonction à l'autre
  • De présenter une interface très flexible (surtout avec des DB) pour transmettre de nombreuses données
  • De faire une persistance des paramètres nommés dans une DB,Fichier, Json, service en ligne, etc
>>> d = { 'name':'hello', 'value':12, 'value2':'test me' }
>>> printkw( **d )
value2 = 'test me'
name = 'hello'
value = 12

La première ligne crée un dictionnaire avec les paramètre nommés (qui auraient pu provenir d'un fichier json comme dans l'intro de l'article).
La deuxième ligne appel printkw() en passant le dictionnaire d en tant que paramètres nommés (c'est à cela que sert ** )

Recharger un fichier json
Juste pour le fun, voici comment j'ai rechargé le fichier json dans la liste d.

import json
# retourne le nom de fichier pour les données famille
#    'c:\\python\\catflask-alpha\\toolbox\\family.json'
filename = json_filename( 'family' )
with open( filename ) as json_data:
    d = json.load( json_data )
    json_data.close()

1 commentaire:

Anonyme a dit…

On ne doit pas faire de close() quand on utilise un context manager.
Il faut supprimer la ligne
json_data.close()