Seite 1 von 2

Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 13:42
von hypnoticum
Hallo,
ich habe eine Schleife in der ich mehrere Instanzen erzeuge. Diesen Instanzen sollen dynamisch attribute zugewiesen werden. Bei dem geschachtelten Aufruf von __dict__[] klappt das nicht mehr.
kann jemand erklären warum, bzw. mir sagen wie ich es machen soll?

Code: Alles auswählen

class ClassTyp(object):
      def __init__(self):
             GroupDict = {'Key_1': 'Val_1', 
                               'Key_2': 'Val_2',
                               'Key_3': 'Val_3'}
             for Test in GroupDict:
                    self.__dict__[Test].__dict__['Var'] = dynVal
...

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 13:50
von EyDu
Hallo.

Beschreibe mal, was du eigentlich machen willst. Was du da vor hast sieht schon sehr seltsam aus.

Sebastian

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 13:55
von BlackJack
@hypnoticum: Von `__dict__` würde ich grundsätzlich erst einmal abraten. Es gibt `getattr()` und `setattr()` um dynamisch Attribute zu lesen und zu binden.

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 14:23
von hypnoticum
Ich will Checkboxen in einer Schleife erzeugen.
Jeder Checkbox wird dabei ein "text" und eine "variable" zugewiesen.
der wert der variablen kommmt aus einem dictionary.
der wert für text kommt aus einem dictionary.
beide dictionaries stimmen in den "keys" für "text" und "variable" überein
beim beenden des dialogs sollen die werte der jeweiligen variablen in dem einen dictionary gespeichert werden.
das geschieht wieder in einer schleife.

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 14:33
von hypnoticum
@BlackJack:
Ich versteh mal wieder nicht wie ich das mit "setattr()" anstellen soll.
Wie erzeuge ich ein Attribut 'Var' vom Typ "Tkinter.IntVal" in dem dynamisch erzeugten Namensraum/Attribut "Test" der Kasse ClassTyp mit setattr()?

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 14:36
von Xynon1
Relativ einfach:

Code: Alles auswählen

for name in checkbutton_names:
    setattr(object, name, tkinter.IntVar())
Die Namen müssen Strings sein. Edit: Achso und "object" sollte natürlich deine Instanz sein, bei deinem Aufruf wird das warscheinlich "self" sein.

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 14:46
von hypnoticum
Schulle, ich meinte "Tkinter.IntVar", nicht "IntVal"
aber was mache ich mit "Test"?

Code: Alles auswählen

setattr(setattr(self, Test, None), 'Var', Tkinter.IntVar())

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 14:49
von Xynon1
Sry, Tippfehler war gerade noch woanders mit meinen Gedanken, macht aber keinen Unterschied. Ich korrigiere es oben.
Oha, hatte das bei dir so gesehen, habe ich ebend selbst nicht mitbekommen :D

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 15:01
von Xynon1
Kannst du mal definieren, was für eine Strucktur bei dir am Ende raus kommen soll? Etwa so was hier ?

Code: Alles auswählen

instance = ClassTyp()
instance.Test.Var1
instance.Test.Var2

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 15:06
von hypnoticum

Code: Alles auswählen

self.Key_1.Var
self.Key_2.Var
self.Key_3.Var
wobei die Attribute "Var" halt vom Typ Tkinter.IntVar" sein sollen. Der Typ von "Key_x" ist egal.

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 15:12
von BlackJack
@hypnoticum: Wenn der Typ egal ist, warum gibt es das Objekt überhaupt? Warum steckst Du das nicht einfach in ein normales Dictionary? Beziehungsweise warum heissen die Attribute von den "egal"-Objekten alle `Var`? Schreibt tatsächlich irgendjemand Quelltext in dem über ``obj.Key_1.Var`` darauf zugegriffen wird?

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 15:28
von hypnoticum
Das Objekt dient der Unterscheidung der Variablen "Var". Es war von mir eigentlich so gedacht, mehrere Namensräume "Key_x" anzulegen, in denen immer wieder die gleichen Attribute mit anderen Werten zu finden sind.
Ich werde es mal mit einem Dictionary probieren.

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 15:40
von Xynon1
Also so was oder wie?

Code: Alles auswählen

self.Key_1.Var_1
self.Key_1.Var_2
self.Key_1.Var_3
self.Key_2.Var_1
self.Key_2.Var_2
self.Key_3.Var_1
self.Key_3.Var_2
....

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 15:46
von hypnoticum
@Xynon1: ja so. Die anderen "Var" könnten dann auch andere Typen sein. Ich werde es wohl nun mit Dictionaries machen. Falls du eine Lösung weisst würde es mich trotzdem sehr interessieren.

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 15:52
von Xynon1
Naja, immer noch setattr, aber bevor du damit rumspielst solltest du dir erstmal eine Datenstrucktur überlegt haben und halt prüfen ob es wirklich so kompliziert sein muss.

Denn ob man wirklich sowas haben will ist fragwürdig.

Code: Alles auswählen

class ClassTyp(object): pass
class Test(object): pass

instance = ClassTyp()
checkbutton_names = ["var_1", "var_2", "var_3"]
test_names = ["key_1", "key_2", "key_3", "key_4"]

for test in test_names:
    test_instance = Test()
    for name in checkbutton_names:
        setattr(test_instance, name, tkinter.IntVar())
    setattr(instance, test, test_instance)

>>> instance.key_1.var_2
<Tkinter.IntVar instance at 0x018584B8>

Re: Anwendung von __dict__[]

Verfasst: Dienstag 12. April 2011, 15:59
von EyDu
Dictionaries sehen bereits nach dem richtigen Weg aus. Aber um meine Frage von oben noch einmal auf Dictionaries anzuwenden: was genau meinst du mit "Namensraum"? Gibt es zu jedem Schlüssel eine vorher bekannte Anzahl an Variablen und ist die Anzahl der Variablen bei allen Schlüsseln gleich? Handelt es sich nur um Daten oder sind es eher Objekte?

Re: Anwendung von __dict__[]

Verfasst: Mittwoch 13. April 2011, 09:07
von hypnoticum
Ich kriegs nicht hin. Die Checkboxen werden einfach nicht gestzt, obwohl die Werte im "TestDict"-Dictionary stehen. Hier mal nur für einen Namen:
(Korrektur: Es funktioniert doch, aber seltsamerweise nur in diesem Minimalbeispiel. Ich werde mal sehen, wo der Fehler ist ...)

Code: Alles auswählen

import Tkinter

TestDict = {'eins': '1', 'zwei': '0'}
class TestClass(object): pass
MasterName = Tkinter.Tk()
       
i = 0
TestInstance = TestClass()
for Test in TestDict:
    setattr(TestInstance, Test, Tkinter.IntVar())
    TestInstance.__dict__[Test].set(int(TestDict[Test]))
    Tkinter.Checkbutton(MasterName, text = Test, variable = TestInstance.__dict__[Test]).grid(sticky = Tkinter.W, row = i, column = 0, columnspan = 1)
    i = i + 1
    
MasterName.mainloop()

Re: Anwendung von __dict__[]

Verfasst: Mittwoch 13. April 2011, 09:24
von Xynon1
Ich habe dein vorheriges Script auch noch gesehen... Was zur Hölle tust du da? Nochmal und das gilt für beide Scripte - Finger weg von .__dict__

Vieleicht wäre es besser mal den Sinn dahinter zu erklären warum du solch eine Strucktur brauchst, dann könnte man vieleicht eine adäquat Lösung finden.

Re: Anwendung von __dict__[]

Verfasst: Mittwoch 13. April 2011, 10:02
von BlackJack
@hypnoticum: Ich würde mich dem anschliessen: Finger weg von `__dict__` und versuch doch mal "pythonischer" zu schreiben. Das mit der Gross-/Kleinschreibung führt zum Beispiel IMHO immer wieder zu Verständnisproblemen -- wenn etwas mit einem Grossbuchstaben beginnt, dann ist das in den Köpfen von Pythonprogrammierern der Name einer Klasse und man muss immer umdenken wenn dem dann nicht so ist. Dann kann man sich auch Zusätze wie `Class` oder `Instance` sparen, denn dann ist klar das `Test` eine Klasse und `test` ein Exemplar ist.

`MasterName` ist irreführend, weil es kein Name ist.

Das manuelle hochzählen von `i` würde man eher durch `enumerate()` ersetzen und wenn Du in der Schleife immer auch den Wert zu einem Schlüssel benötigst, kannst Du auch gleich über die Schlüssel/Wert-Paare iterieren. So sieht das IMHO auch deutlich "aufgeräumter" aus:

Code: Alles auswählen

import Tkinter as tk

name2value = {'eins': '1', 'zwei': '0'}

class Test(object):
    pass

master = tk.Tk()

test = Test()
for i, (name, value) in enumerate(name2value.iteritems()):
    int_var = tk.IntVar()
    int_var.set(int(value))
    setattr(test, name, int_var)
    checkbutton = tk.Checkbutton(master, text=name, variable=int_var)
    checkbutton.grid(sticky=tk.W, row=i, column=0)

master.mainloop()

Re: Anwendung von __dict__[]

Verfasst: Mittwoch 13. April 2011, 10:37
von hypnoticum
OK, vielen Dank für die Hilfe.
Ich werde versuchen mich hinsichtlich meiner Schreibweise zu bessern.
Eine weitere Frage habe ich aber noch. Die gehört dann eher in die Ecke Tkinter-Probleme:

Wenn ich die Variable vom Typ IntVar() in einem Toplevel-Fenster erzeuge, dann muss ich das komischerweise immer als Atttribut des Master-Fensters machen ("self.master.test"), damit die CheckButtons auch gesetzt werden. Eigentlich geht es doch das Master-fenster nichts an, oder?

Code: Alles auswählen

from Tkinter import *

class TestGUI(object):
    def __init__(self):
        self.master = Tk()
        self.init_widgets()
        self.master.mainloop()
        
    def init_widgets (self):
        btn = Button(master = self.master,
              text = 'Configure',
              command = lambda: ConfigDia(self.master))
        btn.pack()

class ConfigDia(object): 
    def __init__(self, Master):
        self.master = Master
        self.top = Toplevel()
        self.init_widgets()
          
    def init_widgets(self):
        class Test(object): 
            pass
        
        testDict = {'eins': '1', 'zwei': '0'}
        self.master.test = Test()
        for i, (name, value) in enumerate(testDict.iteritems()):
            int_var = IntVar()
            int_var.set(int(value))
            setattr(self.master.test, name, int_var)
            checkbutton = Checkbutton(self.top, text=name, variable=int_var)
            checkbutton.grid(sticky=W, row=i, column=0)
            
newTestGUI = TestGUI()