@Alfons Mittelmeyer: Man braucht ``del`` in keinem der gezeigten Fälle. Wenn man ein Objekt auf Modulebene an einen Namen bindet, dann ist das in 99,9% der Fälle eine Konstante die man den gesamten Programmverlauf potentiell benötigt. Ist das nicht der Fall dann hat dieser Name nichts auf Modulebene zu suchen. Und zwar nicht wegen Speicherverbrauch sondern weil man sonst einen variablen Wert hat der in Funktionen und Methoden verwendet wird ohne über deren Funktionssignatur ersichtlich ist, was unsauber, weil sehr magisch und unübersichtlich ist. Es schafft ”unsichtbare” Verbindungen zwischen Funktionen/Methoden/Objekten die Code schwerer durchschaubar und schwerer testbar machen.
Wenn man allgemein sauber programmiert, ohne dabei auf Speicherverwaltung zu achten, erledigt sich das mit der Speicherverwaltung von selbst, genau deswegen braucht man sich da keine Gedanken drum zu machen. Nur wenn es tatsächlich mal ein Problem geben sollte, also real, messbar, spürbar, nicht eingebildet, *dann* muss man sich mal hinsetzen und über den Speicherverbrauch nachdenken. Das aber dann in der Regel auch nicht über ``del`` sondern über einen anderen Algorithmus oder eine andere Datenstruktur lösen, denn wenn man sauber programmiert und trotzdem Speicherprobleme bekommt, ist das normalerweise ein strukturelles Problem und nichts was man mit ein paar ``del``\s lösen könnte.
Wenn man später mal embedded Programmieren will nimmt man schlicht kein Python. Selbst manuell dynamisch Speicher verwalten spart man sich in dem Bereich oft und macht das statisch um sicherzustellen das auch tatsächlich während der Laufzeit der Speicher nicht ausgeht.
Problem mit Audio CDs
@Alfons:
Das mit dem del ist aber auch aufregend. Ich dachte immer, es ist einfach nur zum Entfernen von Bezeichnern aus Namensräumen oder von Attributen. Kannst Du mir nochmal erklären, was dass jetzt mehr macht als das? Ich verstehs einfach nicht und möchts doch gerne richtig anwenden.
Das mit dem del ist aber auch aufregend. Ich dachte immer, es ist einfach nur zum Entfernen von Bezeichnern aus Namensräumen oder von Attributen. Kannst Du mir nochmal erklären, was dass jetzt mehr macht als das? Ich verstehs einfach nicht und möchts doch gerne richtig anwenden.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Da sind zwei oder gar drei verschiedene Ziele vermischt. Das eine ist der GuiEditor zur Erstellung, Übernahme aus bestehenden Programmen, Modifizierung und Speicherung der GUI, der auch einige zusätzliche Gimmicks enthalten wird. Da hätte ich etwa Nachladelabel, die aussehen wie solche <href Label auf Webseiten. Weiss allerdings nicht, ob ich sie wieder herausnehme, weil man sie leicht selber machen kann. Das andere ist DynTkInter, eine tkinter Erweiterung, welche dynamische GUIs ermöglicht, die man zur Laufzeit jederzeit modifizieren, ganz oder teillöschen und nachladen kann. Auf DynTkInter - wie es funktioniert hatte ich im Thread spazierengehen in der GUI dargestellt - beruht auch der GuiEditor. Das dritte wären dann weitere Dynamische Applikationen, die auf DynTkInter beruhen und womit man dann eine Menge anstellen kann. Was genau das für Applikationen sein könnten, habe ich mir allerdings noch nicht überlegt. DynTkInter funktioniert auch mit Sourcen, die in TkInter geschrieben sind und es können auch Gui Teile, die in tkinter geschrieben sind, nachgeladen werden. Hierfür reicht dann allerdings nicht eine Quellangabe für ein Script, sondern es ist noch eine zweite Angabe erforderlich, nämlich welche Funktion oder Methode darin mit der Angabe des Parents aufzurufen ist.Sirius3 hat geschrieben:@Alfons Mittelmeyer: weil Du hier noch nie Dein wahres Ziel gepostest hast, tu ich mal das für Dich. Widersprich mir, wenn ich falsch liege: Du willst eine GUI-Anwendung schreiben, wo Nutzer interaktiv Fenster gestalten können und mit Funktionen hinterlegen können. Diese Fenster können gespeichert, verschickt, ins Internet geladen werden, von dort wieder von anderen Nutzern heruntergeladen werden, bearbeitet oder benutzt werden. Also alles in einem, Editor und Ausführung von beliebig vielen "Apps".
Erstes Ziel ist, den GuiEditor zu überarbeiten, damit der Code gut aussieht, ihn fertigzustellen, indem ich mich noch mit PanedWindows und Menüs befasse und weitere Speicherroutinen einzubauen also nicht nur DynTkInter Quellcode, sondern auch tkinter Quellcode und so etwas wie qt ui Dateien oder Ähnliches.
Es empfielt sich, umfangreiche Apps als Klasse zu definieren. Wenn jemand lieber globale Funktionen nimmt, kann ich auch damit umgehen - d.h. am Ende die globalen Referenzen beseitigen. Von Interaktivität prozedural steuern war keine Rede und ein Script das hintereinander Befehle ausführt steht in keinerlei Gegensatz zu einer GUI. Ein typisches Script für eine App sähe so aus:Sirius3 hat geschrieben:Dazu ein paar Anmerkungen:
GUIs sind Event-gesteuert. Gerade wenn es viele Apps geben soll, ist es fast unumgänglich, eine App als Klasse zu definieren. Daher ist es schwierig, Interaktivität prozedural zu steuern, ein Skript das nacheinander Befehle ausführt widerspricht dem Grundaufbau einer GUI.
Code: Alles auswählen
class MyApp():
xxxx
xxxx
MyApp()
Das am Besten für DynTkInter geeignete Format ist DynTkInter Sourcecode. Für einfache tkinter Programme und Beispiele biete ich dann auch Speicherung in tkinter Sourcecode an und für komplexere Programm, die auch ihre eigenen Widget Klassen wollen, so etwas ähnliches wie Qt ui Files. Muss mir allerdings noch Gedanken machen, wie das genau aussehen soll. Kann man ja später darüber diskutieren.Sirius3 hat geschrieben:Um Fenster laden und speichern zu können, braucht es ein Datenformat, das am Besten Ähnlichkeiten zur internen Struktur hat, also eine Art Baum, wo Knöpfe und Eingabefelder die Blätter sind, die zusätzlich noch Attribute haben. Schau Dir mal ui-Dateien von QT an.
Ja haargenau so sollte programmiert werden. GUI Callbacks sollen keinerlei App spezifischen Funktionen aufrufen. Nehmen wir das Beispiel einer Eingabemaske. Nach Eingabe gibt es einen Button für Daten übernehmen. Alles was dieser Button dann tun soll ist die Daten zu senden mit einer bestimmten Message ID. Und das war es dann für die GUI. Und die App richtet dann einen Callback für diese Message ID ein und ruft in diesem Callback dann ihre Funktionen oder Methoden asuf, welche die Daten weiterverarbeiten. Genauso gibt es auch den umgekehrten Weg, dass die App Daten an die GUI sendet.Sirius3 hat geschrieben:Jetzt kommen wir zum Punkt Aktionen: die hängen ja nicht in der bloßen Luft. Neben der Außenansicht (GUI) gibt es auch noch das Innenleben (Geschäftslogik) die beide erstmal nichts miteinander zu tun haben. Die Geschäftslogik sollte ohne GUI entwickelt und getestet werden, erst danach, wird sozusagen als Aufsatz eine GUI gemacht. Änderungen bedeuten dann oft eine Änderung der Datenstrukturen, und damit muß man die App komplett neustarten.
Wie ich das mache, muss ich mir überlegen, wenn ich etwas mit vielen Apps mache. Jetzt überlege ich es mir noch nicht.Sirius3 hat geschrieben:Und damit komme ich zum letzten Punkt: viele Apps in einer Anwendung wird selten gemacht, weil die Nachteile überwiegen. Getrennte Prozesse sind voreinander geschützt. In Python kann so ziemlich alles dynamisch geändert werden. Eine fehlerhaft programmierte App kann damit das ganze Programm instabil machen. Und das will man normalerweise nicht haben.
Sorry, mit dem GUI Editor erstellt man GUI und führt keine Programme aus. Es ist nur ein Schmankerl, wenn man anbieten kann, dass der GUI Editor auch zu laufenden Programmen dazugeladen werden kann und deren Gui bearbeitet und abgespeichert werden kann. Ebenso ein Schmankerl, wenn man bei laufendem Programm unter bestimmten Voraussetzungen Code modifizieren und testen kann. Notwendig ist es eigentlich nicht und eigentlich habe ich es selber auch kaum verwendet. Denn ein Editor mit Syntax Highlighting gefällt mit besser als eine Eingabe in ein Text-Widget. Wenn Microsoft solche Dinge nicht anbietet, dann liegt es daran, dass das mit .Net und C/C++ nicht so einfach ist, wie mit tkinter und Python, denn so etwas geht nicht in C/C++: eval(compile("Button()"))Sirius3 hat geschrieben:Selbst so große Firmen wie Microsoft haben in ihren Visual XY den (GUI-)Editor vom Ausführen der Programme getrennt. Vielleicht gibt es den ein oder anderen Programmieranfänger, der Deine Visionen toll findet, aber damit das Projekt erfolgreich werden kann, mußt Du Dich an erprobte Praktiken halten. Dazu zählen Module, Klassen und Methoden, keine globalen Variablen, insbesondere kein eval, das globale Zustände ändert.
Naja ließe sich auch mit einer if Abfrage über alle Wiget Typen machen. Sollte man allerdings noch eigene Widget Klassen dabei berücksichtigen, wäre es mit if Abfragen gar nicht mehr machbar. Zur Zeit behandle ich nur normale tkinter Widgets und keine vom Benutzer definierten. Derjenige, der den GuiEditor für seine Apps verwendet, kann Module Klassen und Methoden nehmen wie er will. Ich benütze das DynTkInter Modul und ob ich lieber eine Klasse nehme und dann das in __init__ reinschreibe, was ich ohne Klasse gemacht hatte oder ob es übersichtlicher ist, das nicht zu tun, werde ich mir noch überlegen. Jedenfalls benutze ich dann zum Aufbau des GuiEditor einen gesonderten Namensraum, damit es mit Sicherheit keinerlei Überschneidungen mit einer App gibt und globale Funktionen für diesen gesonderten Namensraum sind auch kein Problem, weil sie automatisch - naja, durch die Ladefunktion - wieder beseitigt werden. Und kein eval? Eval läßt sich nicht vermeiden, da jedenfalls ein import sich verbietet - könnte man ja auch nur einmal laden - scripts muss man so oft laden können, wie man will. Ja und wenn ohne import, wie dann? Oder ist exec akzeptabel?
Das ist keine neue Programmiersprache. Das ist entstanden, weil ich da noch nicht wußte, wie ich Definitionen wieder wegbekomme. Gar keine Variablen verwenden ausser einem Stack und einem Dictionary und keine Funktionen zu verwenden außer compilertem Code, geht auch. Aber sieht eben abscheulich aus. Jetzt weiß ich ja durch unsere Diskussion, wie ich auch unter Verwendung von Funktionen und Ähnlichem, wieder alles wegbekomme - del nehme ich hierbei nicht - und kann dann den GuiEditor so umschreiben, dass der Code dann gut aussieht.Sirius3 hat geschrieben:Das was Du bisher gezeigt hast, ist kein Python, sondern eine Art maschinennahes BASIC in Python-Syntax. Der Vorteil von Python ist, dass man sich um vieles keine Gedanken machen muß, wenn man sich an ein paar einfache Regeln hält. Bei Deiner neuen Programmiersprache muß sich der Programmierer dagegen viele Gedanken um Dinge machen, wo die meisten Programmierer froh sind, sie seit etlichen Jahren los zu sein.
Neee, das ist ein Wahrnehmungsproblem. Das ist entstanden, weil du keine Ahnung davon hattest wie man Programme in Python schreibt und dich beharrlich weigerst das zu lernen.Alfons Mittelmeyer hat geschrieben:Das ist keine neue Programmiersprache. Das ist entstanden, weil ich da noch nicht wußte, wie ich Definitionen wieder wegbekomme.
Zuletzt geändert von sparrow am Samstag 22. August 2015, 20:26, insgesamt 1-mal geändert.
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Also das mit del steht nicht gut in der Dokumentation. Unter del in der Dokumentation findet man nur das mit dem Namensraum und unter __del__() findet man dann das mit dem Referenzzähler. Wenn Du etwa schreibst: a = MyClass()jerch hat geschrieben:@Alfons:
Das mit dem del ist aber auch aufregend. Ich dachte immer, es ist einfach nur zum Entfernen von Bezeichnern aus Namensräumen oder von Attributen. Kannst Du mir nochmal erklären, was dass jetzt mehr macht als das? Ich verstehs einfach nicht und möchts doch gerne richtig anwenden.
Dann hast Du eine Variable mit dem Namen a definiert und eine Instanz von MyClass. Und die Variable a enthält eine Referenz auf diese Instanz. Wenn sonst nichts auf diese Instanz verweist, ist der Referenzzähler für diese Instanz auf eins.
Was del macht, ist, den Referenzzähler um eins erniedrigen und den Namen aus dem Namensraum beseitigen. Wenn der Referenzzähler auf eins war, geht damit dann der Referenzzähler auf Null und der Speicher wird freigegeben. Wenn allerdings diese Instanz in ihrem init sich oder eine ihrer Methoden an etwas anderes gebunden hat, dann geschieht bei del dasselbe, nur der Speicher wird dann noch nicht freigegeben. Sondern erst, wenn dann auch die anderen Referenzen aufgelöst werden.
Bei globalen Variablen muss man immer mit einem del dafür sorgen, dass der Speicher freigegeben werden kann. Bei lokalen Variablen innerhalb einer Funktion oder einer Methode braucht es das normalerweise nicht, da dann bei Funktionsende der Referenzzähler automatisch erniedrigt wird.
Aber auch globale Funktionen sind eine Referenz auf Speicher für diese Funktion. Und wenn man diese Funktion nicht mehr braucht, was in Scripten der Fall sein kann, dann kann man mit del auch diesen Speicher wieder freigeben, aber nur wenn nicht andere Funktionen diese referenzieren. Eventuell muss man bei Funktionen etwas mehr aufpassen, da müßte man mal nachsehen, ob nach del diese Funktion für andere vorher definierte Funktionen noch zur Verfügung steht oder nicht mehr. Oder ob dann diese Funktionen crashen. Ich habe mir das jetzt noch nicht angeschaut.
Statt del kann man als Ersatz - etwa bei viel Speicher - auch eine Neuzuweisung machen, etwa a = None. Zuweisungen enthalten bereits das del. Hier gilt dasselbe wie für del. Die vorherige Instanz bleibt im Speicher wieder solange erhalten, bis keine Referenzen mehr dafür da sind. Wenn keine sonstigen da waren, wird der Speicher freigegeben, wenn noch welche da sind, etwa Methodenbindung an Callbacks und dergleichen, dann erst, wenn diese Referenzen aufgelöst wurden.
Nö, ich denke dass es bei Funktionen so ist:
Code: Alles auswählen
def myfunction():
xxxx
xxxx
a = myfunction
del myfunction
a()
-
- User
- Beiträge: 1715
- Registriert: Freitag 31. Juli 2015, 13:34
Das ist so entstanden, weil ich nicht gewußt hatte, dass man Funktionen mit del löschen kann. Jetzt weiß ich außerdem dass Ihr etwas dagegen habt und kann es jetzt so machen, dass Ihr nichts dagegen habt, denn bei einem dictionary darf man ja del nehmen:sparrow hat geschrieben:Neee, das ist ein Wahrnehmungsproblem. Das ist entstanden, weil du keine Ahnung davon hattest wie man Programme in Python schreibt und dich beharrlich weigerst das zu lernen.Alfons Mittelmeyer hat geschrieben:Das ist keine neue Programmiersprache. Das ist entstanden, weil ich da noch nicht wußte, wie ich Definitionen wieder wegbekomme.
Code: Alles auswählen
def myfunction():
xxxx
xxxx
myfunction()
del globals()['myfunction']
Eine andere Frage: eine Funktionsdefinition bekomme ich weg. Instanzen einer Klasse bekomme ich weg. Bekomme ich auch Klassendefinitionen weg?
Das nächste Wahrnehmungsproblem deinerseits . Das nimmt ja gar kein Ende.
Der gute Jerch wird dir vielleicht auch noch eins zeigen.
Ich bleibe dabei: entweder du bist ein Troll, oder du wirst nie Zugang zur Programmierung in Python finden. Bleib doch bei .Net, da scheint du dich ja bestens auszukennen.
Zu helfen ist dir jedoch nicht.
Der gute Jerch wird dir vielleicht auch noch eins zeigen.
Ich bleibe dabei: entweder du bist ein Troll, oder du wirst nie Zugang zur Programmierung in Python finden. Bleib doch bei .Net, da scheint du dich ja bestens auszukennen.
Zu helfen ist dir jedoch nicht.
@Alfons Mittelmeyer: Unter ``del`` findet man nur das mit dem Namensraum *weil es das einzige ist was Python garantiert* und *weil genau dafür, und nur dafür ``del`` gedacht ist*.
Das mit dem Referenzzähler was bei `__del__()` beschrieben ist, ist ein CPython Implementierungsdetail, und als solches ist dort auch nur als *Anmerkung* ausgezeichnet beschrieben. Eine Python-Implementierung muss keine Referenzzähler verwenden! Das tun auch nicht alle! Und auch künftige CPython-Versionen müssen das nicht. Das also ständig als Erklärung zu bringen was bei ``del`` passiert, ist schlicht falsch, weil es nicht so laufen muss, weder in allen Implementierungen noch in Zukunft bei Implementierungen die das heute so machen.
Bei globalen Variablen *muss* man nicht mit einem ``del`` dafür sorgen das der Speicher freigegeben werden kann, denn a) hat man keine globalen Variablen wenn man sauber programmieren will und b) ist das falls man die doch hat kein Problem da ein bisschen Speicher zu belegen.
Da ``del`` *Namen* aus Namensräumen entfernt kann man so eine ”entfernte Funktion” nicht mehr über den Namen aufrufen nachdem der entfernt wurde. Auch wenn das Funktionsobjekt selbst noch irgendwo erreichbar ist, über den Namen natürlich nicht mehr. Denn das ist ja genau der Effekt den ``del`` hat. Der einzige der Effekt der für die Sprache dokumentiert ist, also genau das was man damit machen können soll. Und man braucht das tatsächlich dann auch nur äusserst selten.
Zuweisungen enthalten kein ``del``, die sind genau das *Gegenteil* von ``del`` wenn der Name vorher nicht existierte, denn dann wird der Name erstellt und nicht gelöscht, was ja die einzige Funktion von ``del`` ist, oder der Name wird an einen neuen Wert gebunden, und ist danach natürlich auch nicht gelöscht, was ``del`` machen würde.
Wenn man den Speicher für die Funktion im letzten Beispiel freigeben will kann man gar nichts machen ausser die Bindung lösen und *hoffen* das die Python-Implementierung den Speicher *vielleicht* und *irgendwann* freigibt, was aber *nicht garantiert ist*!
Und ``del myfunction`` durch ``del globals()['myfunction']`` und zu behaupten das wir ja nichts dagegen haben ist entweder trollen oder Du verstehst es einfach nicht. Es provoziert auf jeden Fall. Hör mit diesem Scheiss auf!
Das mit dem Referenzzähler was bei `__del__()` beschrieben ist, ist ein CPython Implementierungsdetail, und als solches ist dort auch nur als *Anmerkung* ausgezeichnet beschrieben. Eine Python-Implementierung muss keine Referenzzähler verwenden! Das tun auch nicht alle! Und auch künftige CPython-Versionen müssen das nicht. Das also ständig als Erklärung zu bringen was bei ``del`` passiert, ist schlicht falsch, weil es nicht so laufen muss, weder in allen Implementierungen noch in Zukunft bei Implementierungen die das heute so machen.
Bei globalen Variablen *muss* man nicht mit einem ``del`` dafür sorgen das der Speicher freigegeben werden kann, denn a) hat man keine globalen Variablen wenn man sauber programmieren will und b) ist das falls man die doch hat kein Problem da ein bisschen Speicher zu belegen.
Da ``del`` *Namen* aus Namensräumen entfernt kann man so eine ”entfernte Funktion” nicht mehr über den Namen aufrufen nachdem der entfernt wurde. Auch wenn das Funktionsobjekt selbst noch irgendwo erreichbar ist, über den Namen natürlich nicht mehr. Denn das ist ja genau der Effekt den ``del`` hat. Der einzige der Effekt der für die Sprache dokumentiert ist, also genau das was man damit machen können soll. Und man braucht das tatsächlich dann auch nur äusserst selten.
Zuweisungen enthalten kein ``del``, die sind genau das *Gegenteil* von ``del`` wenn der Name vorher nicht existierte, denn dann wird der Name erstellt und nicht gelöscht, was ja die einzige Funktion von ``del`` ist, oder der Name wird an einen neuen Wert gebunden, und ist danach natürlich auch nicht gelöscht, was ``del`` machen würde.
Wenn man den Speicher für die Funktion im letzten Beispiel freigeben will kann man gar nichts machen ausser die Bindung lösen und *hoffen* das die Python-Implementierung den Speicher *vielleicht* und *irgendwann* freigibt, was aber *nicht garantiert ist*!
Und ``del myfunction`` durch ``del globals()['myfunction']`` und zu behaupten das wir ja nichts dagegen haben ist entweder trollen oder Du verstehst es einfach nicht. Es provoziert auf jeden Fall. Hör mit diesem Scheiss auf!
- Hyperion
- Moderator
- Beiträge: 7478
- Registriert: Freitag 4. August 2006, 14:56
- Wohnort: Hamburg
- Kontaktdaten:
+1BlackJack hat geschrieben:Es provoziert auf jeden Fall. Hör mit diesem Scheiss auf!
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
assert encoding_kapiert