Alfons Mittelmeyer's Wundersame Welt

Fragen zu Tkinter.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Das Problem kommt mir bekannt vor. Man hat es auch, wenn man ein Script mit einer Funktion mit read von einem File lädt und dann mit compile und exec ausführt. Die Lösung ist, einen Namensraum dafür zu schaffen.

Das macht man so:

Code: Alles auswählen

def main():

    from tkinter import *

    class ....

main()
Nö, nicht ganz richtig, dieses Problem besteht, wenn man diese Lade, Kompilier und exec Funktion in einem anderen Modul hat. Dann ist der globale Namensraum nämlich der von diesem Modul und nicht der von diesem Script. Und im Script muss man dann einen bekannten lokalen Namensraum schaffen, um bekannt zu machen, was außerhalb von Funktionen und Klassen ist.
BlackJack

@Alfons Mittelmeyer: Das was Du da schreibst hat nichts mit dem ja nun bereits gelösten Problem zu tun. Und Probleme die man durch `compile()` und `exec` bekommt behebt man ganz einfach in dem man `compile()` und `exec` nicht benutzt. :twisted:
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack, ja stimmt, es ist nicht dieses Problem. Aber meinst Du etwa auch, wenn jemand Problem mit tkinter und Python hat, dass es es dann halt einfach nicht benützen soll? Bei compile und exec bist Du ja dieser Meinung. Damit beschränkst Du Dich aber auf nur ein einziges Main Script, während man mit compile und exec beliebig viele Scripts haben kann.

Meinst Du, wenn Du zu einem Programm 50 Hilfeseiten dazu machst, dass das alles im Mainscript verwaltet werden soll? Sollen die Hilfeseiten sich doch selber verwalten und nur die Einsprünge dazu irgendwo im Menü des Mainscripts stehen.
BlackJack

@Alfons Mittelmeyer: Wenn ich 50 Hilfeseiten habe dann sind das Daten die in Datendateien kommen. Vorzugsweise in einem Format was es schon gibt, wie HTML. Und dann schreibt man einmal Code der das anzeigt, beziehungsweise einen Browser startet der das dann anzeigt. Bei moderneren GUI-Toolkits gibt's für so etwas oft auch schon Lösungen/Rahmenwerke die man verwenden kann.

Ansonsten kann man natürlich auch beliebig viele Module haben die man importiert, statt den Quelltext `compile()` und `exec` zu verarbeiten. Da ist kein relevanter Unterschied zum Importieren. Höchstens irgendwelche eingebildeten Speicherprobleme. Was aber mit dem Problem in diesem Thema hier wieder so rein gar nichts zu tun hat.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:@BlackJack Ansonsten kann man natürlich auch beliebig viele Module haben die man importiert, statt den Quelltext `compile()` und `exec` zu verarbeiten. Da ist kein relevanter Unterschied zum Importieren. Höchstens irgendwelche eingebildeten Speicherprobleme. Was aber mit dem Problem in diesem Thema hier wieder so rein gar nichts zu tun hat.
Da gibt es doch zwei nennenswerte Unterschiedie. Denn was im Mainscript steht oder was man importiert sind globale Definitionen und die soll man vermeiden. Und der andere Unterschied ist eine mehr als nur temporäre Existenz. Erwartet wird, dass lokale Variablen oder Objekte nach einem Funktionsaufruf im Garbage Collector entsorgt werden sofern man sie nicht durch Referenzierung an länger bestehen bleibende Objekte knüpft.

Und ein Import verletzt vollständig das Prinzip, möglichst keine globalen Definitionen zu haben. Denn was man importiert ist nachher auch aufrufbar.- Soll es aber nicht sein.

Vielleicht habe ich ja etwas übersehen. Gibt es vielleicht einen sonstigen Pythonbefehl, mit dem man in den Garbage Collector importieren kann?
Sirius3
User
Beiträge: 18051
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: Du bringst mal wieder grundsätzlich Verschiedenes durcheinander. Globale Definitionen darf man so viele haben, wie man braucht. Globale Variablen sollte man vermeiden, weil sie Code schwerer Lesbar machen und Abhängigkeiten entstehen, die beim Testen oder Wiederverwenden von Code stören.
Dagegen sollten Funktions-/Klassendefinitionen immer global sein, und nicht irgendwo lokal in einer Funktion, da lokale Funktionen das Testen oder Wiederverwenden von Code verhindern.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sirius3 Da sehe ich jetzt aber keinen Unterschied zwischen einer Variablen und einer Funktion. Wenn wir einmal von primitiven Datentypen absehen, dann ist es egal ob man eine Referenz auf ein Objekt hat oder eine Funktion, die eine Referenz auf ein Objekt liefert. Man kann das eine genauso wie das andere benutzen, nur dass man bei der Funktion die runden Klammern nicht vergessen sollte.

Immerhin bin ich jetzt etwas beruhigt. Hatte mir schon überlegt, dass ja auch built in Functions globale Definitionen sind und ob man da nicht auch die gleich herauslöschen sollte, die man nicht braucht.

Außerdem verstehe ich nicht die Voreingenommenheit gegen exec und compile. Da mag ja die Befürchtung bestehen, dass solche Scripte etwas Bestehendes modifizieren könnten. Aber da gibt es ganz einfache Lösungen. Wenn man weder eine Variable noch eine Funktion definiert, kann so ein Script auch nicht darauf zugreifen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Es bringt natürlich auch nichts, irgendwelche Prinzipien verfechten zu wollen. Wenn man den Standpunkt vertritt, dass man keine globalen Strukturen haben sollte und dann bei tkinter die Children Listen löscht, hat man dann eben keine Widgets.

Wenn man denkt, dass man nichts Globales haben sollte und dann das Main Script leer läßt, hat man kein Programm. Wenn man denkt, dass beim Aufruf von Python mit Scriptangabe ja ein read, compile und exec stattfindet und man compile und exec nicht will und deshalb am Besten kein Script aufruft, dann bleibt nur noch direktes Eintippen, aber auch eine Befehlszeile wird mit compile und exec ausgeführt. Dann bleibt nur noch, ganz auf Python verzichten, damit man ja kein compile und exec hat.

Ach so, sofern nicht compile und exec draufsteht, darf man es anscheinend doch verwenden?
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Alfons: Wie auch im Python Zen steht, sollte man immer einen offensichtlichen Weg zur Verfügung haben, etwas zu tun. Und für das Nutzen von Modulen ist das schlicht und ergreifend ``import``!

Aber das Thema hatten wir doch eigentlich abgehakt, oder?
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

@Hyperion Nutzen von Modulen, was habe ich davon? Wenn ich in meinem 'Modul' außer Definition von Widgets lediglich eine Callbackroutine für einen Close Button habe, den eigentlich nur der User drücken soll, was soll ich damit anfangen? Soll ich die jetzt von meinem Mainscript aus aufrufen, ohne dass jemand drückt?

Ich erwarte eigentlich, dass, wenn der User den Close Button drückt, sowohl die Widgets als auch die Callback Routine in den Garbage Collector wandern. Und so werden die Widgets gelöscht, doch die dann ohne Widgets unbrauchbare Callback Funktion bleibt bestehen.

Kein Mensch kommt etwa bei HTML auf den verrückten Gedanken, dass es nur eine HTML Seite geben darf und weitere HTML Seiten als Module zu implementieren wären.

Und dann geht es natürlich auch um Programmsicherheit. Was man als Modul importiert, kann auch aufgerufen werden. Nein, Aufruf von außen darf es nicht geben, wo käme man dahin. Und solche unsichere Dinge wie hier darf es natürlich auch nicht geben:

Code: Alles auswählen

def function_a():
    ....

def function_b():
    ....
    function_a()
    ....
Hier ruft die funktion_b einfach eine function_a auf. Was außerhalb von function_b ist, geht function_b überhaupt nichts an und dass diese einfach function_a aufruft, ohne dass man sich das reichlich überlegt hat und dann speziell die function_a der function_b bekannt gemacht hat, darf nicht sein. Da könnte ja wer weiß etwas passieren.
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

@Alfons: Mach dich doch nicht dümmer als Du bist! Den Sinn von Modulen kann man nicht ernsthaft anzweifeln, selbst Dir glaubt das niemand! Du willst doch nur wieder einmal Deinen geradezu perversen Irrweg anpreisen, der schon so oft als solcher entlarvt worden ist.

Das Python Zen reicht dafür hier schon vollkommen aus! Der Standardweg Module zu benutzen ist ``import``. Simpel, elegant und offensichtlich.

Wer sich konsequent dagegen wehrt, muss ein masochistisch motiviertes Vergnügen haben, ständig gegen eine Sprache zu arbeiten statt mit ihr. Das darf natürlich jeder tun, aber bitte still und leise - und nicht permanent in jedem Thread, der eine Anknüpfung so halbwegs zulässt :!:
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

@Hyperion Anscheinend hast Du nicht verstanden, dass es hier nicht um Module geht, sondern um Scripte. Also nicht um Libraryfunktionen die man aufrufen kann oder soll. Ein kleines Bespiel für so ein Script etwa ist dieses:

Code: Alles auswählen

Toplevel('HelpSaveLoad',link='guidesigner/HelpSaveLoadContent.py')
Was fange ich jetzt damit an, wenn ich es als Modul importiere? Dieses Script etwa erzeugt ein Toplevel Window und lädt es mit dem Inhalt aus einem anderen Script.

Dass man es so schreiben muss, habe ich jetzt nicht implementiert:

Code: Alles auswählen

Toplevel('HelpSaveLoad',link='file://guidesigner/HelpSaveLoadContent.py'
Ich denke, auch wenn man 'file://' nicht schreibt, sollte dennoch daraus ersichtlich sein, dass es sich nicht um 'http://' handelt.
Zuletzt geändert von Alfons Mittelmeyer am Mittwoch 4. November 2015, 21:02, insgesamt 2-mal geändert.
Üpsilon
User
Beiträge: 225
Registriert: Samstag 15. September 2012, 19:23

Alfons Mittelmeyer hat geschrieben:@Hyperion Anscheinend hast Du nicht verstanden, dass es hier nicht um Module geht, sondern um Scripte. Also nicht um Libraryfunktionen die man aufrufen kann oder soll.
Das hatten wir doch schon mal!!! http://www.python-forum.de/viewtopic.ph ... o&start=15 Ich kenne ein Forum, da gibt es einen animierten Smiley, der den Kopf gegen die Wand schlägt, den bräuchte ich jetzt.
Und wenn es keine Funktion ist, dann benutz doch den altbekannten Trick mit if __name__ == "__main__": main() und den ganzen code in die Main-Funktion. Dann kannste dein Modul/Script als beides benutzen. Das hatten wir doch aber auch schon mal.
PS: Die angebotene Summe ist beachtlich.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

Und wenn man auch Webinhalte im Visier hat, dann muss dringendst davon abgeraten werden, diese automatisch als Module zu importieren. Vielmehr geht es darum, die Rechte genau festzulegen und sicherheitsrelevante Funktionen dafür zu löschen.
Benutzeravatar
kbr
User
Beiträge: 1494
Registriert: Mittwoch 15. Oktober 2008, 09:27

Alfons hat völlig recht. Da alles ein Objekt ist, müllen ungebrauchte builtins und wilde Importe den Speicherraum zu; keiner bekommt diese ungewünschte Speicherokkupation wieder ordentlich aufgeräumt. Die del-Anweisung und der Garage-Collector entziehen sich jeder vernünftigen Kontrolle. Überhaupt ist das import-Statement in dieser Hinsicht ein totales Antipattern; das ist bei dem Entwurf von Python nicht richtig durchdacht worden; waren die Entwickler eigentlich komplett bekifft? Alles Schrott. Das import-Statement sollte ab Python 4.0 als deprecated eingestuft werden.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Alfons bitte hoere endlich damit auf in fremden Threads ungefragt von `eval`, globalen Variablen, Namen loeschen & co anzufangen.
Ich bin es schon seit langem leid und ich glaube nicht, dass ich damit allein stehe.

Danke.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@Sorry cofi, bin ich es denn, der damit ständig anfängt und der das dann weiter austreten will? Hab ich das etwa geschrieben?
@Alfons Mittelmeyer: Das was Du da schreibst hat nichts mit dem ja nun bereits gelösten Problem zu tun. Und Probleme die man durch `compile()` und `exec` bekommt behebt man ganz einfach in dem man `compile()` und `exec` nicht benutzt.
Und mit Speicherproblemen hat das zwar auch zu tun aber auch mit völlig unsinnigen Forderungen und mit erheblichen Sicherheitsrisiken. Mal schon darüber nachgedacht, welche Sicherheitsrisiken import birgt?

Davon abgesehen hat kbr auch nicht unrecht, wenn auch nicht alles stimmt, denn was del macht und der Garbage Collector ist genau definiert. Aber del brauche ich nicht zu benützen, denn der Garbage Collector erledigt bereits alles zu meiner Zufriedenheit. Man braucht ihm nur die Gelegenheit dazu zu geben.
Und anscheinend wollen ihn die meisten gar nicht erst ranlassen. Im Mainscript etwa steht ein mainloop. Da steht es auch mit recht, aber dadurch kann das Script nicht zu Ende kommen und der Garbage Collector auf das im Mainscript Definierte auch nicht wirksam werden.
Anderes importiert man als Module und damit ist das global definiert und bleibt bis zum Programmende bestehen und auch da kommt dann der Garbage Collector wieder nicht zum Zuge.

Auf das, was der Garbage Collector zugreift, ist lokal Definiertes. Lokal Definiertes bekommt man, indem man eine Funktion schreibt und die dann aufruft. Und wenn die Funktion dann zuende ist, werden die lokalen Variablen und Objekte entsorgt, sofern sie nicht an etwas Global Definiertes gebunden wurden.
Wahrscheinlich kein großes Geheimnis für alle.

Idealerweise sollte man so eine Funktion schreiben:

Code: Alles auswählen

def load_script(filename):
    exec(compile(open(filename, "r").read(), filename, 'exec'))

Hier wird nämlich ein Script geladen und ausgeführt und dann dem Garbage Collector übergeben. Wennn man nicht will, dass dieses Script auf etwas im Mainscript zugreifen soll, legt man diese Funktion am Besten in ein anderes Modul, welches man dann importiert.
Wenn man nicht will, dass so ein Script auf irgend etwas in diesem Modul zugreifen soll, schreibt man eben auch nichts anderes rein. Wenn man nicht will, das so ein Script load_script aufruft, dann kann man auch load_script aus dem globalen Namensraum dieses Modules beseitigen.
Wenn man nicht will dass so ein Script import und andere sicherheitsrelevanten Builtin Funktionen aufruft, kann man auch diese beseitigen.

Wenn man dagegen import benutzt, kann man gar nichts. Ein mit import importiertes Modul ist erstens global und kann zweitens tun, was ihm gefällt. Das aber gefällt mir gar nicht. Dann was etwas tun darf oder nicht darf will ich bestimmen und das nicht irgendeinem importierten Skript überlassen.

Und was ich auch nicht einsehe ist, dass man so unsinnige Sachen von mir will, wie dass ich import benutzen soll für Skripte, die außer Funktionsaufrufen nichts enthalten. Dass ich einfach nur dafür Module verbraten soll, damit direkt beim ersten Import Funktionsaufrufe ausgeführt werden, während die Module dann völlig leer sind und nichts mehr darüber hinaus enthalten.
Und wenn es ganz blöd kommt und jemand dann hundert Icons ungeschickt lädt, muss ich um eine GUI Seite zu laden, dann auch mal hundert Module verbraten. Da werden die sich ganz bestimmt sehr freuen, die dann aus Ihren Verzeichnissen ein paar Tausend Modulfiles immer hinterher herauslöschen dürfen.

Außerdem gibt es auch komplexere Seiten, die wirklich mal 50 Scripte, also 50 Module brauchen. Und manche enthalten dann auch noch Code. Für komplexere Seiten nimmt man bei HTML etwa Java Script. Da nimmt man dann eben Python. Und dann bleibt auch global definierter Garbage übrig, der nicht im Garbage Collector landet, wie er es eigentlich tun sollte.

Also das Ansinnen, dass ich import benutzen sollte, finde ich absolut unsinnig.
Benutzeravatar
kbr
User
Beiträge: 1494
Registriert: Mittwoch 15. Oktober 2008, 09:27

Alfons Mittelmeyer hat geschrieben:... hat kbr auch nicht unrecht ...
Geschieht mir vermutlich recht - hatte angenommen auf das Ironie-Smilie verzichten zu können.
BlackJack

@Alfons Mittelmeyer:
Alfons Mittelmeyer hat geschrieben:bin ich es denn, der damit ständig anfängt und der das dann weiter austreten will?
Ja, das bist Du, denn *Du* hast hier *wieder* mit dem `compile()` und `exec`-Unsinn angefangen und hörst nach mehreren Hinweisen nicht auf damit. In einem Thema was geklärt war und damit überhaupt nichts zu tun hat. Und *Du* hörst damit nicht auf, obwohl mehrere Benutzer das Thema weder hier noch sonst irgendwo *schon wieder* lesen wollen. Ist ja auch keine Diskussion mehr und es bringt auch keinen zusätzlichen Erkenntnissgewinn, sondern Du wiederholst den gleichen Unsinn wieder und wieder, bei dem sich erfahrene Python-Programmierer einfach nur an den Kopf fassen und sich schon wieder mal fragen ob Du so engstirnig und begriffsstutzig bist oder ein Troll, also Dummheit oder absichtliche Provokation.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@BlackJack, wer hat da nicht aufgehört und hat dann import propagiert? Du magst ja die Überzeugung haben, dass compile und exec Unsinn wären. Aber wann import dann der weitaus größere 'Unsinn' ist, das solltest Du mal versuchen zu verstehen.
Antworten