'command' zwei Argumente übergeben?

Fragen zu Tkinter.
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: hier noch ein schöner Beitrag was Deine Probleme noch vergrößern könnte. Python ist einfach nicht dafür gemacht, unendlich viele Module zu laden. Ich würde vorschlagen, wenn Du bei halbunendlich vielen Modulen angekommen bist, können wir gemeinsam eine Lösung suchen, bis dahin solltest Du Dich wie jeder andere Python-Benutzer nicht explizit um Speicherverwaltung kümmern, das macht Python für Dich sehr gut.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jens Mach Dich nur lustig. Die 600.000 bezogen sich auf ein Programm von der Größe 100 Byte. Es soll aber auch Programme mit 100 kByte geben. Vielleicht schon mal etwas von so großen Programmen gehört oder übersteigt das Dein Vorstellugsvermögen?
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Du merkst irgendwie nicht, das du in der Premature optimization is the root of all evil Endlosschleife bist, oder?!?

Wie oft willst du noch hören, das es realitätsfern ist?

Mach erstmal. Wenn du wirklich Speicherprobleme bekommst, kannst du drüber nachdenken...

Du denkt aber in einer Endlosschleife über fiktive Probleme nach...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Sirius3 hat geschrieben:@Alfons Mittelmeyer: hier noch ein schöner Beitrag was Deine Probleme noch vergrößern könnte. Python ist einfach nicht dafür gemacht, unendlich viele Module zu laden. Ich würde vorschlagen, wenn Du bei halbunendlich vielen Modulen angekommen bist, können wir gemeinsam eine Lösung suchen, bis dahin solltest Du Dich wie jeder andere Python-Benutzer nicht explizit um Speicherverwaltung kümmern, das macht Python für Dich sehr gut.
Es geht nicht um unendlich viele Module sondern um ein paar hundert. Und was dort geschieht ist im Prinzip nichts anderes wie viele Print Anweisungen auszugeben - nur dass es GUI Anweisungen sind, wie Button oder command=. Wenn man einfach eine Menge Printanweisungen macht, ist das kein Problem. Wenn man allerdings eine Menge Print Anweisungen in Funktionen packt, dann bleiben die Funktionen solange im Speicher, bis man sie löscht. Wenn man eine Menge Print Anweisungen in eine Funktion gepackt hat, und die aufgerufen hat, dann kann man sie auch wieder löschen.

Wenn Ihr nicht mit del einverstanden seid, bleib ich eben bei meinem Code und mach gar keine Funktion. Eine Lösung gäbe es auch, dass man dann zur Laufzeit nicht compiliert: man macht eine Liste aus lamda Anweisungen und macht sich dann auch noch eine GOTO Anweisung für bedingten und unbedingten Sprung und damit gehen sogar Schleifen.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

jens hat geschrieben:Du denkt aber in einer Endlosschleife über fiktive Probleme nach...

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Sirius3
User
Beiträge: 17741
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: eine normale Funktion hat einige 100 Bytes. Normale Module einige KBytes. Alle von mir in den letzten Jahren geschriebenen Pythonprogramm brauche nicht mehr als 20MB. Alle bei mir installierten Module haben zusammen gerade einmal 100MB.
Wenn Du also so produktiv bist wie 1000 Programmierer, dann hast Du in 10 Jahren genug Python-Code geschrieben, dass heutige Rechner langsam anfangen zu merken, dass Code einen bedeutsamen Anteil an Speicher verbrauchen. Und dann mußt Du noch alles, was Du in den 10000 Programmierjahren geschrieben hast, auf einmal laden.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jens Es geht nicht um fiktive sondern um reale Probleme. Bei DynTkInter ist eine Funktion nutzlos. Da kann ich mit dem GuiCreator folgendermaßen importieren:

Es wird das Programm ausgeführt bis zu folgender Markierung: ### CODE
Das danach wird dann geladen bis zur Markierung: ###

Jetzt gibt es zwei Möglichkeiten, nämlich dass dieser CODE Teil nach dem Reinladen nicht ausgeführt wird, weil man nur die GUI editieren will und die dazu im Anfangszustand lassen will.
Der CODE Teil könnte ja so etwas wie grid.remove() tun. Und man möchte nicht mit keinem Layout abspeichern.

Man kann auch mit Codeteil ausführen laden. Man kann auch den Codeteil ändern und ausführen. Wenn das allerdings eine Funktion wäre, könnte man wahrscheinlich nicht nur bis zur Mitte kompilieren und ausführen. Und wenn das eine Funktion wäre, dann wären Variablen lokal und ein davon getrennter Code Teil im Edit Modus könnte damit nichts anfangen.

Also ganz normal ausgeführt, würde das Programm funktionieren. Aber im Edit Modus könnte man dann den Code während des Editierens nicht testen. Man könnte natürlich auf dieses Feature verzichten, sodass man zwar während des GUI Editierens auch den Code verändern, aber ihn nicht laufen lassen kann.

Also geht es auch um das reale Problem, Verzicht auf das Feature partiellen Code, der zu einem Frame gehört während des GUI Editierens nicht nur zu verändern, was kein Probledm ist, sondern auch zu testen.

Es gibt also noch viele Probleme, die bei einer Umstellung zu bedenken sind. Dass ich function für Funktionen benütze, ist eine gute Idee. Aber die Gesamtfunktion ergäbe manche Probleme und dazu würde dann auch eine Beschränkung der Modulgröße von 64kb gehören.

Nee falsch, bei DynTkInter könnte ich das Feature weiterhin anbieten, weil dort die Widgets namentlich angesprochen werden können und ich deshalb im Gui Teil (also die Widget Definition) gar keine Variablen brauche. Nur für normales tkinter kann ich dann dieses Feature nicht anbieten. Naja macht ja nichts.
Zuletzt geändert von Alfons Mittelmeyer am Dienstag 11. August 2015, 10:48, insgesamt 3-mal geändert.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Alfons Mittelmeyer hat geschrieben:@jens Es geht nicht um fiktive sondern um reale Probleme. Bei DynTkInter ist eine Funktion nutzlos. Da kann ich mit dem GuiCreator folgendermaßen importieren:
Real? Wo kann ich deine sourcen downloaden und ausprobieren und sehen, das der Speicher voll läuft?

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jens Habe gestern crash.py und nocrash.py hier hereingestellt. Kannnst sie allerdings auch mit Ausgabe erst nach 1000 Funktionen haben. Vielleicht ist es dann ein wenig schneller. Oder Du hängst nicht nur 100 Bytes rein in die Funktionen sondern etwas Realistisches wie 50 kB.

Hier crash.py:

Code: Alles auswählen

counter = 0
while True:

	a = "function"+str(counter)+": This isn't much, normally it should be a GUI"

	b = """def function"""+str(counter)+"""():
	if counter%1000 == 0:
		print("""+'"'+a+'"'+""")
function"""+str(counter)+"""()
"""

	eval(compile(b,'<string>', 'exec'))
	
	counter += 1
Hier nocrash.py:

Code: Alles auswählen

counter = 0
while True:

	a = "function"+str(counter)+": This isn't much, normally it should be a GUI"

	b = """def function"""+str(counter)+"""():
	if counter%1000 == 0:
		print("""+'"'+a+'"'+""")
function"""+str(counter)+"""()
del function"""+str(counter)+"""
"""

	eval(compile(b,'<string>', 'exec'))
	
	counter += 1
Mit crash.py hatte ich den Crash nach ein paar Minuten. nocrash.py mit del nach Funktionsaufruf lief die ganze Nacht und es erfolgte kein Crash.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Alfons Mittelmeyer hat geschrieben:@jens Habe gestern crash.py und nocrash.py hier hereingestellt.
Konstruierter Test != Reelles Problem

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
BlackJack

@Alfons Mittelmeyer: Die Regel dynamisch belegten Speicher wieder freizugeben wenn man ihn nicht mehr braucht, gilt für Sprachen/Laufzeitumgebungen wo man sich als Programmierer manuell um die Speicherverwaltung kümmern muss. Bei Sprachen/Laufzeitumgebungen mit automatischer Speicherbereinigung gilt die selbstverständlich nicht mehr, denn genau dafür hat und *will* man ja auch automatische Speicherbereinigung, damit man sich eben nicht mehr selbst darum kümmern muss. Und schon gar nicht um eingebildete Probleme zu lösen.

Selbst bei Sprachen/Laufzeitumgebungen mit manueller Speicherverwaltung und dem Szenario mit den lang laufenden Prozessen, also zum Beispiel Server, aber auch Webbrowser, ist man von diesem „micromanaging“ weg was Du hier propagierst. Denn das ist mühselig für den Programmierer und damit fehleranfällig, denn irgendwo vergisst man dann doch etwas und die 24/7-Anwendung leckt Speicher. Darum verwendet man „memory pools“ über die man Speicher anfordern und freigeben kann, wo man aber auch am Ende eines grösseren Arbeitsschrittes auch auf einen Schlag den gesamten Speicher freigeben kann, welcher über einen Pool vorher angefordert wurde. So spart man sich viele kleine Freigaben, und verringert die Gefahr etwas zu vergessen. Die Apache Portable Runtime Bibliothek hat solche Funktionen und die Netscape Portable Runtime (NSPR), jetzt von Mozilla weitergeführt, ebenfalls, um mal jeweils ein Beispiel aus dem Server- und eins aus dem Anwendungsbereich zu nennen.

Zu dem Python-Programm das im gleichen Prozess andere Python-Programme ausführt: Da würde man mitverfolgen welche Module das Programm lädt, und *die* dann hinterher mit generischem Code wieder freigeben, und nicht Code pro Modul oder gar pro Funktion in die Programme schreiben. Das ist viel zu umständlich. (Wobei das in CPython laut SO-Beitrag von weiter oben ja sowieso nicht möglich zu sein scheint.)

Und noch einmal: Die GUI-Aufbau-Funktion kann man versuchen gleich nach der Ausführung freizugeben. Aber das löst *kein Problem*. Also warum sollte man so etwas unsinniges tun? (Ich glaube die Frage hatte ich schon mal gestellt… ;-))

Wie sieht denn der Quelltext einer realistischen 50 KiB-Funktion (Bytecode!) aus? Ich glaube so etwas habe ich auch noch nicht gesehen. Bitte kein eigenes Beispiel schreiben, sondern etwas von echten Python-Programmierern aus einer realen Anwendung bitte. Und da das ja realistisch sein soll, lassen sich sicher problemlos drei Anwendungen finden an denen man das zeigen kann, oder? ;-)
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Jens: Hm... Du versuchst eine Endlosschleife mit einer Endlosschleife zu beenden :mrgreen: Coole Idee, aber leider nicht effektiv wie es aussieht :twisted:

@Alfons Mittelmeyer: Ich möchte Dir einen einfachen Denkanstoß auf den Weg geben: Wenn man offenkundig in einer Domäne gegen den Strom schwimmt, dann ist man entweder ein Genie oder ein Dummkopf. Genies und Paradigmenwechsel begründende Leute sind eher selten, jedenfalls viel seltener als das Gegenteil. Man sollte sich immer selber fragen, ob man denn wirklich ein Genie ist oder nicht. Wenn nicht, dann sollte man auf die "best practises" und anerkannten Konzepte und Idiome zurückgreifen und nicht versuchen, selber welche zu erfinden...

Du hast jetzt so viel substanziell relevantes und belegtes gehört, was gegen Deinen Ansatz spricht, dass Du Dich ernsthaft fragen solltest, ob Dein Weg wirklich so eine gute Idee ist, oder Du nicht ohne Not gegen den Strom schwimmst... ;-)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack Jetzt höre mal langsam damit auf, einen Krampf zu erzählen, was die Speicherverwaltung automatisch macht und worum sich dann der Programmierer nicht zu kümmern braucht. Denn das macht keine Speicherverwaltung:

Mal nachsehen, wieviel Funktionen BlackJack definiert hat. Ui sind ja eine ganze Menge. Ob er die alle brauchen wird? Die Funktion, glaub ich nicht, dass er die später nochmal aufrufen wird: Die lösch ich einfach mal raus. Und wenn er sie dann später doch noch aufruft? Ja, dann hat er eben Pech gehabt.

Also keine Speicherverwaltung der Welt löscht Dir automatisch Deine Funktionen raus.
BlackJack

@Alfons Mittelmeyer: Natürlich macht das die Speicherverwaltung nicht, denn das braucht ja auch kein Mensch. Wenn das sinnvoll wäre, dann würde sich die Speichervewaltung um so etwas kümmern, oder es würde eine andere Lösung für das Problem geben, oder die Leute würden Funktionen *versuchen* mit ``del`` aus dem Speicher zu bekommen. Da das alles nicht der Fall ist, solltest Du vielleicht *nochmal* darüber nachdenken was für einen Unsinn Du hier propagierst.

Ich habe für den zuerst postulierten Modulfall übrigens immer noch keinen Beweis gesehen. Ich könnte mir beispielsweise auch vorstellen, dass der Bytecode eines Moduls en Block im Speicher liegt und Funktionsobjekte auf den Bytecode der Funktion innerhalb des Blocks verweisen, man also nur den gesamten Block als ganzes freigeben kann, was dann nur passieren würde/könnte wenn *alle* Funktionen und Methoden aus dem Modul gelöscht sind, *und* das Modulobjekt selbst. Da niemand (ausser Dir) einzelne Funktionen aus einem Modul löschen will, würde diese vorgehensweise Sinn machen weil ein Speicherblock pro Modul weniger Platz und Aufwand bedeuten würde. Der Bytecode kommt schon als Block aus der *.pyc-Datei oder aus dem Compiler, und den dann nochmal in kleinen Häppchen zu Funktionen umzukopieren, macht erst einmal keinen Sinn. Wie gesagt das wäre mehr Aufwand und weniger kompakt in der Speicherbelegung. (Und Speicher sparen scheint ja auch Dir ganz wichtig zu sein. ;-)) Also bevor man *so* fest behauptet das ``del`` von Funktionen bei Modulen sinnvoll ist, sollte man das echt mal beweisen…
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Hyperion Ich habe überhaupt nichts substantiell Relevantes und Belegtes gegen die Verwendung von del erfahren, nur Vermutungen, dass man das wahrscheinlich nie braucht.
Es spricht überhaupt nichts gegen die Verwendung von del. Außer dass einige dieses nicht tun, weil sie es bei ihren Programmen nicht brauchen. Wenn sie es nicht brauchen, dann habe ich überhaupt nichts dagegen, dass sie es nicht verwenden.

Aber: weil sie es nicht verwenden - was sie auch nicht brauchen - erwarten sie, dass es andere auch nicht verwenden. Und machen daraus dann ein Hallo, wie wenn die Welt untergehen würde.
Und wehren sich wie sie nur können dagegen, dass ein anderer 'del' benützt. Ob Ihr del nicht benützt, ist Eure Sache. Und ob ich del benütze ist meine Sache. Ich weiß schon warum ich das tue.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Sag ich ja, mach doch einfach mal weiter und veröffentliche dein DynTkInter, dann können wir weiter sehen...

bzw. du weißt, was "Garbage Collection" ist oder?
-> https://de.wikipedia.org/wiki/Garbage_Collection

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Alfons Mittelmeyer hat geschrieben:@Hyperion Ich habe überhaupt nichts substantiell Relevantes und Belegtes gegen die Verwendung von del erfahren, nur Vermutungen, dass man das wahrscheinlich nie braucht.
Ich habe jetzt keine Luste die letzten Seiten alle noch einmal durchzugucken, aber BlackJack und andere haben Dir zig Fakten bezüglich Python allgemein und CPython im speziellen dargelegt, die sehr wohl zeigen, dass ``del`` in dem Kontext sinnlos ist.
Alfons Mittelmeyer hat geschrieben: Es spricht überhaupt nichts gegen die Verwendung von del. Außer dass einige dieses nicht tun, weil sie es bei ihren Programmen nicht brauchen. Wenn sie es nicht brauchen, dann habe ich überhaupt nichts dagegen, dass sie es nicht verwenden.
Es sind nicht *einige*, sondern die *aller meisten*! Genau das meinte ich mit gegen den Strom schwimmen - aber wenn Du nicht einmal in der Lage bist zu erkennen, dass Du dies tust, dann ist Dir nicht zu helfen und Du gehörst dann auch nicht zu den Genies sondern zum Komplement dieser Gruppe :twisted:

Viel Spaß noch beim Querulieren - ich denke der halbwegs aufmerksame stumme Mitleser oder zukünftiger Thread-Archäologe wird mittlerweile kapiert haben, dass Deine Idee unsinnig ist. Mehr müssen wir nicht erreichen als Regulars 8)
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

jens hat geschrieben: bzw. du weißt, was "Garbage Collection" ist oder?
-> https://de.wikipedia.org/wiki/Garbage_Collection
Ja die Garbage Collection löscht Garbage, aber fängt nicht an Deine Funktionen zu löschen, die Du nicht mehr brauchst, aber einfach nicht durch del als Garbage kennzeichnen willst.
Benutzeravatar
snafu
User
Beiträge: 6738
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Man muss Garbage nicht explizit als solchen kennzeichnen. Python zählt die Referenzen auf ein Objekt automatisch mit. Wenn der Referenzzähler auf Null steht, d.h. wenn kein Bezeichner mehr auf das Objekt verweist, dann sieht Python es als unerreichbar für den Programmierer an und gibt es daher zum Löschen frei.

Das Aufrufen von `del` führt dabei auch nicht zwangsläufig zum Löschen des Objektes. Es verringert lediglich den besagten Referenzzähler um eine Einheit, da die Verbindung zwischen Bezeichner und Objekt gekappt wird. Falls der Zähler dadurch auf Null steht, dann kann das Objekt gelöscht werden, andernfalls aber lebt das Objekt munter weiter. Bitte `del` daher keinesfalls so ansehen, dass hiermit unmittelbar eine Art Destruktor für das Objekt aufgerufen würde - diese Annahme ist schlichtweg falsch.

Also nochmal ganz deutlich: Mit `del` werden lediglich Referenzen gelöscht. Ein Löschen des Objektes an sich ist nur eine "zufällige" Auswirkung, wenn keine Referenzen mehr für das Objekt bestehen und wenn der Python-Interpreter hierdurch "meint", ein Löschen durchführen zu müssen. Wann der Interpreter dies tut bzw ob er dies überhaupt irgendwann mal vor dem Interpreter-Shutdown tut, ist absolut nicht vorhersehbar.
Benutzeravatar
jens
Python-Forum Veteran
Beiträge: 8502
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Na, also, dann ruft man del solange auf, bis der Referenz-Zähler Null ist :P

GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Gesperrt