562 votes

Comment puis-je créer des variables variables?

Je sais que certaines autres langues, comme le PHP, prennent en charge le concept de "noms de variables variables" - c'est-à-dire que le contenu d'une chaîne peut être utilisé comme partie d'un nom de variable.

J'ai entendu dire que c'est une mauvaise idée en général, mais je pense que cela résoudrait certains problèmes que j'ai dans mon code Python.

Est-il possible de faire quelque chose comme ça en Python ? Quels sont les risques ?


Si vous essayez simplement de <em>rechercher une variable existante</em> par son nom, consultez <a href="https://stackoverflow.com/questions/47496415">Comment puis-je sélectionner une variable par son nom (chaîne) ?</a>. Cependant, envisagez d'abord de réorganiser le code pour éviter ce besoin, en suivant les conseils de cette question.

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)

449voto

Vous pouvez utiliser des dictionnaires pour accomplir cela. Les dictionnaires sont des magasins de clés et de valeurs.

>>> dct = {'x': 1, 'y': 2, 'z': 3}
>>> dct
{'x': 1, 'y': 2, 'z': 3}
>>> dct["y"]
2

Vous pouvez utiliser des noms de clés variables pour obtenir l'effet de variables variables sans le risque de sécurité.

>>> x = "spam"
>>> z = {x: "eggs"}
>>> z["spam"]
'eggs'

Pour les cas où vous envisagez de faire quelque chose comme

var1 = 'foo'
var2 = 'bar'
var3 = 'baz'
...

une liste peut être plus appropriée qu'un dictionnaire. Une liste représente une séquence ordonnée d'objets, avec des indices entiers :

lst = ['foo', 'bar', 'baz']
print(lst[1])           # affiche bar, car les indices commencent à 0
lst.append('potatoes')  # lst est maintenant ['foo', 'bar', 'baz', 'potatoes']

Pour les séquences ordonnées, les listes sont plus pratiques que les dictionnaires avec des clés entières, car les listes prennent en charge l'itération dans l'ordre des index, le découpage, append, et d'autres opérations qui nécessiteraient une gestion des clés maladroite avec un dictionnaire.

118voto

SilentGhost Points 79627

Utilisez la fonction intégrée getattr pour obtenir un attribut sur un objet par son nom. Modifiez le nom selon vos besoins.

obj.spam = 'eggs'
name = 'spam'
getattr(obj, name)  # retourne 'eggs'

95voto

Nadia Alramli Points 40381

Ce n'est pas une bonne idée. Si vous accédez à une variable globale, vous pouvez utiliser globals() .

>>> a = 10
>>> globals()['a']
10

Si vous voulez accéder à une variable dans la portée locale, vous pouvez utiliser locals() , mais vous ne pouvez pas attribuer de valeurs au dictionnaire retourné.

Une meilleure solution est d'utiliser getattr ou de stocker vos variables dans un dictionnaire et ensuite y accéder par nom.

3 votes

locals().update({'new_local_var':'some local value'}) fonctionne très bien pour moi en Python 3.7.6 ; donc je ne sais pas ce que vous voulez dire quand vous dites que vous ne pouvez pas attribuer des valeurs à travers cela.

0 votes

Étant donné que x = "foo" et locals()["x"] = "bar" en utilisant print x donne la sortie bar pour Jython 2.5.2. Ceci a été testé avec un script d'automatisation à la demande dans maximo.

9 votes

La documentation de locals() indique spécifiquement : "Le contenu de ce dictionnaire ne doit pas être modifié." (mes soulignements)

89voto

TigerhawkT3 Points 25584

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.

49voto

sepp2k Points 157757

Chaque fois que vous voulez utiliser des variables variables, il est probablement préférable d'utiliser un dictionnaire. Donc au lieu d'écrire

$foo = "bar"
$$foo = "baz"

vous écrivez

mydict = {}
foo = "bar"
mydict[foo] = "baz"

De cette façon, vous ne risquez pas d'écraser accidentellement des variables déjà existantes (ce qui est l'aspect sécurité) et vous pouvez avoir des "espaces de noms" différents.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X