Wie erstelle ich eine variable Anzahl von Variablen?

364

Wie führe ich Variablenvariablen in Python durch?

Hier ist ein ausführlicher manueller Eintrag, zum Beispiel: Variable Variablen

Ich habe gehört, dass dies im Allgemeinen eine schlechte Idee ist, und es ist eine Sicherheitslücke in Python. Ist das wahr?

Taryn
quelle
39
Es sind die Wartungs- und Debugging-Aspekte, die den Horror verursachen. Stellen Sie sich vor, Sie möchten herausfinden, wo sich die Variable 'foo' geändert hat, wenn in Ihrem Code keine Stelle vorhanden ist, an der Sie 'foo' tatsächlich ändern. Stellen Sie sich weiter vor, dass Sie den Code eines anderen pflegen müssen ... OK, Sie können jetzt zu Ihrem glücklichen Ort gehen.
Glenn Jackman
4
Eine weitere Gefahr, die bisher nicht erwähnt wurde, besteht darin, dass eine solche dynamisch erstellte Variable denselben Namen hat wie eine in Ihrer Logik verwendete Variable. Sie öffnen Ihre Software im Wesentlichen als Geisel für die Eingabe, die sie gibt.
Holdenweb
Bei allen Antworten hier wird davon ausgegangen, dass Sie Zugriff auf die Basisvariablen haben, auf die Sie dynamisch nach Namen zugreifen möchten, was nicht immer der Fall ist. Ich denke, der allgemeinste Ansatz, um das Beispielverhalten in PHP zu reproduzieren, ist die Verwendung von eval () wie folgt: var_name = 'foo'; Balken = 5; output = eval (var_name)
Luis Vazquez
1
Sie können Ihre globalen und lokalen Variablen ändern, indem Sie auf die zugrunde liegenden Wörterbücher zugreifen. Aus Wartungssicht ist dies eine schreckliche Idee ... aber sie kann über globals (). update () und local (). update () (oder durch Speichern der Diktatreferenz von beiden und Verwendung wie bei jedem anderen Wörterbuch) erfolgen ). NICHT EMPFOHLEN ... aber Sie sollten wissen, dass es möglich ist.
Jim Dennis
(Ich füge diesen Kommentar hinzu, weil eine ähnliche Frage, insbesondere das Anfordern dieser Art von Manipulation, mit einem Zeiger auf diese "nah genug" -Frage geschlossen wurde. Ich möchte, dass diejenigen, die der geschlossenen Frage folgen, ihre Antwort erhalten.)
Jim Dennis

Antworten:

297

Sie können Wörterbücher verwenden , um dies zu erreichen. Wörterbücher sind Speicher von Schlüsseln und Werten.

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

Sie können Variablenschlüsselnamen verwenden, um die Wirkung variabler Variablen ohne Sicherheitsrisiko zu erzielen.

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

Für Fälle, in denen Sie daran denken, so etwas zu tun

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

Eine Liste ist möglicherweise angemessener als ein Diktat. Eine Liste repräsentiert eine geordnete Folge von Objekten mit ganzzahligen Indizes:

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

Für geordnete Sequenzen, sind Listen bequemer als dicts mit Integer - Schlüssel, weil Listen Iteration in Indexreihenfolge unterstützen, Slicing , appendund anderen Operationen , die umständlich Schlüssel - Management mit einem dict erfordern würden.

ggorlen
quelle
88

Verwenden Sie die integrierte getattrFunktion, um ein Attribut für ein Objekt nach Namen abzurufen. Ändern Sie den Namen nach Bedarf.

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

Das ist keine gute Idee. Wenn Sie auf eine globale Variable zugreifen, können Sie diese verwenden globals().

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

Wenn Sie auf eine Variable im lokalen Bereich zugreifen möchten, können Sie sie verwenden locals(), dem zurückgegebenen Diktat jedoch keine Werte zuweisen.

Eine bessere Lösung besteht darin getattr, Ihre Variablen in einem Wörterbuch zu verwenden oder zu speichern und dann über den Namen darauf zuzugreifen.

Nadia Alramli
quelle
local (). update ({'new_local_var': 'ein lokaler Wert'}) funktioniert in Python 3.7.6 für mich einwandfrei; Ich bin mir also nicht sicher, was Sie meinen, wenn Sie sagen, dass Sie dadurch keine Werte zuweisen können.
Jim Dennis
Gegeben x = "foo"und locals()["x"] = "bar"Verwenden print xgibt die Ausgabe barfür Jython 2.5.2. Dies wurde mit einem On-Demand-Automatisierungsskript in maximo getestet .
Prediger
37

Wann immer Sie variable Variablen verwenden möchten, ist es wahrscheinlich besser, ein Wörterbuch zu verwenden. Also anstatt zu schreiben

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

du schreibst

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

Auf diese Weise überschreiben Sie nicht versehentlich zuvor vorhandene Variablen (was der Sicherheitsaspekt ist) und können verschiedene "Namespaces" haben.

sepp2k
quelle
34

Neue Codierer schreiben manchmal Code wie folgt:

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

Dem Codierer bleibt dann ein Stapel benannter Variablen mit einem Codierungsaufwand von O ( m * n ) übrig , wobei m die Anzahl der benannten Variablen und n die Häufigkeit ist, mit der auf diese Gruppe von Variablen zugegriffen werden muss (einschließlich der Erstellung) ). Der klügere Anfänger stellt fest, dass der einzige Unterschied in jeder dieser Zeilen eine Zahl ist, die sich aufgrund einer Regel ändert, und entscheidet sich für die Verwendung einer Schleife. Sie bleiben jedoch bei der dynamischen Erstellung dieser Variablennamen hängen und versuchen möglicherweise Folgendes:

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

Sie stellen bald fest, dass dies nicht funktioniert.

Wenn das Programm beliebige Variablennamen benötigt, ist ein Wörterbuch die beste Wahl, wie in anderen Antworten erläutert. Wenn Sie jedoch einfach versuchen, viele Variablen zu erstellen, und es Ihnen nichts ausmacht, mit einer Folge von Ganzzahlen auf sie zu verweisen, suchen Sie wahrscheinlich nach einer list. Dies gilt insbesondere dann, wenn Ihre Daten homogen sind, z. B. tägliche Temperaturwerte, wöchentliche Quizergebnisse oder ein Raster grafischer Widgets.

Dies kann wie folgt zusammengesetzt werden:

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

Dies listkann auch in einer Zeile mit einem Verständnis erstellt werden:

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

In beiden Fällen ist das Ergebnis ein ausgefülltes Ergebnis list, bei dem auf das erste Element zugegriffen wird my_calculator.buttons[0], auf das nächste mit my_calculator.buttons[1]und so weiter. Der Name der "Basis" -Variable wird zum Namen der listund der variierende Bezeichner wird verwendet, um darauf zuzugreifen.

Vergessen Sie nicht andere Datenstrukturen wie die set- dies ähnelt einem Wörterbuch, außer dass jedem "Namen" kein Wert zugeordnet ist. Wenn Sie einfach eine "Tasche" mit Objekten benötigen, kann dies eine gute Wahl sein. Anstelle von so etwas:

keyword_1 = 'apple'
keyword_2 = 'banana'

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

Sie werden dies haben:

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

Verwenden Sie a listfür eine Folge ähnlicher Objekte, a setfür einen beliebig geordneten Beutel mit Objekten oder a dictfür einen Beutel mit Namen mit zugehörigen Werten.

TigerhawkT3
quelle
12

Anstelle eines Wörterbuchs können Sie auch namedtupledas Sammlungsmodul verwenden, um den Zugriff zu erleichtern.

Zum Beispiel:

# 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)
ojas mohril
quelle
10

Wenn Sie kein Objekt verwenden möchten, können Sie es dennoch setattr()in Ihrem aktuellen Modul verwenden:

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
Guillaume Lebreton
quelle
Dieser klingt für mich besser als die Verwendung von 'exec'.
Fralau
Dies funktioniert jedoch nicht mit __dict__Variablen. Ich frage mich, ob es einen allgemeinen Mechanismus gibt, um eine globale Variable dynamisch zu erstellen .
Alexey
globals()kann dies tun
Guillaume Lebreton
9

Die SimpleNamespaceKlasse kann verwendet werden, um neue Attribute mit setattroder eine Unterklasse zu SimpleNamespaceerstellen und eine eigene Funktion zum Hinzufügen neuer Attributnamen (Variablen) zu erstellen.

from types import SimpleNamespace

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

Ich beantworte die Frage: Wie erhalte ich den Wert einer Variablen, deren Name in einer Zeichenfolge angegeben ist? Dies wird als Duplikat mit einem Link zu dieser Frage geschlossen.

Wenn die Variablen in Frage Teil eines Objekts (Teil einer Klasse zum Beispiel) sind dann einige nützliche Funktionen genau zu erreichen , die sind hasattr, getattrund setattr.

So können Sie zum Beispiel haben:

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)

Dann können Sie tun:

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

"initial_variable"

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

"ist eigentlich nicht initial"

patapouf_ai
quelle
5

Verwenden globals()

Sie können Variablen tatsächlich dynamisch dem globalen Bereich zuweisen, wenn Sie beispielsweise 10 Variablen möchten, auf die in einem globalen Bereich zugegriffen werden kann i_1, i_2... i_10:

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

Dadurch wird all diesen 10 Variablen ein 'a' zugewiesen. Natürlich können Sie den Wert auch dynamisch ändern. Auf alle diese Variablen kann jetzt wie auf andere global deklarierte Variablen zugegriffen werden:

>>> i_5
'a'
Rocky Li
quelle
4

Sie müssen eine globals()integrierte Methode verwenden , um dieses Verhalten zu erreichen:

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
Andriy Ivaneyko
quelle
3

Der Konsens besteht darin, dafür ein Wörterbuch zu verwenden - siehe die anderen Antworten. Dies ist in den meisten Fällen eine gute Idee, daraus ergeben sich jedoch viele Aspekte:

  • Sie sind selbst für dieses Wörterbuch verantwortlich, einschließlich der Speicherbereinigung (von In-Dict-Variablen) usw.
  • Es gibt entweder keine Lokalität oder Globalität für variable Variablen, dies hängt von der Globalität des Wörterbuchs ab
  • Wenn Sie einen Variablennamen umbenennen möchten, müssen Sie dies manuell tun
  • Sie sind jedoch viel flexibler, z
    • Sie können entscheiden, ob vorhandene Variablen überschrieben werden oder ...
    • ... wählen Sie const Variablen zu implementieren
    • eine Ausnahme beim Überschreiben für verschiedene Typen auslösen
    • usw.

Trotzdem habe ich eine Manager- Klasse für variable Variablen implementiert, die einige der oben genannten Ideen enthält. Es funktioniert für Python 2 und 3.

Sie würden die Klasse folgendermaßen verwenden :

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'])

Wenn Sie nur das Überschreiben von Variablen desselben Typs zulassen möchten:

myVars = VariableVariablesManager(enforceSameTypeOnOverride = True)
myVars['test'] = 25
myVars['test'] = "Cat" # <- raises Exception (different type on overwriting)
DomTomCat
quelle
Auf den ersten Blick ließen mich die langen Kamelimporte denken, dies sei Java.
Markroxor
3

Ich habe beide in Python 3.7.3 ausprobiert. Sie können entweder globals () oder vars () verwenden.

>>> food #Error
>>> milkshake #Error
>>> food="bread"
>>> drink="milkshake"
>>> globals()[food] = "strawberry flavor"
>>> vars()[drink] = "chocolate flavor"
>>> bread
'strawberry flavor'
>>> milkshake
'chocolate flavor'
>>> globals()[drink]
'chocolate flavor'
>>> vars()[food]
'strawberry flavor'


Referenz:
https://www.daniweb.com/programming/software-development/threads/111526/setting-a-string-as-a-variable-name#post548936

Hzzkygcs
quelle
0

Jeder Satz von Variablen kann auch in eine Klasse eingeschlossen werden. "Variablen" -Variablen können zur Laufzeit zur Klasseninstanz hinzugefügt werden, indem über das Attribut __dict__ direkt auf das integrierte Wörterbuch zugegriffen wird.

Der folgende Code definiert die Variables-Klasse, die ihrer Instanz während der Konstruktion Variablen (in diesem Fall Attribute) hinzufügt. Variablennamen stammen aus einer angegebenen Liste (die beispielsweise durch Programmcode generiert worden sein könnte):

# 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
ru13r
quelle