Les nouveaux codeurs écrivent parfois du code comme ceci :
my_calculator.button_0 = tkinter.Button(root, text=0)
my_calculator.button_1 = tkinter.Button(root, text=1)
my_calculator.button_2 = tkinter.Button(root, text=2)
...
L'informaticien se retrouve alors avec une pile de variables nommées, avec un effort de codage de O(m * n), où m est le nombre de variables nommées et n est le nombre de fois que ce groupe de variables doit être accédé (y compris la création). Le débutant plus astucieux observe que la seule différence dans chacune de ces lignes est un nombre qui change en fonction d'une règle, et décide d'utiliser une boucle. Cependant, il se bloque sur la façon de créer dynamiquement ces noms de variable, et peut essayer quelque chose comme ceci :
for i in range(10):
my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)
Ils découvrent bientôt que cela ne fonctionne pas.
Si le programme nécessite des "noms" de variables arbitraires, un dictionnaire est le meilleur choix, comme expliqué dans d'autres réponses. Cependant, si vous essayez simplement de créer de nombreuses variables et que vous ne vous souciez pas de les nommer avec une séquence d'entiers, vous cherchez probablement une list
. C'est particulièrement vrai si vos données sont homogènes, comme les relevés de température quotidienne, les scores de quiz hebdomadaires, ou une grille de widgets graphiques.
Cela peut être assemblé comme suit :
my_calculator.buttons = []
for i in range(10):
my_calculator.buttons.append(tkinter.Button(root, text=i))
Cette list
peut également être créée en une seule ligne avec une compréhension :
my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]
Le résultat dans les deux cas est une list
peuplée, le premier élément étant accessible avec my_calculator.buttons[0]
, le suivant avec my_calculator.buttons[1]
, et ainsi de suite. Le nom de variable "de base" devient le nom de la list
et l'identifiant variable variable est utilisé pour y accéder.
Enfin, n'oubliez pas les autres structures de données, comme le set
- il est similaire à un dictionnaire, sauf que chaque "nom" n'a pas de valeur attachée. Si vous avez simplement besoin d'un "sac" d'objets, cela peut être un excellent choix. Au lieu de quelque chose comme ceci :
keyword_1 = 'pomme'
keyword_2 = 'banane'
if requête == keyword_1 or requête == keyword_2:
print('Correspondance.')
Vous aurez ceci :
mots_clés = {'pomme', 'banane'}
if requête in mots_clés:
print('Correspondance.')
Utilisez une list
pour une séquence d'objets similaires, un set
pour un sac d'objets sans ordre spécifique, ou un dict
pour un sac de noms avec des valeurs associées.
85 votes
C'est les aspects de maintenance et de débogage qui causent l'horreur. Imaginez essayer de savoir où la variable 'foo' a changé quand il n'y a pas d'endroit dans votre code où vous changez réellement 'foo'. Imaginez en outre que c'est le code de quelqu'un d'autre que vous devez maintenir... OK, vous pouvez maintenant aller à votre endroit heureux.
18 votes
Un autre piège qui n'a pas encore été mentionné est si une variable créée dynamiquement a le même nom qu'une variable utilisée dans votre logique. Vous ouvrez essentiellement votre logiciel comme otage de l'entrée qui lui est donnée.
1 votes
Toutes les réponses ici supposent que vous avez accès aux variables de base que vous souhaitez accéder dynamiquement par nom, ce qui n'est pas toujours le cas. Je pense que l'approche la plus générale pour reproduire le comportement de l'exemple en PHP est d'utiliser eval() comme ceci : \= 'foo'; bar = 5; output = eval(var_name)
7 votes
Vous pouvez modifier vos variables globales et locales en accédant aux dictionnaires sous-jacents qui leur sont associés; c'est une idée horrible d'un point de vue de maintenance ... mais cela peut être fait via globals().update() et locals().update() (ou en sauvegardant la référence du dictionnaire à partir de l'un de ceux-ci et en l'utilisant comme n'importe quel autre dictionnaire). NON RECOMMANDÉ ... mais vous devriez savoir que c'est possible.
3 votes
@JimDennis en fait, non, ce n'est pas possible. Les modifications apportées au dict retourné par
locals
n'affecteront pas les espaces de noms locaux dans CPython. C'est une autre raison de ne pas le faire.2 votes
@juanpa.arrivillaga: J'avais essayé de tester cela dans un shell IPython, mais je l'ai fait au niveau supérieur (où locals() se comporte comme globsls()). Refaire ce test dans un code imbriqué (dans la définition d'une fonction) montre que je ne peux pas modifier locals() de l'intérieur. Comme vous l'avez dit, l'aide pour locals (3.7.6) met en garde : "NOTE: Que les mises à jour de ce dictionnaire affecteront ou non les recherches de noms dans la portée locale et vice-versa est dépendant de l'implémentation et n'est couvert par aucune garantie de compatibilité ascendante."