Problem mit Audio CDs

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.
BlackJack

@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.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@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.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

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".
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.

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.
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.
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:

Code: Alles auswählen

class MyApp():
    xxxx
    xxxx
MyApp()
Hier haben wir zwei Befehle, die hintereinander ausgeführt werden, nämlich die Definition der Klasse und deren temporäre Instanzierung
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.
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: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.
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: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.
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: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.
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()"))
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?
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.
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.
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Alfons Mittelmeyer hat geschrieben:Das ist keine neue Programmiersprache. Das ist entstanden, weil ich da noch nicht wußte, wie ich Definitionen wieder wegbekomme.
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.
Zuletzt geändert von sparrow am Samstag 22. August 2015, 20:26, insgesamt 1-mal geändert.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

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.
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()
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()
Das mit a ist eine Referenz und geht noch. Wenn aber andere Funktionen myfunction() aufrufen wollen, das geht nicht mehr, denn das geht über den Namen, den es dann nicht mehr gibt. Wenn man jetzt den Speicher für myfunction freigeben will, muss man a löschen oder einen anderen Wert reinschreiben.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

sparrow hat geschrieben:
Alfons Mittelmeyer hat geschrieben:Das ist keine neue Programmiersprache. Das ist entstanden, weil ich da noch nicht wußte, wie ich Definitionen wieder wegbekomme.
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.
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:

Code: Alles auswählen

def myfunction():
    xxxx
    xxxx

myfunction()

del globals()['myfunction']
Natürlich mich ich das letzteres nicht in der Source sondern in der Ladefunktion für die Source und werfe alles Globale - im gesonderten Namespace heraus

Eine andere Frage: eine Funktionsdefinition bekomme ich weg. Instanzen einer Klasse bekomme ich weg. Bekomme ich auch Klassendefinitionen weg?
Benutzeravatar
sparrow
User
Beiträge: 4193
Registriert: Freitag 17. April 2009, 10:28

Das nächste Wahrnehmungsproblem deinerseits :roll:. 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.
BlackJack

@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!
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

BlackJack hat geschrieben:Es provoziert auf jeden Fall. Hör mit diesem Scheiss auf!
+1
encoding_kapiert = all(verstehen(lesen(info)) for info in (Leonidas Folien, Blog, Folien & Text inkl. Python3, utf-8 everywhere))
assert encoding_kapiert
Gesperrt