Seite 1 von 1

Problem mit dict.item()

Verfasst: Dienstag 15. Januar 2008, 21:47
von Frank aka Ch3ck3r
Hi ich habe ein Problem bei folgendem dict und der Methode item()

Code: Alles auswählen

        addmenus = {
            "Programm":
                {
                    "&Informationen": [u"Informationen \xfcber das Programm",self.onAbout],
                    "&Beenden": ["Verbindung trennen und das Programm beenden",self.onExit]
                },
            "Verbindung":
                {
                    "&Herstellen": ["Die Verbindung mit dem Server herstellen",self.onConnect],
                    "&Trennen": ["Die Verbindung mit dem Server trennen",self.onDisconnect],
                    "separator": None,
                    u"&Pr\xfcfen": [u"Die Verbindung mit dem Server pr\xfcfen",self.onCheck]
                }
        }
Wenn ich nun

Code: Alles auswählen

for heading,content = addmenus.items():
    print heading
laufen lasse bekomme ich als erstes "Verbindung" ausgegeben, anstatt "Programm". Auch wenn ich das Dict umdrehe bleibt die Ausgabe so.
Ich möchte jedoch erst Programm ausgeben.

Re: Problem mit dict.item()

Verfasst: Dienstag 15. Januar 2008, 22:15
von Trundle
http://docs.python.org/lib/typesmapping.html hat geschrieben:Keys and values are listed in an arbitrary order which is non-random, varies across Python implementations, and depends on the dictionary's history of insertions and deletions.
Die Reihenfolge der Schlüssel und Werte ist mehr oder weniger willkürlich, sie ändert sich lediglich nicht, wenn du das dict nicht veränderst.

Verfasst: Dienstag 15. Januar 2008, 22:22
von Zap
Das die Syntax überhaupt geht :?: ...

Richtig sollte es so sein:

Code: Alles auswählen

for heading,content in addmenus.items():
    print heading
Wie Trundle schon sagte, kannst du bei einem dict nicht davon ausgehen das die Werte in der Reihenfolge rausfallen wie du sie einträgst.

Verfasst: Dienstag 15. Januar 2008, 22:44
von Frank aka Ch3ck3r
das war nur ein kleines beispiel... ich wollte euch nicht diesen kompletten Code schreiben:

Code: Alles auswählen

        addmenus = {
            "Verbindung":
                {
                    "&Herstellen": ["Die Verbindung mit dem Server herstellen",self.onConnect],
                    "&Trennen": ["Die Verbindung mit dem Server trennen",self.onDisconnect],
                    "separator": None,
                    u"&Pr\xfcfen": [u"Die Verbindung mit dem Server pr\xfcfen",self.onCheck]
                },
            "Programm":
                {
                    "&Informationen": [u"Informationen \xfcber das Programm",self.onAbout],
                    "&Beenden": ["Verbindung trennen und das Programm beenden",self.onExit]
                }
        }
        self.menus(addmenus)
        self.Show(1)
        
    def menus(self,menus={}):
        self.menubar = wx.MenuBar()
        for menuname,menuentries in menus.items():
            newmenu = wx.Menu()
            for title,details  in menuentries.items():
                print title
                if title != "separator" and details != None:
                    status = details[0]
                    function = details[1]
                    tobind = newmenu.Append(-1,title,status)
                    self.Bind(wx.EVT_MENU,function,tobind)
                else:
                    newmenu.AppendSeparator()
            self.menubar.Append(newmenu,menuname)
        self.SetMenuBar(self.menubar)
Wie zum Teufel kann ich denn dann bitte die Reihenfolge bestimmen?
Ich kann ja nicht sagen ich lese zuerst "Programm" aus also addmenu["programm"] denn ich weiß ja nicht was dort steht (also hier in dem Beispiel schon, aber das soll ja dynamisch laufen am ende, und der erste eintrag soll zu erst ausgegeben werden.)

Verfasst: Dienstag 15. Januar 2008, 22:52
von Nicht_zu_definieren
Ich würde es ganz einfach mit Tupeln machen:

Code: Alles auswählen

addmenus = (
    ('Programm', (
        ('Herstellen', 'Die Verbindung herstellen', self.onConnect),
        ('Trennen', 'Die Verbindung trennen', self.onDisconnect),
        :
        :
    :
    :
)

Verfasst: Dienstag 15. Januar 2008, 23:01
von Trundle
Frank aka Ch3ck3r hat geschrieben:Wie zum Teufel kann ich denn dann bitte die Reihenfolge bestimmen?
Mit einer Liste oder einem Tupel beispielsweise.

Code: Alles auswählen

addmenus = (
    ('Programm', (
        ('Informationen',
            ('Informationen über das Programm', self.onAbout)),
        ('Beenden',
            ('Verbindung trennen und das Programm beenden', self.onExit))
    )),
    ('Verbindung', (
        ('Herstellen',
            ('....', self.onConnect)),
        ('Trennen',
            ('....', self.onDisconnect))
    ))
)

for menuname, menuentries in addmenus:
    for title, details  in menuentries:
        ...
Edit: zu lahm.

Verfasst: Dienstag 15. Januar 2008, 23:28
von Leonidas
Trundle hat geschrieben:Mit einer Liste oder einem Tupel beispielsweise.
Oder mit einem Ordered Dict. Gibts auch schon mehrfach implementiert.

Verfasst: Mittwoch 16. Januar 2008, 15:02
von Frank aka Ch3ck3r
gefällt mir nicht so wirklich xD aber wenn es nun einmal nicht anders geht, werde ich das mit Tupeln machen.

Danke für eure Hilfe (ich werd mir erstmal die Ordered Dicts anschauen)

Verfasst: Mittwoch 16. Januar 2008, 16:13
von CM
Vielleicht ist dieses Beispiel interessant für Dich:
http://www.python-forum.de/topic-6891.html ?
(Soll keine Eigenwerbung sein ...)

Gruß,
Christian

Verfasst: Mittwoch 16. Januar 2008, 17:43
von birkenfeld
Trundle hat geschrieben:
Frank aka Ch3ck3r hat geschrieben:Wie zum Teufel kann ich denn dann bitte die Reihenfolge bestimmen?
Mit einer Liste oder einem Tupel beispielsweise.
Wo wir schon im anderen Thread bei den Grundkonzepten von Listen und Tupeln sind, wäre das hier "korrekter":

Code: Alles auswählen

addmenus = [
    ('Programm', [
        ('Informationen',
            ('Informationen über das Programm', self.onAbout)),
        ('Beenden',
            ('Verbindung trennen und das Programm beenden', self.onExit))
    ]),
    ('Verbindung', [
        ('Herstellen',
            ('....', self.onConnect)),
        ('Trennen',
            ('....', self.onDisconnect))
    ])
]

Verfasst: Mittwoch 16. Januar 2008, 19:31
von sma
Ich persönlich würde eine DSL erfinden und benutzen, um derartige Menüs zu definieren. Zum Beispiel so:

Code: Alles auswählen

menu_bar(
  menu("Programm",
     item("&Informationen", help_text="Informationen über das Programm", action=self.onAbout),
     item("&Beenden", help_text="...", action=self.onExit),
  ),
  ...
)
Letztlich wird das die selbe Struktur mit Tupel und Listen erzeugen, doch das ist um eine Größenordnung leichter zu lesen und zu verstehen, finde ich.

Es könnte auch interessant sein, folgenden Ansatz mal auszuprobieren:

Code: Alles auswählen

@menu_item("About", in_menu="Programm", help_text="...")
def onAbout():
   ...

@menu_item("Beenden", in_menu="Programm", help_text="...")
def onExit():
   ....
Vorteil wäre, dass man sich so sein Menü relativ dynamisch zusammenbauen kann. Nachteil wäre, dass das Menu relativ dynamisch zusammengebaut ist und z.B. die Reihenfolge der Menüeintrage schwer zu definieren ist.

Da es mir allgemein besser erscheint, ein Command-Pattern zu benutzen und nicht einfach nur Funktionen, wäre eine Kombination beider Ansätze denkbar:

Code: Alles auswählen

class AboutCmd(Command):
  label = "About"
  help_text = "..."
  
  def execute(): ...

class ExitCmd(Command):
  label = "Beenden"

  def execute(): ...

menu_bar(
  menu("Programm", AboutCmd, ExitCmd, ...),
)
Das würde (mit weniger Aufwand) dem Weg entsprechen, wie man das z.B. in der Eclipse-Plattform sieht. Es gibt dann verschiedene Arten von Kommandos: Welche, die man rückgängig machen (UndoableCommand) kann und welche, die die Undo-Liste löschen usw. Kommandos kann man dann sowohl in der zentralen Menüleiste, also auch in Form von Schaltflächen in der Funktionsleiste als auch als einzelne Schaltflächen vorfinden. Kommando-Exemplare könnten zudem wissen, ob sie gerade erlaubt sind (enablement state), dann können diese aber wiederum keinen Zustand für das Undo speichern, weil jetzt Kommando-Exemplare und nicht mehr Kommando-Klassen über die Menüleiste referenziert werden.

Egal, was ich sagen wollte ist: Nimm nicht einfach nur Listen, mach es lesbar und abstrahiere dabei. Nutze die Möglichkeiten der Metaprogrammierung.

Stefan

Verfasst: Mittwoch 16. Januar 2008, 19:41
von lunar
sma hat geschrieben:Das würde (mit weniger Aufwand) dem Weg entsprechen, wie man das z.B. in der Eclipse-Plattform sieht. Es gibt dann verschiedene Arten von Kommandos: Welche, die man rückgängig machen (UndoableCommand) kann und welche, die die Undo-Liste löschen usw. Kommandos kann man dann sowohl in der zentralen Menüleiste, also auch in Form von Schaltflächen in der Funktionsleiste als auch als einzelne Schaltflächen vorfinden. Kommando-Exemplare könnten zudem wissen, ob sie gerade erlaubt sind (enablement state), dann können diese aber wiederum keinen Zustand für das Undo speichern, weil jetzt Kommando-Exemplare und nicht mehr Kommando-Klassen über die Menüleiste referenziert werden.
Ein halbwegs modernes GUI-Toolkit sollte solche Klassen eigentlich mitbringen. Qt4 hat QAction, Swing hat Action, aber wx offenbar nicht, oder?