Bekomme imp.reload nicht hin

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

Da man ständig sagt, compile und exec soll man nicht nehmem, habe ich imp.reload probiert. Aber irgend erwas mache ich wohl falsch. Kann jemand helfen?

Code: Alles auswählen

import imp

def writefile(code):
	handle = open("temp.py",'w')
	handle.write(code)
	handle.close()

code="def main():print('test import')"
writefile(code)

modulid = __import__('temp')

def comp_exec(code):
	global modulid
	writefile(code)
	modulid = imp.reload(modulid)
	import temp
	temp.main()

def main():

	code="def main(): print('Call number 1')"
	comp_exec(code)

	code="def main(): print('Call number 2')"
	comp_exec(code)

main()
Es kommt immer nur das:

Code: Alles auswählen

test import
test import
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Die Kritik deinem Code gegenüber ist dagegen gerichtet Code zur Laufzeit zu generieren und auszuführen. Ob du dies mit compile/exec machst oder Module generierst und über das Importsystem ausführst macht keinen wesentlichen Unterschied und ändert auch an der Kritik nichts.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

DasIch hat geschrieben:Die Kritik deinem Code gegenüber ist dagegen gerichtet Code zur Laufzeit zu generieren und auszuführen. Ob du dies mit compile/exec machst oder Module generierst und über das Importsystem ausführst macht keinen wesentlichen Unterschied und ändert auch an der Kritik nichts.
Wenn es das ist, muss ich nicht nach einer imp.reload Lösung suchen. Nur weiss ich dann nicht, was man eigentlich will. Das wäre etwa tkinter Code:

Code: Alles auswählen

### NAME NewName
NewName = Entry(parent)
NewName.grid(row=1,colum=1,columnspan=2)
Ist nicht schlecht normalen Code ohne zusätzliche Libraries zu haben. Nur hier muss man die Callbacks im selben Modul machen, weil es nachher keinen Zugriff mehr gibt. Allerdings, wenn ich die Kommentarzeile: ' ### NAME NewName' durch eine Funktion ersetze, dann hat man Zugriff auch noch später, wenn die GUI aufgebaut ist. Die Geschäftslogik will man ja von der GUI trennen. Soll man sie nicht trennen können, oder will man auf normales tkinter ohne zusätzliche Library verzichten? Oder muss ich mehrere Arten von Source Code anbieten?
pyseidon
User
Beiträge: 19
Registriert: Donnerstag 24. September 2009, 20:25

Kommentier mal Zeile 8 und 9 aus und nach Zeile 16 machst du ein `print modulid`. Schau Dir mal die Ausgabe an, vielleicht kommst Du dann drauf.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

pyseidon hat geschrieben:Kommentier mal Zeile 8 und 9 aus und nach Zeile 16 machst du ein `print modulid`. Schau Dir mal die Ausgabe an, vielleicht kommst Du dann drauf.
Zeile 8 und 9 auskommentieren funktioniert natürlich nicht. Denn dann habe ich kein modul temp und bekomme eine Fehlermeldung.

Interessant is folgendes. Wenn ich bereits ein Modul temp.py habe. Das macht das Programm ja beim ersten Durchlauf und wsenn ich dann am Anfang gleich schreibe:

Code: Alles auswählen

import imp
import temp
dann macht das Programm genau einmal einen imp.reload, denn es kommt dann das:

Code: Alles auswählen

Call number 1
Call number 1
Jetzt habe ich es rausgefunden, wie es geht, wenn man nämlich vor dem Funktionsaufruf einbaut:

Code: Alles auswählen

time.sleep(1)
Jetzt hört bloss bitte mit dem Krampf aus, dass compile und eval unsicher wären. Hat bisher immer einwandfrei und zuverlässig funktioniert. Aber das mit imp.reload, das ist so etwas von wacklig - kompiliert wahrscheinlich im Background -, dass man es schleunigst vergessen sollte. Oder wie lange soll man warten, ist das spezifiziert?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons Mittelmeyer:
eval und compile sind nicht unsicher, sondern der injizierte Code könnte es sein. Wenn Du sicherstellen kannst, dass der Code 100%ig zum aktuellen Zustand Deines Programmes passt, ist alles knorke. Das dicke Aber ist leider, dass man das meistens nicht ohne beträchtlichen Aufwand sicherstellen kann. Daher Finger weg von eval & Konsorten.
BlackJack

@Alfons Mittelmeyer: CPython erkennt ein geändertes Modul an dem Zeitstempel der Datei. Nur wenn der von der *.py-Datei sich von dem der *.pyc-Datei unterscheidet wird auch neu kompiliert. Ansonsten wird die *.pyc-Datei geladen.

Der ``import`` in `comp_exec()` macht keinen Sinn denn der liefert genau den selben Wert der auch schon an `modulid` gebunden ist. Über *den* Namen solltest Du vielleicht noch mal nachdenken, denn ein Modul-Objekt würde ich nicht unbedingt als ID bezeichnen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

BlackJack hat geschrieben:Der ``import`` in `comp_exec()` macht keinen Sinn denn der liefert genau den selben Wert der auch schon an `modulid` gebunden ist.
Und wie bekomme ich dann den Namensraum? Ohne import kennt das Programm temp.main() nicht
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

jerch hat geschrieben:@Alfons Mittelmeyer:
eval und compile sind nicht unsicher, sondern der injizierte Code könnte es sein. Wenn Du sicherstellen kannst, dass der Code 100%ig zum aktuellen Zustand Deines Programmes passt, ist alles knorke. Das dicke Aber ist leider, dass man das meistens nicht ohne beträchtlichen Aufwand sicherstellen kann. Daher Finger weg von eval & Konsorten.
Natürlich ist sicher, dass es mit eval und compile paßt. Ohne das müßte ich meine 24 Module zu einem Modul mit 3000 Zeilen vereinen. Damit wäre der Code total unübersichtlich. Außerdem bräuchte ich vielleicht noch 10 verschiedene Varianten davon, um mal dieses oder jenes tun zu können. Und das ist etwas was ich wirklich nicht tun sollte. Das wäre beträchtlicher Aufwand, wäre schier unüberschaubar und da ist meine Meinung, bloß Finger weg von so etwas.
Benutzeravatar
cofi
Python-Forum Veteran
Beiträge: 4432
Registriert: Sonntag 30. März 2008, 04:16
Wohnort: RGFybXN0YWR0

Alfons Mittelmeyer hat geschrieben:Ohne import kennt das Programm temp.main() nicht
Da du aber nicht nur eine Id hast, sondern das komplette Modul, funktioniert `modulid.main()`.

Also wenn deine Codebase nur dann testbar ist, wenn der Code in eigenen Modulen steht, dann laeuft was falsch.
Dass 3000 Zeilen unuebersichtlich sein koennen kann ich durchaus nachvollziehen, aber nicht den Einfluss auf die Testbarkeit.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

cofi hat geschrieben:
Alfons Mittelmeyer hat geschrieben:Ohne import kennt das Programm temp.main() nicht
Da du aber nicht nur eine Id hast, sondern das komplette Modul, funktioniert `modulid.main()`.

Also wenn deine Codebase nur dann testbar ist, wenn der Code in eigenen Modulen steht, dann laeuft was falsch.
Dass 3000 Zeilen unuebersichtlich sein koennen kann ich durchaus nachvollziehen, aber nicht den Einfluss auf die Testbarkeit.
Wie kommst Du jetzt darauf, dass das Programm nur testbar wäre, wenn es in Module aufgeteilt ist? Davon hatte ich nichts geschrieben. Ich hatte nur geschrieben, dass es dann unübersichtlich wäre. Das andere ist, dass ich auch Codemodifikationen brauche. Und 10 Codevarianten zu haben, um dieses und jenes zu tun anstatt den Code nach dem Laden zu modifizieren, macht die ganze Sache dann bald nicht mehr wartbar.
Sirius3
User
Beiträge: 17750
Registriert: Sonntag 21. Oktober 2012, 17:20

@Alfons Mittelmeyer: Du verschwendest viel zu viel Zeit mit Details, die keinen Nutzen bringen. Dir sollte doch klar sein, dass eine Zeile exec besser ist, als 10 Zeilen mit temporären Dateien und einem reload. Das ist das selbe, wie damals, als wir gesagt haben, "del ist schlecht" und Du angefangen hast, den selben Effekt viel komplizierter mit pop zu erreichen. Es geht nicht um den einzelnen Befehl, sondern das Konzept das dahinter steht. Wenn Du eine GUI verändern willst, dann generierst Du keinen Python Code der die GUI ändert, sondern änderst die GUI direkt. Wenn Du Dein Programm dynamisch erweitern willst, dann liegen die Erweiterungen schon als fertige py-Module vor und Du kannst sie einfach mit import einbinden, ohne etwas neues erfinden zu müssen. Es gibt genug Beispiele für gelungene Plugin-Systeme, schau Dir an, wie es dort gelöst wurde.

Kein Mensch weiß hier, was Du mit 10 Variationen von 24 Modulen meinst. Mach endlich mal ein konkretes Beispiel, das lauffähig ist, das die Konzepte enthält, wie Du sie meinst umsetzen zu müssen und dann werden wir ziemlich schnell sehen, was Du tatsächlich willst, und wie man das ganze viel sauberer umsetzen kann. Gegen quick-and-dirty-Lösungen ist ja nichts einzuwenden, wenn man sich damit auf den Kern des Problems hinbewegt und dadurch eine schöne Lösung findet. Aber dieses ewige nebulöse Herumgeeiere bringt niemand etwas.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons Mittelmeyer:
Wenn Du was Modifizierbares mit Python brauchst, musst Du die Sache anders angehen. Python ist von der Maschine wegabstrahiert, daher werden alle "Wie komm ich an den Speicher ran oder kann den wiederfreigeben?"-Versuche mit Frust oder furchtbaren Krücken enden. Beispiele dafür hast Du schon genug geliefert. Wenn Du so low level rangehen willst, dann nimm eine Sprache, welche dafür ausgelegt ist.

Wenn Du Python als "Baukasten" für den Anwender erhalten willst, geht es nur mit einer Bibliothek - heisst Du hältst Primitive für alles Mögliche vor und vertraust darauf, dass der Anwender programmieren kann und die Bibliothek richtig einsetzt. Mit diesem Ansatz bist Du in guter Gesellschaft, alle großen Drittbibliotheken funktionieren nach diesem Prinzip.

Wenn Du nicht auf die Programmierkünste der Anwender vertrauen kannst, hilft nur ein Pluginsystem, welches die Freiheitsgrade der Aktionen genau festklopft.

Bei letzterem Ansatz kannst Du dann auch die "Langlebigkeit" steuern, bei ersterem nicht.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

jerch hat geschrieben:@Alfons Mittelmeyer:
Wenn Du was Modifizierbares mit Python brauchst, musst Du die Sache anders angehen. Python ist von der Maschine wegabstrahiert, daher werden alle "Wie komm ich an den Speicher ran oder kann den wiederfreigeben?"-Versuche mit Frust oder furchtbaren Krücken enden. Beispiele dafür hast Du schon genug geliefert. Wenn Du so low level rangehen willst, dann nimm eine Sprache, welche dafür ausgelegt ist.
@jerch, das mit dem Speicher hat sich längst erledigt. Meine Scripte bestehen jetzt aus einer Funktion main() und nichts noch extra. Damit ist dann alles lokal und das Speicherthema interessiert mich deshalb nicht mehr.
jerch hat geschrieben:Wenn Du Python als "Baukasten" für den Anwender erhalten willst, geht es nur mit einer Bibliothek - heisst Du hältst Primitive für alles Mögliche vor und vertraust darauf, dass der Anwender programmieren kann und die Bibliothek richtig einsetzt. Mit diesem Ansatz bist Du in guter Gesellschaft, alle großen Drittbibliotheken funktionieren nach diesem Prinzip.
Speziell habe ich eine Biblothek mit einer Erweiterung für tkinter gemacht. Der Anwender braucht davon nur ein paar Interface Funktionen, da die GUI durch einen GUI Designer erstellt wird. Viele Funktionen dieser Bibliothek braucht dagegen der GUI Designer.
jerch hat geschrieben:Wenn Du nicht auf die Programmierkünste der Anwender vertrauen kannst, hilft nur ein Pluginsystem, welches die Freiheitsgrade der Aktionen genau festklopft.

Bei letzterem Ansatz kannst Du dann auch die "Langlebigkeit" steuern, bei ersterem nicht.
Die Bibliothek, die ich habe erlaubt unbegrenztes Nachladen von Python Scripten, so wie man auch mit einem Webbrowser soviel Seiten aufrufen kann wie man will. Die Idee ist auch, tkinter GUI Anwendungen in einem Fenster laufen zu lassen und auch immer welche nachladen zu können, so wie man mit einem Webbrowser surft. Allerdings der Webbrowser ist gesichert gegen Unsinn. Mein System bisher nicht:

Code: Alles auswählen

def main(parent):

    # das dürfte jemand noch machen und dabei seine in einem Fenster laufende Anwendung beenden.
    parent.destroy()

    # aber das sollte niemand tun, denn das würde ja Zerstörung eines 'Browser'-Teils bedeuten
    parent.master.destroy()
Also wenn man vor hat, so etwas wie einen Python tkinter Script Browser zu machen, müßte man ihn gegen Zerstörung und sonstigen Unfug schützen.

Aber so einfach ist das nicht. Da müßte man sich etwas anderes überlegen, und den sogenannten 'Browser' eventuell gar nicht in Python und tkinter programmmieren, damit es da keinerlei Zugriff gibt. Oder kann man sonst ein Python GUI Fenster in einem anderen Python GUI Fenster anzeigen, wenn es am Besten eigenständige getrennte Anwendungen sind?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Alfons Mittelmeyer:
Das ist doch ein Widerspruch in sich - Du kannst nicht dem Anwender die größtmögliche Freiheit geben (sprich Pythoncode direkt ausführen lassen) und auf der anderen Seite die Kontrolle behalten wollen. Da ist auch egal ob der Code per eval, compile, Modul oder Spracheingabe angeflogen kommt. Der Vergleich mit Browsern ist müßig - da sind Jahre von sandboxing-Erfahrung reingeflossen und trotzdem zeigt sich immer wieder die ein oder andere Lücke.

Du suchst ein Pluginsystem, wo der Anwender nur sehr eingeschränkt vordefinierte Aktionen machen kann. Da die eigentliche Aktion von Deinem Plugin-Code ausgeführt wird, behältst Du die Kontrolle. Das geht prima mit einem GUI-Interface. Oder falls es unbedingt ein Editorinterface sein muss, dann brauchst Du eine eigene Sprache (DSL reicht wahrscheinlich). Dann bist Du Herr des globalen Zustandes. Mit Python als Interfacesprache innerhalb eines Interpreters wird das nichts.

Edit:
Dir ist natürlich freigestellt, den eingefügten Pythoncode eben nicht im Kontext des Standardinterpreters auszuwerten, z.B. selbst Parsen oder per Subprozess. Damit wäre der Zustand Deiner Hauptanwendung sicher. Dann musst Du aber andere Probleme lösen, z.B. IPC im Falle von Subprozessen.
Alfons Mittelmeyer
User
Beiträge: 1715
Registriert: Freitag 31. Juli 2015, 13:34

@jerch Ich würde mal sagen World Wide Web auf Python Basis ist keine gute Idee. Denn die Scripte könnten jeden Unsinn anstellen. Geprüfte Scripte, die sich an Vorgaben halten, dagegen wären möglich. Nur wer soll das kontrollieren, wenn man das nicht nur an einer Stelle tut, die auf diese Kriterien achtet, sondern wenn auch andere dasselbe tun, aber nicht darauf achten? Bei Java Script und Java Applets dagegen sollte gewährleistet sein, dass keine unerwünschten Zugriffe auf den Computer erfolgen.

Naja, GUI Widget Definitionen könnte man wohl auch für JAVA konvertieren. Aber was ist mit dem Python Code dazu? Python auf JAVA umparsen, dazu habe ich keine Lust. Aber es gibt ja wohl auch JPython, gibt es das auch für JAVA Applets?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Ich weiss nicht, wo du mit der Webdiskussion hin willst. Python hat sehr wohl seinen Platz im Web (vorallem serverseitig), aber nicht als Austauschformat oder im clientseitigen Einsatz. Letzteres ist eher historisch gewachsen und von Javascript beansprucht. Python ist hierfür ebenso (un-)geeignet wie Javascript, bräuchte aber einen modifizierten Interpreter.
Alfons Mittelmeyer hat geschrieben:Denn die Scripte könnten jeden Unsinn anstellen.
Soso. Wenn Du es jetzt noch schaffst, diesen Gedanken auf die eval-Problematik zu übertragen, dann hat diese Diskussion vllt. doch noch was gebracht.
Alfons Mittelmeyer hat geschrieben:Geprüfte Scripte, die sich an Vorgaben halten, dagegen wären möglich. Nur wer soll das kontrollieren, wenn man das nicht nur an einer Stelle tut, die auf diese Kriterien achtet, sondern wenn auch andere dasselbe tun, aber nicht darauf achten?
Jein. Skripte, die sich an die Vorgaben halten, sind immer gefahrlos möglich. So wie Du es schreibst, steht und fällt es aber mit der Prüfung und das ist falsch bzw. Augenwischerei. Die Prüfung ist nur Teil der Wahrheit, viel schwerwiegender ist das Problem der Vertrauenswürdigkeit. Kann ich der Prüfung trauen? Kann ich dem Prüfer trauen? Kann ich dem Vermittler trauen? Ist die Signatur noch gültig? Wie kann ich das *sicher* prüfen? Das gilt für alle Software/Datenformate, welche Du von extern beziehst. Die Tatsache, dass Python skriptbasiert ist, senkt hier nur die Einstiegshürde für Angreifer.
Alfons Mittelmeyer hat geschrieben:Bei Java Script und Java Applets dagegen sollte gewährleistet sein, dass keine unerwünschten Zugriffe auf den Computer erfolgen.
Und wogegen willst Du Deine Anwendung schützen? Das ist doch analog.
DasIch
User
Beiträge: 2718
Registriert: Montag 19. Mai 2008, 04:21
Wohnort: Berlin

Der Underhanded C Contest zeigt sehr deutlich dass die Idee man könnte Code überprüfen und sicherstellen dass dieser vertrauenswürdig ist, vollkommen realitätsfern ist.
Antworten