On m'a demandé d'ajouter une fonctionnalité à la fonction suivante:Comment diviser une fonction avec plusieurs comportements contrôlés par des drapeaux
def maybe_do_thing(x, y, z, really_do_thing):
if really_do_thing:
return f(x, y, z) # returns a list
return [] # an empty list if we did nothing
Plus précisément, il devrait également être en mesure d'appeler g(x, y, z)
, contrôlée par un montant supplémentaire drapeau. La mise en œuvre est évidente:
def maybe_do_things(x, y, z, do_f, do_g):
results = []
if do_f:
results.extend(f(x, y, z))
if do_g:
results.extend(g(x, y)) # g needs slightly different params
return results
Pour être clair, un sous-ensemble de f et g peut être appelé: à la fois, non plus, ou un seul, selon les deux drapeaux distincts. f et g sont liés conceptuellement, il est donc logique de les regrouper comme ça, mais cela me semble plutôt insatisfaisant: en réalité, maybe_do_things
est juste une multitude de fonctions se déguisant en une seule fonction au moyen de plusieurs drapeaux. Je suis assez sûr que c'est un anti-modèle, mais je ne sais pas comment ça s'appelle ou quel est le bon modèle pour le réparer. Je pense que je devrais être capable de le diviser en plusieurs fonctions autosuffisantes d'une manière qui est toujours aussi pratique à appeler que la fonction composite, ou nettoyer d'une manière ou d'une autre l'API de la fonction composite afin qu'elle ne soit pas un gros blob . Pour chaque site d'appel, il n'est pas très judicieux d'indiquer Il peut être utile que les appelants sachent à l'avance lequel de f et g sera exécuté, mais ces deux paramètres sont déterminés au moment de l'exécution. Ainsi, chaque appelant aurait besoin du corps complet de la fonction en cours, ainsi que des définitions locales représentant les variables x/y/z maintenant répétées.
Je ne pense pas que beaucoup de fonctionnalités seront ajoutées à cette fonction à l'avenir, donc au moins je n'ai pas à m'inquiéter de l'explosion de la liste de paramètres. Peut-être que ma mise en œuvre "évidente" est en fait le meilleur compromis?
Si l'appelant a suffisamment d'informations pour savoir si passer '' do_f' ou do_g', ils ont suffisamment d'informations pour appelez juste le bon eux-mêmes. C'est un peu difficile à analyser sans en savoir plus sur ces drapeaux et où/comment les fonctions sont appelées. Mais une possibilité est de considérer "really_do_thing" comme un "drapeau" indiquant s'il faut appeler "f", d'appeler cet argument "contexte" ou autre. Ensuite, chaque site d'appel passe un "contexte" qui contient toutes les informations nécessaires pour décider quoi faire réellement. Mieux vaut peut-être faire du contexte un objet qui a f, g, etc. comme méthodes. – BrenBarn
Oui, ils ont assez d'informations pour pouvoir appeler eux-mêmes les bonnes fonctions. Mais il est beaucoup plus facile de simplement passer un argument booléen à la fonction 'maybe_do_things', par exemple' maybe_do_things (..., should_i_do_f()) ', que d'écrire l'ensemble de' if should_i_do_f(): f (x, y, z) ', si' f' est une chose compliquée à faire. – amalloy