C'est correct pour les petites applications et les scripts prétendument "uniques", en particulier avec la fonction vars
l'amélioration mentionnée par @kaizer.se et la .format
version mentionnée par @RedGlyph.
Cependant, pour les grandes applications ayant une longue durée de vie et de nombreux mainteneurs, cette pratique peut conduire à des maux de tête en matière de maintenance, et je pense que c'est de là que vient la réponse de @S.Lott. Permettez-moi d'expliquer certaines des questions en jeu, car elles ne sont peut-être pas évidentes pour quiconque ne porte pas les cicatrices du développement et de la maintenance de grandes applications (ou de composants réutilisables pour de telles bêtes).
Dans une application "sérieuse", votre chaîne de format ne serait pas codée en dur - ou, si c'était le cas, elle se présenterait sous une forme telle que _('Hello {name}.')
où le _
vient de gettext ou des cadres i18n / L10n similaires. Le fait est qu'une telle application (ou les modules réutilisables qui peuvent être utilisés dans de telles applications) doit supporter l'internationalisation (AKA i18n) et la localisation (AKA L10n) : vous voulez que votre application soit capable d'émettre "Hello Paul" dans certains pays et cultures, "Hola Paul" dans d'autres, "Ciao Paul" dans d'autres encore, et ainsi de suite. Ainsi, la chaîne de format est plus ou moins automatiquement remplacée par une autre au moment de l'exécution, en fonction des paramètres de localisation actuels ; au lieu d'être codée en dur, elle se trouve dans une sorte de base de données. À toutes fins utiles, imaginez que cette chaîne de format soit toujours une variable, et non une chaîne littérale.
Donc, ce que vous avez est essentiellement
formatstring.format(**locals())
et vous ne pouvez pas trivialement vérifier exactement ce que les noms locaux que le formatage va utiliser. Il faudrait ouvrir et parcourir la base de données L10N, identifier les chaînes de formatage qui vont être utilisées ici dans différents paramètres, et les vérifier toutes.
Donc, en pratique, vous n'avez pas connaître quels noms locaux vont être utilisés - ce qui nuit terriblement à la maintenance de la fonction. Vous n'avez pas le droit de renommer ou de supprimer une variable locale, car cela pourrait nuire à l'expérience des utilisateurs ayant une combinaison obscure (pour vous) de langues, de paramètres locaux et de préférences.
Si vous disposez d'excellents tests d'intégration/de régression, la rupture sera détectée avant la sortie de la version bêta - mais le service d'assurance qualité vous criera dessus et la sortie sera retardée... et, soyons honnêtes, si vous visez une couverture à 100 % avec unité est raisonnable, il ne l'est vraiment pas avec les intégration une fois que vous considérez l'explosion combinatoire des paramètres [[pour L10N et pour de nombreuses autres raisons]] et des versions supportées de toutes les dépendances. Ainsi, vous ne pouvez pas allègrement risquer des ruptures parce que "elles seront détectées par l'AQ" (si vous le faites, vous ne ferez pas long feu dans un environnement qui développe de grandes applications ou des composants réutilisables;-).
Ainsi, en pratique, vous ne supprimerez jamais la variable locale "name", même si les responsables de l'expérience utilisateur ont depuis longtemps remplacé ce message d'accueil par un "Welcome, Dread Overlord !" plus approprié. (et des versions L10n appropriées). Tout cela parce que vous avez choisi locals()
...
Vous accumulez donc des déchets à cause de la façon dont vous avez réduit votre capacité à maintenir et à modifier votre code - et peut-être que cette variable locale "nom" n'existe que parce qu'elle a été extraite d'une base de données ou autre, donc la conserver (ou une autre variable locale) n'est pas seulement un déchet, elle réduit aussi vos performances. Est-ce que la commodité de surface de locals()
qui vaut que ?-)
Mais attendez, il y a pire ! Parmi les nombreux services utiles qu'un lint
-comme un programme (comme, par exemple, pylint ) peut faire pour vous, c'est de vous avertir des variables locales inutilisées (j'aimerais qu'il puisse le faire aussi pour les globales inutilisées, mais, pour les composants réutilisables, c'est juste un peu trop difficile;-). De cette façon, vous attraperez la plupart des erreurs d'orthographe occasionnelles telles que if ...: nmae = ...
très rapidement et à peu de frais, plutôt que de voir un test unitaire échouer et de faire un travail de détective pour le découvrir. por qué il s'est brisé (vous faire ont des tests unitaires obsessionnels et envahissants qui serait vous finirez par l'attraper, n'est-ce pas ?) -- lint vous signalera une variable locale inutilisée nmae
et vous le réparerez immédiatement.
Mais si vous avez dans votre code un blah.format(**locals())
ou, de manière équivalente, une blah % locals()
... vous êtes SOL, mon pote!-) Comment la pauvre charpie va-t-elle savoir si nmae
est en fait une variable inutilisée, ou bien elle est utilisée par n'importe quelle fonction ou méthode externe à laquelle vous passez la commande locals()
à ? Il ne peut pas - soit il va quand même avertir (provoquant un effet de "cri du loup" qui vous conduit finalement à ignorer ou à désactiver ces avertissements), soit il ne va jamais avertir (avec le même effet final : aucun avertissement;-).
Comparez cela à l'alternative "l'explicite est meilleur que l'implicite"... :
blah.format(name=name)
Il n'y a plus aucun souci d'entretien, de performance ou de peluches, c'est le bonheur ! Vous faites comprendre immédiatement à toutes les personnes concernées (peluches comprises;-) exactement ce que Les variables locales sont utilisées, et dans quel but exactement.
Je pourrais continuer, mais je pense que ce billet est déjà assez long ;-).
Donc, en résumant : " le connaître !" Hmm, je veux dire, "connais-toi toi-même !". Et par "toi-même", je veux dire "le but et la portée de ton code". S'il s'agit d'une chose unique, qui ne sera jamais traduite en anglais et en français, qui n'aura pas besoin de maintenance ultérieure, qui ne sera jamais réutilisée dans un contexte plus large, etc, etc. locals()
Si vous savez autre chose, ou même si vous n'êtes pas tout à fait certain, optez pour la prudence et rendez les choses plus explicites - subissez le petit inconvénient d'expliquer exactement ce que vous allez faire, et profitez de tous les avantages qui en découlent.
D'ailleurs, ce n'est là qu'un des exemples où Python s'efforce de prendre en charge à la fois la programmation "petite, ponctuelle, exploratoire, voire interactive" (en autorisant et en prenant en charge des commodités hasardeuses qui vont bien au-delà de l'utilisation de l'ordinateur) et le développement de l'informatique. locals()
-- pense à import *
, eval
, exec
et bien d'autres façons de réduire en bouillie les espaces de noms et de risquer des impacts sur la maintenance pour des raisons de commodité), ainsi que des applications et des composants "importants, réutilisables et d'entreprise". Il peut faire du bon travail dans les deux cas, mais seulement si vous vous connaissez et si vous évitez d'utiliser les parties "pratiques" sauf si vous êtes absolument certain de pouvoir vous les offrir. Le plus souvent, la considération clé est "qu'est-ce que cela fait à mes espaces de noms, et à la conscience de leur formation et de leur utilisation par le compilateur, lint &c, les lecteurs et mainteneurs humains, etc ".
Rappelez-vous, "Les espaces de noms sont une idée géniale - faisons-en plus !" est la conclusion du Zen de Python... mais Python, en tant que "langage pour adultes consentants", laisse vous définir les limites de ce que cela implique, en fonction de votre environnement de développement, de vos objectifs et de vos pratiques. Utilisez ce pouvoir de manière responsable !-)