string zu no string konvertieren ?

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

BlackJack hat geschrieben:Zeile 10 ist reichlich kompliziert und überflüssig. Die verschachtelte Liste würde ich einfach in der Schleife mit aufbauen.
Oder einfacher initialisieren (siehe unten Zeile 10)
Aber das verursacht sicher die Verzögerung nicht ...

Da ich die Verzögerung beim Programmstart nicht reproduzieren kann, mal zwei Vorschläge ins Blaue hinein:

Zum einen könntest du versuchen festzustellen, an welcher Stelle das Problem liegt, indem du ein paar Zeitmessungen einschiebst. Dann könnte z.B. so aussehen:

Code: Alles auswählen

import time, platform
import Tkinter as tk

timer = time.time if platform.system() == "Linux" else time.clock

class MyApp(object):
    def __init__(self, myParent):
        t0 = timer()
        self.myParent = myParent
        self.buttonlist = [[None]*25 for k in xrange(25)]
        print timer()-t0
        for i in xrange(25):
            for o in xrange(25):
                self.buttonlist[i][o] = tk.Button(self.myParent, width=2, height=1)
        print timer()-t0
        for i in xrange(25):
            for o in xrange(25):
                self.buttonlist[i][o].grid(row=i, column=o)
        print timer()-t0

root = tk.Tk()
myapp = MyApp(root)
root.mainloop()
Möglicherweise hilft das aber auch nicht, weil die Konsolenausgaben erscheinen, bevor die GUI steht.

Zweite Idee: Vielleicht liegt es am grid-Manager, obwohl das mal ein Aufbau ist, wo grid besser passt als pack. Versuch es doch mal mittels pack(), ob das irgendeinen Unterschied macht:

Code: Alles auswählen

import Tkinter as tk

root = tk.Tk()
for y in xrange(25):
    row = tk.Frame(root)
    for x in xrange(25):
        tk.Button(row, width=2, height=1).pack(side="left")
    row.pack()
root.mainloop()
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

Gute Idee die Zeit zu messen.

Hab deinen Code in den Editor reinkopiert und laufenlassen:

3.77142905034e-005
0.0742387649827
0.0935973706155

Also diese Zeiten kann man nicht merken.
Außerdem sieht man, nachdem sie Zeiten schon dastehen, wie sich das Fenster mit den Buttons erst erzeugt.
(Jetzt, da die Buttons direkt in das Fenster kommen und nicht in ein extra Frame, erscheinen die Buttons nacheinander.)


Der Tipp mit dem pack() war allerdings besser.
Das Fenster erscheint mit Buttons fast ohne Verzögerung :) . Danke.

Versteh ich allerdings nicht warum mit grid() ein Verzögung von 2 Sekunden entsteht !?
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

BlackJack hat geschrieben:Zeile 10 ist reichlich kompliziert und überflüssig. Die verschachtelte Liste würde ich einfach in der Schleife mit aufbauen.
War das in etwa so gemeint?

Code: Alles auswählen

import Tkinter as tk

class MyApp(object):
    def __init__(self, myParent):
        self.myParent = myParent
        self.buttonlist = []
        for i in xrange(25):
            self.buttonlist.append([])
            self.row = tk.Frame(self.myParent)
            self.row.pack()
            for o in xrange(25):
                self.buttonlist[i].append('button%d'%((i*25)+o))
                self.buttonlist[i][o] = tk.Button(self.row, width=2, height=1)
                self.buttonlist[i][o].pack(side='left')

root = tk.Tk()
myapp = MyApp(root)
root.mainloop()
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

smashed to pieces hat geschrieben:
BlackJack hat geschrieben:Zeile 10 ist reichlich kompliziert und überflüssig. Die verschachtelte Liste würde ich einfach in der Schleife mit aufbauen.
War das in etwa so gemeint? Bzw. kann man das so machen?

Code: Alles auswählen

import Tkinter as tk

class MyApp(object):
    def __init__(self):
        self.root = tk.Tk()
        self.root['bg'] = '#2ff2ff2ff'
        self.root.geometry("%dx%d+%d+%d" % (750, 750, 250, 50))
        self.root.title("Ein paar Knoepfe")

        self.container1 = tk.Frame(self.root)
        self.container1.pack(expand='yes')
        
        self.buttonlist = []
        
        for i in xrange(25):
            self.buttonlist.append([])
            self.row = tk.Frame(self.container1)
            self.row.pack()
            for o in xrange(25):
                self.buttonlist[i].append('button%d'%((i*25)+o))
                self.buttonlist[i][o] = tk.Button(self.row, width=2, height=1)
                self.buttonlist[i][o].pack(side='left',padx=1, pady=1)
        self.root.mainloop()


myapp = MyApp()
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

So ähnlich auf jeden Fall. Die Zeilen 20-22 würde man eher so schreiben:

Code: Alles auswählen

button = tk.Button(self.row, width=2, height=1)
button.pack(side='left') 
self.buttonlist[i].append(button)
oder auch kürzer (aber weniger schön):

Code: Alles auswählen

self.buttonlist[i].append(tk.Button(self.row, width=2, height=1))
self.buttonlist[i][-1].pack(side='left')
Im übrigen würde für row auch eine lokale Variable genügen; am Ende ist in self.row ohnehin nur die zuletzt erzeugte Reihe mit Knöpfen.

Mir persönlich gefällt es so besser, dass "root" ein Attribut von myapp ist.
Die Bezeichnung container1 finde ich nicht so gelungen, weil es nichts Inhaltliches aussagt (außer, dass es ein Container ist und zwar der erste).
BlackJack

Ich bin kein Fan von unnötigen Zählvariablen und Indexzugriffen. Ungetestet:

Code: Alles auswählen

        self.buttons = list()
        for dummy in xrange(25):
            row_frame = tk.Frame(self.container1)
            row_frame.pack()
            row_buttons = list()
            for dummy in xrange(25):
                button = tk.Button(row_frame, width=2, height=1)
                button.pack(side=tk.LEFT, padx=1, pady=1)
                row_buttons.append(button)
            self.buttons.append(row_buttons)
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Nachtrag:

Gegenüber der Schreibweise:

Code: Alles auswählen

self.root['bg'] = '#2ff2ff2ff'
hat sich die Variante:

Code: Alles auswählen

self.root.config(bg='#2f2f2f')
weitgehend durchgesetzt. Die Dictionary-Variante ist noch ein Überbleibsel aus der Zeit, als Python keine Schlüsselwortparameter kannte (vor Python 1.3, glaube ich), funktioniert aber nach wie vor.
Vorteilhaft ist die Verwendung von config() vor allem dann, wenn man mehrere Optionen festzulegen hat, weil das dann alles mit einem Aufruf geht.

Und noch eine Anmerkung zur Datenstruktur:
Zu überlegen wäre, ob es für die Buttons wirklich eine zweidimensionale, d.h. geschachtelte Liste sein muss. Bei deinem ersten Weg mittels grid() bot sich das an, aber es muss ja nicht unbedingt sein. Ich persönlich würde wahrscheinlich eine schlichte eindimensionale Liste vorziehen, weil sich damit einfacher operieren lässt. Wenn du tatsächlich dann gezielt über Koordinaten auf einen Button zugreifen musst, kannst du seine Spalten- und Zeilenposition einfach mittels divmod() aus der Listenposition ermitteln.

Der entsprechende Teil sähe dann so aus:

Code: Alles auswählen

self.buttonlist = []
for i in xrange(25):
    row = tk.Frame(self.container1)
    row.pack()
    for o in xrange(25):
        button = tk.Button(row, width=2, height=1)
        button.pack(side="left")
        self.buttonlist.append(button)
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

Hab jetzt mal mein Ursprüngliches Programm auf pack() umgestellt.
Code : http://paste.pocoo.org/show/91342/

Habe jetzt allerdings gleich mehrere Probleme mit Klassen. Ich versteh das Zusammenspiel von zwei Klasse einfach überhaupt nicht :( .
Bei der Programmausführung wird als erst die Klasse Cube und dann die Klasse Root durchgegangen oder?

Code: Alles auswählen

if __name__ == "__main__":
    cube = Cube()
    root = Root()
    cube.cubeDict()
Das erste Ärgerniss ist das cube.cubeDict() nicht funktioniert.
Fehlermeldung: TypeError: 'dict' object is not callable
Der Aufruf cube.cubeDict führt allerdings zum gewünschtem Ergebniss.

Dabei sollte es doch das selbe Bewirken: (Zeile:22)

Code: Alles auswählen

def cubeDict(self):
        return self.cubeDict
Zweitens benutze ich in Zeile 187 cube.main() (main() nur da cube.cubeDict() nicht funktioniert und cube.cubeDict zu ungewollten Plazierungen der Felder führt) in der Root Klasse, obwohl ich es außerhalb der Klasse definiert habe. Weiß nicht wie man einen solchen Zugriff normalerweise durchführt, so nehm ich mal an nicht.

Hab auch versucht in der Klasse Root self.cube = Cube() zu definieren. Das erschien mir aber gleich ziemlich falsch.


Wisst ihr vielleicht ein tutorial, welches OOP genauer/besser erklärt? bzw. auch meine Frage beantworten könnte.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

smashed to pieces hat geschrieben:Dabei sollte es doch das selbe Bewirken: (Zeile:22)

Code: Alles auswählen

def cubeDict(self):
        return self.cubeDict
Das gibt effektiv sich selbst zurück, wozu soll das gut sein?
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Wisst ihr vielleicht ein tutorial, welches OOP genauer/besser erklärt? bzw. auch meine Frage beantworten könnte.
Kommt drauf an, was du mit genauer / besser meinst.

Die Grundlagen von OOP? Oder mehr fortgeschrittene Dinge? Hast du keine Probleme mit OOP selbst sondern nur mit der Anwendung?

Für die Grundlagen gibt es eigentlich genug, auch, wenn viel schlechtes ebenso zu finden ist.

Die Grundlagen hab ich persönlich mir mittels diesem Forum und dem hier zu findendem Code + den Ratschlägen + dem OOP Tutorial von "A byte of Python" sowie einem mittelmässigem Java Einsteiger Heftchen.

Für breitere Sichtweisen hilft oft die Beschäftigung mit verschiedenen Arten von Sprachen und die Umsetzung dort.

Ansonsten: Design Patterns anschauen. Das Buch von der "Gang of Four" ist ganz gut. Der Rest ist Übung.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

str1442 hat geschrieben:Ansonsten: Design Patterns anschauen. Das Buch von der "Gang of Four" ist ganz gut. Der Rest ist Übung.
Das Buch ist gefährlich. Viele Patterns sind einfach so schon in Python möglich, ohne da irgednwas spezielles implementieren zu müssen. Andere Patterns könnte man in Python flexibler lösen. Also mit Vorsicht zu genießen. Natürlich hat das Buch selbst auch seinen Nutzen, nur sollte man das was drinsteht nicht einfach so übernehmen.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

Leonidas hat geschrieben:
smashed to pieces hat geschrieben:Dabei sollte es doch das selbe Bewirken: (Zeile:22)

Code: Alles auswählen

def cubeDict(self):
        return self.cubeDict
Das gibt effektiv sich selbst zurück, wozu soll das gut sein?
Hab gehört das macht man so :D.
Zum Beispiel, wenn ich self.cubeDict mal Privat warden lasse --> self.__cubeDict, bräuchte ich die Methode ja tatsächlich.
Und das wäre wiederum Sinnvoll, da die cubeDict ja nur über die rotating-Methode der Klasse Cube veränderbar sein soll.
str1442 hat geschrieben:Die Grundlagen von OOP? Oder mehr fortgeschrittene Dinge? Hast du keine Probleme mit OOP selbst sondern nur mit der Anwendung?
Naja so ein Mittelding. Die Grundlagen hab ich schon so ca. verstanden. Also hab mir auch schon 2 tutorials zu dem Thema durchgelesen, aber die schreiben meist nur das, was man schon mal gelesen hat, also alle das Gleiche.
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

smashed to pieces hat geschrieben:Hab gehört das macht man so :D.
In Python eher nicht. Am Anfang hatte ich - von Java herkommend - auch meine Schwierigkeiten, den ganzen getter/setter-Salat abzustellen. Aber wenn man sich einmal dran gewöhnt hat, dass es auch anders gut geht, möchte man nicht mehr zurück ... :)

Per Konvention gilt: Bezeichner, die mit einem Unterstrich beginnen, gelten als privat. Da lässt man einfach die Finger von.

Doppelter Unterstrich wird zwar gelegentlich auch als "Privatisierungsverfahren" verkauft (habe ich anfangs auch gedacht und ärgere mich heute über selbstgeschriebenen Code, in dem es vor doppelten Unterstrichen nur so wimmelt), dient aber im Grunde nur dazu, Namensraumprobleme zu vermeiden. Praktisch heißt das, dass man so gut wie immer ohne doppelten Unterstrich auskommt.

Edit: Und wenn man doch mal aus bestimmten Gründen getter/setter braucht, dann gibt es die Möglichkeit via property() das quasi zu verstecken, so dass es nach außen hin weiterhin wie ein Direktzugriff auf ein Datenattribut aussieht. Das ist eine elegante Sache.
BlackJack

@smashed to pieces: Das Problem ist, dass Du eine Methode mit dem Namen `cubeDict` hast, dann aber ein Dictionary unter dem gleichen Namen an das Objekt bindest. Und wie die Fehlermeldung ja so treffend sagt, versuchst Du dann das Dictionary aufzurufen, aber Dictionaries sind nicht aufrufbar.

Der Quelltext enthält immer noch zu viele magische Zahlen und Copy'n'Paste-Code.

Ich würde erst einmal die GUI aussen vor lassen und den Würfel mit seinen ganzen Methoden implementieren, mit einer einfachen `__str__()`-Methode um die Wirkung der Methoden zu überprüfen. Und das würde ich auch machen: Testcode schreiben, der überprüft, ob alles so wie gewünscht funktioniert.

Und der Code unter der ``if __name__``-Abfrage sollte noch in einer `main()`-Funktion verschwinden. Dann sieht man auch gleich, das Exemplare von `Root` auf ein "globales" `cube`-Objekt zugreifen, was so nicht sein sollte.
Benutzeravatar
str1442
User
Beiträge: 520
Registriert: Samstag 31. Mai 2008, 21:13

Das Buch ist gefährlich. Viele Patterns sind einfach so schon in Python möglich, ohne da irgednwas spezielles implementieren zu müssen. Andere Patterns könnte man in Python flexibler lösen. Also mit Vorsicht zu genießen. Natürlich hat das Buch selbst auch seinen Nutzen, nur sollte man das was drinsteht nicht einfach so übernehmen.
Also mir fiele nur das Decorator Pattern ein, das direkt in Python möglich wäre, auch, wenn Klassen Dekoratoren erst ab 2.6 möglich sind.

Ansonsten ist das Buch ja auf C++ (und Smalltalk, zumindest wird Smalltalk oft erwähnt - soll ja Python doch ähnlicher sein als manch anderes) ausgerichtet. Einige / viele Dinge sind auch etwas umständlich gelöst, allein schon wegen der Statik von C++. Insofern kann man viele Dinge in Python sicher einfacher implementieren, ja.

Die Patterns an sich sind aber auf jedem Fall hilfreich, zumal man allein schon durch die dort angegebenen Beispiele und die Darlegung der Patterns mit der Anwendung von OOP vertrauter wird.

Auf Teufel und Nochwas alles genau so anwenden zu wollen hat eigentlich noch nie funktioniert, nirgends ;)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

str1442 hat geschrieben:Also mir fiele nur das Decorator Pattern ein, das direkt in Python möglich wäre, auch, wenn Klassen Dekoratoren erst ab 2.6 möglich sind.
Spontan fällt mir das Factory Pattern ein und das Visitor Pattern würde man so in Python auch nicht machen. Aber ich habe das Buch gerade nicht da, also kann jetzt nicht reinschauen und sagen was man da noch anders machen würde.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

BlackJack hat geschrieben:Und der Code unter der ``if __name__``-Abfrage sollte noch in einer `main()`-Funktion verschwinden. Dann sieht man auch gleich, das Exemplare von `Root` auf ein "globales" `cube`-Objekt zugreifen, was so nicht sein sollte.
Würde es die Lage verbessern, wenn ich es zum Beispiel so machem würde?:

Code: Alles auswählen

class Root(object):
    def __init__(self, Wuerfel):
        self.Wuerfel = Wuerfel

                

def main():
    if __name__ == "__main__":
        Wuerfel = Cube()
        Fenster = Root(Wuerfel)

main()

Hab gerade auch meinen Fehler im richtigem Code gefunden.
Bei der definition von einem Button wird bei mir das command sofort ausgeführt.

Code: Alles auswählen

        for side in ('back', 'bottom', 'front', 'left', 'right', 'top'):
            self.rotationButtonDict[side] = 'Button'
            self.rotationButtonDict[side] = tk.Button(self.container5, text=(str(side)+'.'), width=16,
                                                      command=wuerfel.rotating(side)) 
            self.rotationButtonDict[side].pack(side='left', padx=2, pady=6)
Deswegen ist der Cube immer schon verdreht, ich die Felder abgebildet werden.
Ich habe Recht, wenn ich annehme, dass rotationButtonDict kein geeigneter name ist?

Ist mir neu, dass bei der Definition von Buttons die command-Anweisung ausgeführt wird. Gehört sich das so?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

smashed to pieces hat geschrieben:Ist mir neu, dass bei der Definition von Buttons die command-Anweisung ausgeführt wird. Gehört sich das so?
Das liegt an dir. Wenn du nicht willst, dass der Command-Handler ausgeführt wird (was man eben meistens nicht will), dann darfst du ihn nicht AUFRUFEN sondern musst den Handler als Objekt übergeben. Oder in Kurzform: Die Klammern müssen weg.
BlackJack

@smashed to pieces: Üblicherweise ruft man die `main()` innerhalb der ``if``-Abfrage auf Modulebene auf, aber so geht's natürlich auch.

Und das die Methoden aufgerufen werden "gehört sich so" denn schliesslich rufst *Du* sie ja auch auf. Und zwar bevor der Button überhaupt erstellt wird.

Code: Alles auswählen

b = X(z=f(42))
ist ja nichts anderes als:

Code: Alles auswählen

tmp = f(42)
b = X(z=tmp)
Wenn Du die Argumente festlegen, aber die Funktion noch nicht aufrufen willst, kannst Du ``lambda`` verwenden, oder `functools.partial()`.
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

oh. :oops:

Ok, da ich wuerfel.rotating(side) natürlich mit dem Parameter side aufrufen will. Muss ich das Ganze anders lösen.
BlackJack hat geschrieben:Wenn Du die Argumente festlegen, aber die Funktion noch nicht aufrufen willst, kannst Du ``lambda`` verwenden, oder `functools.partial()`.
War das so gemeint?
Das funktioniert zwar. Sieht aber meiner Meinung noch nicht alzu schön aus:

Code: Alles auswählen

for side in ('back', 'bottom', 'front', 'left', 'right', 'top'):
    self.rotationButtonDict[side] = 'Button'
    self.rotationButtonDict[side] = tk.Button(self.container5, text=(str(side)+'.'), width=16,
                                              command=lambda side=side: self.Wuerfel.rotating(side))
    self.rotationButtonDict[side].pack(side='left', padx=2, pady=6)
Aber Danke :)
Antworten