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.
Üpsilon
User
Beiträge: 222
Registriert: Samstag 15. September 2012, 19:23

Ich kann zwar nichts zum Thema beitragen, aber bei
Sorry, das ist kein Modul, sondern ein Script
musste ich an "Das ist kein Tier, das ist ein Vogel" denken...
Bild
PS: Die angebotene Summe ist beachtlich.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@Alfons Mittelmeyer: Nochmal: Skripte sind Module also geht es in jedem Fall um Module. Die Freigabe von Speicher geschiet doch von selber, denn der Benutzer gibt keinen Speicher frei. Kann er gar nicht.
Bemühe Dich mal den Unterschied zwischen Top-Level-Script und einem Modul zu begreifen. Wenn Du einfach Python aufrufst und dann eingibst: print(5+9)
ist das dann ein Modul? Gewiss man kann auch einen File machen, etwa script.txt und den kann man dann aufrufen mit: python script.txt
Man kann auch die Fileextension .py verwenden und dann kann man das Script genauso importieren wie ein Modul. Aber vom Sinn her ist es dann immer noch kein Modul, es sei denn, dass man eine Funktion main() als library Funktion ansehen will. Wenn Du das tun willst, dann tu es. Aber ich sag dann dazu auch nichts mehr. Die Freigabe von Speicher geschieht von selber? Ein Irrglaube ist das. Der Programmierer hat dafür zu sorgen, dass die Referenzen freigegeben werden und irgendwann der Referenzzähler auf Null geht. Erst dann wird der Speicher freigegeben. Gewiß etliches davon macht Python selber, etliches aber auch nicht. Und wenn Du ordentlich programmieren willst, mußt Du wissen, was Python selber macht und was nicht. Allerdings wenn Du keine globalen Variablen verwendest, sondern nur eine Funktion oder eine Klasse nebst Instanz, dann ist der halbe Schritt schon getan und wenn Du bei tkinter nur tkinter Callbacks verwendest, dann wird es höchstwahrscheinlich schon passen. Wenn Du aber in einem Modul noch andere Referenzen verwaltest - ich hatte Message Callbacks - dann mußt Du Dich selber darum kümmern, dass diese Referenzen auch freigegeben werden.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Alfons Mittelmeyer hat geschrieben:
BlackJack hat geschrieben:@Alfons Mittelmeyer: Nochmal: Skripte sind Module also geht es in jedem Fall um Module. Die Freigabe von Speicher geschiet doch von selber, denn der Benutzer gibt keinen Speicher frei. Kann er gar nicht.
Bemühe Dich mal den Unterschied zwischen Top-Level-Script und einem Modul zu begreifen. Wenn Du einfach Python aufrufst und dann eingibst: print(5+9)
ist das dann ein Modul? Gewiss man kann auch einen File machen, etwa script.txt und den kann man dann aufrufen mit: python script.txt
Man kann auch die Fileextension .py verwenden und dann kann man das Script genauso importieren wie ein Modul. Aber vom Sinn her ist es dann immer noch kein Modul, es sei denn, dass man eine Funktion main() als library Funktion ansehen will. Wenn Du das tun willst, dann tu es. Aber ich sag dann dazu auch nichts mehr. Die Freigabe von Speicher geschieht von selber? Ein Irrglaube ist das. Der Programmierer hat dafür zu sorgen, dass die Referenzen freigegeben werden und irgendwann der Referenzzähler auf Null geht. Erst dann wird der Speicher freigegeben. Gewiß etliches davon macht Python selber, etliches aber auch nicht. Und wenn Du ordentlich programmieren willst, mußt Du wissen, was Python selber macht und was nicht. Allerdings wenn Du keine globalen Variablen verwendest, sondern nur eine Funktion oder eine Klasse nebst Instanz, dann ist der halbe Schritt schon getan und wenn Du bei tkinter nur tkinter Callbacks verwendest, dann wird es höchstwahrscheinlich schon passen. Wenn Du aber in einem Modul noch andere Referenzen verwaltest - ich hatte Message Callbacks - dann mußt Du Dich selber darum kümmern, dass diese Referenzen auch freigegeben werden. Alles was global ist, das mußt Du selber machen, also auch Referenzen aus einer modulglobalen Liste beseitigen - etwa mit pop() - oder del oder aus einem modulglobalen Dictionary.
Del allerdings hat in Verbindung mit modulglabalen Variablen nichts verloren. Denn bei Modulenn handelt es sich um Libraryfunktionen odder auch Varablen, die man in diesem Zusammenhang braucht. Und da wirft man auch nichts weg. Bei Top-Level-Scripten allerdings ist das ganz was anderes. Da kann man jederzeit neue Variablen definieren, die man nur kurzzeitig braucht, sozusagen Wegwerfvariablen für einmalige oder kurzzeitige Verwendung. Warum man sich dann gegen das Wegwerfen sträubt, geht mir allerdings nicht ein. Da sollte man sich ernsthaft darum bemühen, den Unterschied zwischen Top-Level-Scripten und Modulen zu begreifen. Ansonsten macht darüber zu reden Null Sinn.
Zuletzt geändert von Alfons Mittelmeyer am Freitag 21. August 2015, 23:09, insgesamt 1-mal geändert.
Üpsilon
User
Beiträge: 222
Registriert: Samstag 15. September 2012, 19:23

Aber vom Sinn her ist es dann immer noch kein Modul
Ja, aber der Sinn ist dem Computer egal. Du kannst es theoretisch ausführen und du kannst es theoretisch importieren. Was du praktisch machen willst, steht auf einem anderen Blatt.
PS: Die angebotene Summe ist beachtlich.
Sirius3
User
Beiträge: 17712
Registriert: Sonntag 21. Oktober 2012, 17:20

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

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

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.

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

@Alfons Mittelmeyer: Ich bemühe mich Dir zu erklären das Skript und Modul kein Widerspruch ist. Ein Skript ist ein Modul. Wenn man ein Modul ausführt, dann verwendet man es als Skript/Programm. Die Dichotomie die Du zwischen diesen beiden Begriffen annimmst gibt es nicht. Auch wenn Du das beharrlich wiederholst wird es nicht wahr.

Wenn ich eine interaktive Python-Shell starte und dort ``print(5+9)`` eingebe ist das weder Modul noch Skript. Es wird aber im Kontext eines Moduls ausgeführt welches die Python-Shell am Anfang anlegt und das `__main__` heisst.
Benutzeravatar
snafu
User
Beiträge: 6732
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Die Verarbeitung großer Datenmengen würde jeder erfahrene Programmierer möglichst so implementieren, dass jeweils ein kleiner Happen der Daten eingelesen wird, die Verarbeitung des Happens erfolgt, um anschließend den nächsten Happen einzulesen, diesen zu verarbeiten, usw. Es gibt Situationen, in denen dieses Vorgehen nicht möglich bzw nicht sinnvoll ist, aber die bilden eher die Ausnahme. In der Regel programmiert man speicherschonend, wie zuvor beschrieben.

Das Einlesen aller Tracks einer CD und diese Daten dann in einer Liste allesamt gleichzeitig im Speicher zu halten ist absolut irrsinnig. Die in Python übliche Alternative ist die Nutzung eines Generators statt einer Liste, was ja bereits gezeigt wurde. Selbst das Einlesen der einzelnen Wave-Datei kann blockweise in einer Schleife passieren, sofern man direkt im Anschluss etwas damit machen möchte, was nicht zwingend die Wave-Datei als Ganzes erfordert (z.B. sofortiges Abspielen in einem Audio-Player kann durch häppchenweises Laden erfolgen).

Speicherschonende Programmierung ist wichtig und sollte auch stets umgesetzt werden. Dass `del` dafür das absolut falsche Werkzeug ist, da `del` schlichtweg nicht zur Speicherfreigabe gedacht ist, weil man sich nicht darauf verlassen kann, wann diese Speicherfreigabe erfolgt, wurde ja bereits weitaus mehr als nur einmal erklärt. Der Threadersteller bleibt hierbei uneinsichtig und soll es von mir aus bis an sein Lebensende bleiben, wenn er meint. Für andere interessierte Mitlesende: Durch `del` passiert im Hinblick auf die Speicherfreigabe nichts, was man mit sauberer Programmierung nicht ebenfalls erreichen könnte.

Der Punkt ist, Objekte mit großen Datenmengen (z.B. riesige Zeichenketten) nicht länger als nötig leben zu lassen und ihre Entstehung generell zu vermeiden, wo immer es geht. Wenn man merkt, dass man zuviele solcher Objekte hat und dass diese den Speicher zumüllen, dann ist die Lösung nicht die stumpfe Anwendung von `del`, sondern die intelligente Überarbeitung seiner Datenstrukturen und Algorithmen, sodass diese Ansammlung speicherfressender Objekte gar nicht erst entstehen kann. Wenn man einigermaßen mit den Möglichkeiten von Python vertraut ist und auch Ahnung von Programmierung im Allgemeinen hat, dann weiß man auch, was man dafür zu tun hat und wie man dies umsetzen kann.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons:
Lass Dich nicht beirren - Du bist auf dem richtigen Weg. Damit Dein gezeigtes Skript funktioniert, brauchst Du nur soviel RAM wie Du CDs hast in Deinen Rechner einbauen. Dann wird alles gut.
Benutzeravatar
snafu
User
Beiträge: 6732
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Und es ist ja auch ein allseits bekanntes Problem, dass man z.B. zum Abspielen eines 200 GB umfassenden HD-Films immer auch mindestens 200 GB RAM benötigt, weil die Programme ja alle so geschrieben sind, dass sie die kompletten Daten im Speicher halten. Noch schlimmer wird es dann bei Playlisten oder Serien, wo dann auch immer alle Filme gleichzeitig im Speicher gehalten werden... :roll:
Benutzeravatar
snafu
User
Beiträge: 6732
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Alfons Mittelmeyer hat geschrieben:Wenn ich mein Programm so schreibe, wie ich es mir vorstelle, dann funktioniert es einwandfrei.
Wenn ich es aber so mache, wie man mir es empfiehlt, dann funktioniert es überhaupt nicht.
Dein Code entspricht so ganz und gar nicht dem, was dir empfohlen wird. Was dir tatsächlich empfohlen wird, kannst oder willst du doch gar nicht begreifen. Du willst Konzepte hinsichtlich einer manuellen Speicherfreigabe krampfhaft in eine Sprache übernehmen, die nicht für manuelle Speicherfreigabe entwickelt wurde und wo die entsprechend notwendigen Garantien dafür nicht gegeben werden, sodass dieses Vorhaben völliger Nonsense ist.

Wenn man dir das jedoch versucht zu erklären und alternative Vorgehensweisen erläutert, die in Python Gang und Gäbe sind und sich im Laufe vieler Jahre auch bewährt haben, dann stampfst du wütend mit dem Fuß auf den Boden wie ein kleines Kind, das seinen Willen nicht kriegt, anstatt mal wirklich etwas davon anzunehmen. Und wenn irgendwann niemand mehr auf dich reagiert oder der Thread geschlossen wird, dann machst du den nächsten Thread auf und fängst mit der selben Leier von vorne an. Das ist Trollen in Reinkultur für mich.
Alfons Mittelmeyer hat geschrieben:Zuerst hatte ich gedacht, dass ich immer denselben Namen für die Variable nehme, damit der Speicher dann aufgeräumt wird. Da hat man mir aber gesagt, dass das nicht nötig wäre, denn Python kümmert sich schon automatisch darum. Wenn ich mit einer CD etwas gemacht habe, brauche ich sie nicht mehr im Speicher. Da hatte ich mir gedacht, dass ich den Speicher auch wieder freigebe. Aber dann hat man mich sehr geschimpft und dann so etwas geschrieben: Du betreibst del als Mikromanagement, und Mikromanagement ist unsinnig und damit del auch. Oder dass das Speichermanegement in Python wäre und dass ich davon gefälligst die Finger lassen soll. Oder dass ich damit nur dem Garbage Collector die Arbeit erschwere, der das automatisch macht.
Was für ein Schwachsinn. Warum sollte man Namen nicht wiederverwenden dürfen? Was glaubst du denn, was z.B. in einer `for`-Schleife passiert? Da beruht das gesamte Konzept auf der Wiederverwendung eines Namens. Und ich habe auch noch nie gehört, dass es dem Garbage Collector Schwierigkeiten machen würde, wenn die Bindung für einen Namen im weiteren Verlauf des Programms neu definiert wird.

Zudem kann ich mir nur schwer vorstellen, dass hier jemand eine solche Aussage getroffen hat. Das entspringt wohl wieder mal deiner eigenen Fehlinterpretation, wie so vieles hier.
Alfons Mittelmeyer hat geschrieben:Also ich weiss jetzt nicht mehr weiter, was ich jetzt tun soll. Wenn ich del nehme, dann funktioniert es, wenn ich del nicht nehme, ist es völlig klar, dass das Programm crasht. Aber das will hier keiner einsehen und man will mich so hinstellen, als ob ich uneinsichtig oder bescheuert wäre, weil ich einfach nicht kapieren will, dass man del oder einen Ersatz hier nicht braucht.
Du solltest mal einen großen Knoten in deinem Gehirn lösen und deine Art, in Python zu programmieren, stark überdenken. Solange dieser Knoten besteht, wirst du vermutlich nie einsehen können (oder wollen), warum `del` für dein Programm ungeeignet und auch unnötig ist. Vielen Menschen vor dir ist dies bereits gelungen. Vielleicht schaffst du es irgendwann auch...
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Um es mal auf den Punkt zu bringen: Niemand hat hier ernsthaft bestreitet, das `del` dein konkretes Speicherproblem loest.
ABER dieses Problem entsteht erst dadurch, dass du Python falsch benutzt. In deinem konkreten Beispiel liest du drei komplette Audio-CDs in globale Namen.

Damit belegst du schon mal sicher dein 1 GB an Speicher ohne dass entwas anderes im Speicher liegst und du speichereffizient progammierst (was du nicht tust).
Und da es globale Namen sind, wird der Speicher auch nie freigegeben, schliesslich signalisierst du ja "das wird noch benoetigt".

Wenn das mal wieder ein verzweifelter Versuch ist zu zeigen, dass automatische Speicherverwaltung nicht automatisch ist, dann kann ich nicht mehr darueber lachen: Jedes System geht kaputt, wenn man sich nicht an seine Regeln haelt.
BlackJack

@cofi: Also ich bestreite schon das ``del`` sein allgemeines Speicherproblem löst. Führt man sein CD-laden *mit* ``del`` nach jeder CD mit Jython aus, dann kann das immer noch problemlos an Speichermangel sterben, weil auch ``del`` eben nicht garantiert dass Objekte die nicht mehr von Code aus erreichbar sind, auch tatsächlich aus dem Speicher gelöscht werden. Wenn man Pech hat kommt der GC nicht zum Aufräumen bevor der Speicher aufgebraucht ist. Und das kann man jetzt nicht einfach auf Jython und die JVM schieben, denn die Python-Dokumentation für CPython sagt ja explizit das sich die Art und Weise wie die Speicherverwaltung dort mit Referenzzählern funktioniert, in künftigen CPython-Versionen ändern kann.

Ein Python-Programm das ~500MB grosse Datenmengen nacheinander auf einem System mit 1GB RAM verarbeiten will lebt gefährlich. Da ist, wie schon gesagt, entweder Python die falsche Sprache für die Aufgabe oder das System mit zu wenig RAM ausgestattet. Wenn einem das nicht passt, sollte man für die Aufgabe eine andere Programmiersprache nehmen, oder man verplempert halt sinnlos Zeit manuelle Speicherverwaltung in einer Sprache zu versuchen die das schlicht nicht bietet…
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Darum sagte ich "konkret" nicht "allgemein" ;) Aber da er nunmal in den Raum gestellt hat, dass behauptet wird, was er beobachtet kann nicht sein, fand ich es erwaehnenswert.
Benutzeravatar
snafu
User
Beiträge: 6732
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

`del` *kann* zur Speicherfreigabe führen. Das ist aber nichts, worauf man sich 100%ig verlassen kann. Und man hätte den selben Effekt, den man auch ohne `del` hätte, wenn man denn so programmiert wie alle anderen es auch tun und wie es in einer Sprache mit automatischer Speicherfreigabe ja auch vorgesehen ist.

Wenn man aber konsequent *gegen* bestimmte Sprachkonzepte arbeitet oder Spracheigenschaften herausstellt, die in dieser Form überhaupt nicht existieren, dann muss man sich nicht wundern, dass man von der Community mit Kopfschütteln zurecht gewiesen wird. Das kann man für den Privatgebrauch ja gerne halten wie man möchte, aber als ernstgemeinte Aussage in einem Forum stellt es für mich ein Problem dar.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

snafu hat geschrieben:`del` *kann* zur Speicherfreigabe führen. Das ist aber nichts, worauf man sich 100%ig verlassen kann. Und man hätte den selben Effekt, den man auch ohne `del` hätte, wenn man denn so programmiert wie alle anderen es auch tun und wie es in einer Sprache mit automatischer Speicherfreigabe ja auch vorgesehen ist.

Wenn man aber konsequent *gegen* bestimmte Sprachkonzepte arbeitet oder Spracheigenschaften herausstellt, die in dieser Form überhaupt nicht existieren, dann muss man sich nicht wundern, dass man von der Community mit Kopfschütteln zurecht gewiesen wird. Das kann man für den Privatgebrauch ja gerne halten wie man möchte, aber als ernstgemeinte Aussage in einem Forum stellt es für mich ein Problem dar.
Del gehört natürlich zum Sprachkonzept. Je nachdem, wie man programmiert, braucht man del oder nicht. Und man kann so programmieren, dass man es nicht braucht. Hierzu ein Beispiel:

Code: Alles auswählen

class MyClass():
    xxxx
    xxxx
MyClass()
Hier wird eine Instanz nur temporär angelegt. Wenn aber Methoden von ihr mit tkinter Callbacks verbunden sind, bleibt diese Instanz solange bestehen, bis diese Callbacks durch Löschen der jeweiligen Widgets oder sonstige Beseitigung von commands oder events aufgelöst werden. Dasselbe könnte jemand auch so schreiben:

Code: Alles auswählen

class MyClass():
    xxxx
    xxxx
myInstance = MyClass()
del myInstance
Hier wird eine dauerhafte globale Instanz angelegt. Um sie zu beseitigen, ist del nötig, was aber meist vergessen wird. Aber del braucht man nicht, wenn man es so macht wie vorher gezeigt. Dieses Beispiel macht dasselbe wie das vorherige. Nur Sinn macht es keinen, eine globale Instanz myInstance anzulegen, wenn man myInstance dann in der nächsten Zeile wieder beseitigt. Dabei wird der Speicher freilich nicht freigegeben, solange noch Callbacks zu dieser Instanz existieren, genau wie vorher. Nur hier ohne das del würde der Speicher nie freigegeben, solange man nicht denselben Namen neu vergibt - beinhaltet del - oder Python beendet. Also del ist nicht nötig, wenn man so programmiert, dass man es nicht braucht.

Man sollte jedenfalls über del Bescheid wissen, damit man auch weiss, wie man programmieren soll, dass man es nicht braucht. Es sei denn, dass es nur eine einfache Desktopanwendung wäre, wo sowieso alles egal ist, weil nicht viel Speicher belegt wird und man Python danach beendet. Wer allerdings später einmal embedded programmieren will, sollte nicht so etwas wie sowieso egal denken und 100 Prozent sauber ohne Memory Leaks zu programmieren üben.
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: 4165
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.
Gesperrt