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:IMHO ist es aber besser den Namen als die Zeichenkette zu verwenden weil man dann auf den ersten Blick sieht, dass es sich um eine Konstante handelt und der Interpreter auch an Stellen mit einem `NameError` auf Fipptehler reagiert, wo eine falsch geschriebene Zeichenkette vielleicht "lautlos" durchgeht, aber eben nicht richtig funktioniert.
Was den zweiten Aspekt angeht, so wären die Zeichenketten vorzuziehen, weil man im Traceback einen konkreteren Hinweis bekommt.

Beispiel: Die Konstante tk.NONAME als Wert für die Option "state" eines Entry-Widgets produziert:

Code: Alles auswählen

AttributeError: 'module' object has no attribute 'NONAME'
Die Zeichenkette "noname" hingegen:

Code: Alles auswählen

_tkinter.TclError: bad state "noname": must be disabled, normal, or readonly
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

numerix hat geschrieben:Was deinen Code angeht, so ist die Methode buttonDict überflüssig und auch der Name ist schlecht gewählt, weil es kein Dictionary ist, sondern eine zweidimensionale Liste.
Ja stimmt, sieht auch gleich schöner aus ohne die Methode. :)
BlackJack hat geschrieben:Bei dem Geschwindigkeitsproblem könntest Du mal das "pack"en des `Frame` hinter die Schleife mit den `Button`\s verschieben. Sonst kann es eventuell passieren, dass durch jeden der 625 Knöpfe das Layout neu berchnet und die Anzeige aktualisiert wird.
Hm. Hab's ausprobiert, funktioniert aber alles nicht. Braucht immer ewige einundhalb bis zwei Sekunden bis die Buttons endlich erscheinen.
Also das Fenster ist sofort da. Auch mit Titel und die Größe stimmt auch. Aber die Buttons erscheinen erst noch langen einundhalb Sekunden, dann aber alle auf einmal. :?
Benutzeravatar
numerix
User
Beiträge: 2696
Registriert: Montag 11. Juni 2007, 15:09

Ich habe mal eine Zeitmessung vor und nach MyApp() geschaltet: Bei mir dauert das ca. 0,16 Sekunden, also praktisch keine sichtbare Verzögerung.
Gemessen auf einem 7 Jahre alten Rechner mit Python 2.5 / Tk 8.4 auf einem Linux-System mit KDE .

Edit: Ich glaube, die Zeitmessung sagt nichts aus. Habe es gerade mal unter wine laufen lassen. Da zeigt er mit 0,23 s an, aber der Aufbau der Buttons erfolgt sichtbar von unten nach oben und ist erst fertig, wenn die Ausgabe der Zeit auf der Konsole schon erfolgt ist ...
smashed to pieces
User
Beiträge: 38
Registriert: Samstag 24. November 2007, 16:50

Hm. Liegt anscheinend irgendwie an meinem Computer.
Oder Windows hat eine andere Vorgehensweise ôô.

Find ich komisch. Hab den Code jetzt einfach mal umgestellt:

Code: Alles auswählen

import Tkinter as tk

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



root = tk.Tk()
root.title("Ein paar Buttons")
myapp = MyApp(root)
print 'Hallo'
root.mainloop()
Sollte jetzt nicht erst Hallo erscheinen und sich dann erst das Fenster öffnen :? ?
Naja warscheinlich ein Denkfehler meinersteis ..
numerix hat geschrieben:Edit: Ich glaube, die Zeitmessung sagt nichts aus. Habe es gerade mal unter wine laufen lassen. Da zeigt er mit 0,23 s an, aber der Aufbau der Buttons erfolgt sichtbar von unten nach oben und ist erst fertig, wenn die Ausgabe der Zeit auf der Konsole schon erfolgt ist ...
Bei mir erscheinen die Buttons alle auf einmal.

Und jetzt nach dem obenstehendem Code erscheint zuerst ein Fenster in der gewollten Größe usw.
Dann ist eine Pause von 1-2 Sekunden, inder die Maus das Sympol der bekannten Sanduhr annimmt. Dann erscheinen die Buttons alle auf einmal. Und zuletzt, nachdem das Fenster + Buttons sichtbar ist, erscheint der Text, welcher von der Print-Anweisung ausgeht, in der Editor ansicht.

Ohne die mainloop Anweisung geht der Programmablauf bis zur Ausgabe von Hallo schnell. Also gradezu ohne Verzögerung.



Edit: Ausgabe über print erscheint eh zuerst. Nur beim Programmlauf über den Editor ist die Reinfolge verkehrt herum.
BlackJack

Zeile 10 ist reichlich kompliziert und überflüssig. Die verschachtelte Liste würde ich einfach in der Schleife mit aufbauen.
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 ;)
Antworten