web-dev-qa-db-fra.com

Comment créer un nombre variable de variables?

Comment puis-je accomplir des variables variables en Python?

Voici une entrée manuelle élaborative, par exemple: variables variables

J'ai entendu dire que c'était une mauvaise idée en général, et que c'était un trou de sécurité en Python. Est-ce vrai?

295
Pyornide

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

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

Vous pouvez utiliser des noms de clé variables pour obtenir l'effet de variables variables sans 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 dict. Une liste représente une séquence ordonnée d'objets, avec des index entiers:

l = ['foo', 'bar', 'baz']
print(l[1])           # prints bar, because indices start at 0
l.append('potatoes')  # l is now ['foo', 'bar', 'baz', 'potatoes']

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

252
c_harm

Utilisez la fonction intégrée getattr pour obtenir un attribut sur un objet par son nom. Modifiez le nom si nécessaire.

obj.spam = 'eggs'
name = 'spam'
getattr(obj, name)  # returns 'eggs'
76
SilentGhost

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 souhaitez accéder à une variable de la portée locale, vous pouvez utiliser locals() , mais vous ne pouvez pas affecter de valeurs au dict retourné.

Une meilleure solution consiste à utiliser getattr ou à stocker vos variables dans un dictionnaire, puis à y accéder par leur nom.

61
Nadia Alramli

Lorsque vous souhaitez 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 n'écraserez pas accidentellement des variables existantes (ce qui est l'aspect sécurité) et vous pouvez avoir différents "espaces de noms".

32
sepp2k

Les nouveaux codeurs écrivent parfois du code comme celui-ci:

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)
...

Le codeur 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 consulté (création comprise). Le débutant plus astucieux observe que la seule différence entre chacune de ces lignes est un nombre qui change en fonction d’une règle et décide d’utiliser une boucle. Cependant, ils ne savent pas comment créer dynamiquement ces noms de variables et peuvent essayer quelque chose comme ça:

for i in range(10):
    my_calculator.('button_%d' % i) = tkinter.Button(root, text=i)

Ils constatent rapidement 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 cela ne vous dérange pas de vous y référer avec une suite d’entiers, vous recherchez probablement un list. Cela est particulièrement vrai si vos données sont homogènes, telles que les lectures quotidiennes de la température, les scores hebdomadaires du quiz ou une grille de widgets graphiques.

Ceci 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 ligne avec une compréhension:

my_calculator.buttons = [tkinter.Button(root, text=i) for i in range(10)]

Dans les deux cas, le résultat est un list rempli, avec le premier élément auquel accéder avec my_calculator.buttons[0], le suivant avec my_calculator.buttons[1], etc. Le nom de la variable "base" devient le nom de la list et l'identifiant variable est utilisé pour y accéder.

Enfin, n'oubliez pas les autres structures de données, telles que set - cela ressemble à un dictionnaire, sauf que chaque "nom" n'a pas de valeur. Si vous avez simplement besoin d'un "sac" d'objets, cela peut être un excellent choix. Au lieu de quelque chose comme ça:

keyword_1 = 'Apple'
keyword_2 = 'banana'

if query == keyword_1 or query == keyword_2:
    print('Match.')

Vous aurez ceci:

keywords = {'Apple', 'banana'}
if query in keywords:
    print('Match.')

Utilisez un list pour une séquence d'objets similaires, un set pour un sac d'objets ordonné de manière arbitraire ou un dict pour un sac de noms avec des valeurs associées.

25
TigerhawkT3

Au lieu d'un dictionnaire, vous pouvez également utiliser namedtuple à partir du module Collections, ce qui facilite l'accès.

Par exemple:

# using dictionary
variables = {}
variables["first"] = 34
variables["second"] = 45
print(variables["first"], variables["second"])

# using namedtuple
Variables = namedtuple('Variables', ['first', 'second'])
vars = Variables(34, 45)
print(vars.first, vars.second)
10
ojas mohril

La classe SimpleNamespace peut être utilisée pour créer de nouveaux attributs avec setattr ou la sous-classe SimpleNamespace et créer votre propre fonction pour ajouter de nouveaux noms d'attributs (variables).

from types import SimpleNamespace

variables = {"b":"B","c":"C"}
a = SimpleNamespace(**variables)
setattr(a,"g","G")
a.g = "G+"
something = a.a
9
Bill Oldroyd

Si vous ne souhaitez utiliser aucun objet, vous pouvez toujours utiliser setattr() dans votre module actuel:

import sys
current_module = module = sys.modules[__name__]  # i.e the "file" where your code is written
setattr(current_module, 'variable_name', 15)  # 15 is the value you assign to the var
print(variable_name)  # >>> 15, created from a string
7
Guillaume Lebreton

Vous devez utiliser globals() méthode intégrée pour obtenir ce comportement:

def var_of_var(k, v):
    globals()[k] = v

print variable_name # NameError: name 'variable_name' is not defined
some_name = 'variable_name'
globals()[some_name] = 123
print variable_name # 123

some_name = 'variable_name2'
var_of_var(some_name, 456)
print variable_name2 # 456
5
Andriy Ivaneyko

Je réponds à la question: Comment obtenir la valeur d'une variable étant donné son nom dans une chaîne? qui est fermé comme un doublon avec un lien vers cette question.

Si les variables en question font partie d'un objet (par exemple, une partie d'une classe), certaines des fonctions utiles pour obtenir exactement ce résultat sont hasattr, getattr et setattr.

Ainsi, par exemple, vous pouvez avoir:

class Variables(object):
    def __init__(self):
        self.foo = "initial_variable"
    def create_new_var(self,name,value):
        setattr(self,name,value)
    def get_var(self,name):
        if hasattr(self,name):
            return getattr(self,name)
        else:
            raise("Class does not have a variable named: "+name)

Ensuite, vous pouvez faire:

v = Variables()
v.get_var("foo")

"variable_initial"

v.create_new_var(v.foo,"is actually not initial")
v.initial_variable

"n'est en réalité pas initiale"

3
patapouf_ai

Utiliser globals()

Vous pouvez en fait affecter dynamiquement des variables à la portée globale, par exemple, si vous souhaitez que 10 variables soient accessibles sur une portée globale i_1, i_2 ... i_10:

for i in range(10):
    globals()['i_{}'.format(i)] = 'a'

Cela affectera "a" à l'ensemble de ces 10 variables. Vous pourrez bien entendu modifier la valeur de manière dynamique. Toutes ces variables sont accessibles maintenant comme les autres variables déclarées globalement:

>>> i_5
'a'
2
Rocky Li

Il existe une méthode connue pour émuler un conteneur de variables, qui supporte les deux méthodes d'accès: par le nom d'une variable et par une clé de chaîne.

class Vars:
    def __init__(self, **kw):
        self.__dict__.update(kw)

    def __getitem__(self, key):
        return self.__dict__[key]

    def __setitem__(self, key, val):
        self.__dict__[key] = val

    def __contains__(self, name):
        return name in self.__dict__

    def __nonzero__(self):
        return bool(self.__dict__)

    def __iter__(self):
        return iter(self.__dict__)

    def __len__(self):
        return len(self.__dict__)

    def __copy__(self):
        return self.__class__(**self.__dict__)

    def __repr__(self):
        return 'Vars(' + ', '.join('%s=%r' % (k,v) for k,v in self.__dict__.items()) + ')'

>>> vars = Vars()
>>> vars.a = 1
>>> vars['b'] = 2
>>> print(vars)
Vars(a=1, b=2)
>>> print(vars['a'], vars.b)
1 2
>>> print(Tuple(vars))
('a', 'b')
1
intellimath

Le consensus est d'utiliser un dictionnaire pour cela - voir les autres réponses. C’est une bonne idée dans la plupart des cas, cependant, il en résulte de nombreux aspects:

  • vous serez vous-même responsable de ce dictionnaire, y compris la récupération de place (de variables in-dict), etc.
  • il n'y a pas de localité ou de globalité pour les variables variables, cela dépend de la globalité du dictionnaire
  • si vous voulez renommer un nom de variable, vous devrez le faire manuellement
  • cependant, vous êtes beaucoup plus flexible, par exemple
    • vous pouvez décider d'écraser les variables existantes ou ...
    • ... choisit d'implémenter des variables const
    • lever une exception sur l'écrasement pour différents types
    • etc.

Cela dit, j'ai implémenté une classe gestionnaire de variables variables - qui fournit certaines des idées ci-dessus. Cela fonctionne pour python 2 et 3.

Vous utiliseriez la classe comme ceci:

from variableVariablesManager import VariableVariablesManager

myVars = VariableVariablesManager()
myVars['test'] = 25
print(myVars['test'])

# define a const variable
myVars.defineConstVariable('myconst', 13)
try:
    myVars['myconst'] = 14 # <- this raises an error, since 'myconst' must not be changed
    print("not allowed")
except AttributeError as e:
    pass

# rename a variable
myVars.renameVariable('myconst', 'myconstOther')

# preserve locality
def testLocalVar():
    myVars = VariableVariablesManager()
    myVars['test'] = 13
    print("inside function myVars['test']:", myVars['test'])
testLocalVar()
print("outside function myVars['test']:", myVars['test'])

# define a global variable
myVars.defineGlobalVariable('globalVar', 12)
def testGlobalVar():
    myVars = VariableVariablesManager()
    print("inside function myVars['globalVar']:", myVars['globalVar'])
    myVars['globalVar'] = 13
    print("inside function myVars['globalVar'] (having been changed):", myVars['globalVar'])
testGlobalVar()
print("outside function myVars['globalVar']:", myVars['globalVar'])

Si vous souhaitez autoriser le remplacement de variables du même type uniquement:

myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)
1
DomTomCat

Veuillez vous référer à l'exemple suivant pour créer des variables d'exécution. Vous pouvez utiliser globals().

for i in range(3):
    globals() ['variable_'+str(i)] = i

Dans l'exemple ci-dessus, je souhaite créer trois variables: variable_0, variable_1 et variable_2 à l'exécution avec les valeurs 0,1 et 2 respectivement.

variable_0
[Output]:0

variable_1
[Output]:1

variable_2
[Output]:2

Pour accéder à la valeur des variables créées à l'exécution, vous pouvez utiliser la méthode eval() comme suit:

for i in range(3):
globals() ['variable_'+str(i)] = i
print('Variable Value:',eval('variable_'+str(i)))

[Output]:
Variable Value: 0
Variable Value: 1
Variable Value: 2
1
Sayali Sonawane

Tout ensemble de variables peut également être encapsulé dans une classe. Des variables "variables" peuvent être ajoutées à l'instance de classe pendant l'exécution en accédant directement au dictionnaire intégré via l'attribut __dict__.

Le code suivant définit la classe Variables, qui ajoute des variables (dans ce cas, des attributs) à son instance lors de la construction. Les noms de variables proviennent d'une liste spécifiée (qui, par exemple, aurait pu être générée par le code du programme):

# some list of variable names
L = ['a', 'b', 'c']

class Variables:
    def __init__(self, L):
        for item in L:
            self.__dict__[item] = 100

v = Variables(L)
print(v.a, v.b, v.c)
#will produce 100 100 100
0
Alexey Rodimov

vous pouvez utiliser la fonction intégrée vars()

>>> foo = 'bar'
>>> vars()[foo] = 'something'
>>> bar
'something'
0
Kelvin