** kwargs est-il un contre-modèle?


16

Nous avons beaucoup de code dans notre base de code interne qui appelle nos bibliothèques en interne - ces bibliothèques ont souvent beaucoup d'arguments (pensez matplotlib) et notre code ne fait souvent qu'une tâche spécifique et passe simplement la **kwargsà la fonction suivante appelée.

Par exemple:

def our_method(dataframe, **kwargs):
    result = do_something_with_data(dataframe)
    external_module.draw(result, **kwargs)

Tout en **kwargsnous empêchant de répéter tous les paramètres de notre déclaration de méthode, cela rend également extrêmement opaques les arguments valides lors de l'appel our_method- je dois savoir quelle méthode est appelée, ce que je ne veux souvent pas savoir.

Quelle est votre opinion à ce sujet?

Réponses:


16

Comment votre code est-il utilisé par les développeurs? En d'autres termes, que font-ils exactement pour déterminer quels arguments doivent être utilisés et comment?

  • S'ils s'appuient sur une documentation générée automatiquement à partir de votre code, et que le générateur n'a aucune idée de quoi en faire **kwargs, cela est en effet problématique. Au lieu de trouver la liste des arguments et leur signification dans la documentation, ils n'ont absolument aucune information sauf le vague «il faut des arguments».

    Ce problème peut probablement être résolu en documentant la méthode manuellement, en remplaçant la documentation générée automatiquement. Cela nécessite un travail supplémentaire de la part de l'implémenteur de la méthode, mais n'oubliez pas que le code (et sa documentation) est lu beaucoup plus fréquemment qu'il n'est écrit.

  • Si le code est leur documentation, les développeurs qui utilisent la méthode ont **kwargsbesoin de deux étapes supplémentaires: ils doivent non seulement regarder la signature de la méthode, mais aussi sa mise en œuvre réelle, afin de trouver l'autre méthode qu'il appelle réellement. Ensuite, ils doivent passer à cette autre méthode pour enfin trouver ce qu'ils cherchaient.

    Cela n'implique pas beaucoup d'efforts, mais néanmoins, l'effort doit être répété, encore et encore. Le pire, c'est que vous ne pouvez pas les aider en ajoutant de la documentation: si vous commentez votre méthode, en listant les arguments réels, il y a un gros risque que la prochaine version de la bibliothèque que vos appels de méthode aient différents arguments, et votre documentation être dépassé, car personne ne se souviendra qu'il doit être tenu à jour.

Ma recommandation est de ne compter **kwargsque sur les méthodes qui ont une portée réduite. Les méthodes privées (et par privé dans un contexte Python, je veux dire les méthodes commençant par_ ) qui sont utilisées à quelques endroits dans la classe sont de bons candidats, par exemple. D'un autre côté, les méthodes utilisées par des dizaines de classes partout dans la base de code sont de très mauvais candidats.

Après tout, cela ne devrait pas prendre trop d'efforts pour réécrire les arguments d'une méthode que vous appelez dans la méthode que vous écrivez. Espérons que la plupart des méthodes ne prennent pas plus de six à huit arguments, et si c'est le cas, demandez-vous si vous ne devriez pas refactoriser le code. Dans tous les cas:

  • Rendre les arguments explicites dans votre méthode ne nécessite pas beaucoup d'efforts,

  • Vous voudrez peut-être, plus tard, valider les arguments de toute façon (bien que si vous vous fiez uniquement à ce point pour rendre les arguments explicites, vous violez YAGNI).


J'aime vraiment cette réponse et je pense que c'est une bonne réponse. Malheureusement, beaucoup de notre code a beaucoup de méthodes publiques utilisant ce modèle. Mais maintenant, j'ai des arguments que nous devons le changer (et laisser tomber matplotlib, jamais vu une "interface" plus merdique ..)
Christian Sauer

3

Si la fonction de niveau supérieur a un __doc__, vous pouvez simplement copier le __doc__ dans votre nouvelle fonction.

Par exemple:

def a(x):
    """This function takes one parameter, x, and does nothing with it!"""
    pass

def b(**kwargs):
    a(**kwargs)

b.__doc__=a.__doc__

Cela pourrait s'appliquer de manière récursive et pourrait être appliqué par un décorateur (ce qui pourrait être utile si vous le faites de manière groupée). La chaîne __doc__ peut également être manipulée pour ajouter plus à la fin. Cela signifie que les paramètres affichés seraient toujours des kwargs, mais au moins il y a de la documentation dans l'aide décrivant les paramètres réels.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.