Bei der Instantiierung einer Funktion Code ausführen

Guten Morgen,
ich Beschäftige mich gerade mit mit den Internas von Python Funktionen. Beim Nachdenken über Funktionen, habe ich mich gefragt, ob man Code beim erzeugen einer Funktion unbemerkt ausführen kann. Klinkt jetzt ein bisschen verworren, deshalb hier ein Beispiel:
s = """ def printer(): print("Böse Funktion: ", dir()) """
Diese Funktion liegt als String vor und wenn ich jetzt aus dem String mit exec eine Funktion erzeuge (Instantiiere (?)) habe ich eine Funktion printer im aktuellen Namensraum. So lange ich diese Funktion nicht aufrufe, passiert nichts, rufe ich Sie auf passiert was. Ist es jetzt eigentlich möglich, das bei der Erzeugung (exec(s) genau jetzt), also noch vor dem Aufrufen der selbigen, Schadcode ausgeführt werden kann?
Ich hoffe das klingt jetzt nicht zu bizarr.
Mit freundlichen Grüßen
Albert

Hallo Albert,
Am 08.12.12 10:40, schrieb Albert Hermeling:
Guten Morgen,
ich Beschäftige mich gerade mit mit den Internas von Python Funktionen. Beim Nachdenken über Funktionen, habe ich mich gefragt, ob man Code beim erzeugen einer Funktion unbemerkt ausführen kann. Klinkt jetzt ein bisschen verworren, deshalb hier ein Beispiel:
s = """ def printer(): print("Böse Funktion: ", dir()) """
Diese Funktion liegt als String vor und wenn ich jetzt aus dem String mit exec eine Funktion erzeuge (Instantiiere (?)) habe ich eine Funktion printer im aktuellen Namensraum. So lange ich diese Funktion nicht aufrufe, passiert nichts, rufe ich Sie auf passiert was. Ist es jetzt eigentlich möglich, das bei der Erzeugung (exec(s) genau jetzt), also noch vor dem Aufrufen der selbigen, Schadcode ausgeführt werden kann?
Die Funktion wird erst beim Aufruf ausgeführt. Kannst aber garantieren, dass nicht auch außerhalb der Funktion Anweisungen kommen? Zum Beispiel:
s = """ print('haha') def printer(): print("Böse Funktion: ", dir()) """
Generell würde ich `exec` nur in sehr seltenen Fällen nehmen. Es gibt fast immer eine andere, oft bessere, Lösung. Kannst du mal kurz erklären warum die Funktion als String vorliegt und was genau passieren soll. Dann bietet sich vielleicht eine andere Lösung an.
Viele Grüße Mike

Hallo,
On 2012-12-08 11:35, Mike Müller wrote:
Generell würde ich `exec` nur in sehr seltenen Fällen nehmen. Es gibt fast immer eine andere, oft bessere, Lösung.
das dachte ich auch - und denke ich tendenziell immer noch. Ich war aber überrascht, als ich neulich im `collections`-Modul sah, dass für `namedtuple` eine nicht ganz kleine Klasse mit `exec` erzeugt wird (ab http://hg.python.org/cpython/file/2.7/Lib/collections.py#l230 beziehungsweise konkret http://hg.python.org/cpython/file/2.7/Lib/collections.py#l362 .)
Als potenzielle Vorteile von `exec` sehe ich immerhin zum einen, dass die alternative Erzeugung einer größeren Klasse mit Inline-Definition(en) und/oder Aufbau eines Dictionaries für `type` recht unübersichtlich werden kann. Zum anderen dürfte es bei `exec` einfacher zu kontrollieren sein, was in welchen Namensräumen landet beziehungsweise als Variante, was der erzeugte Code noch alles an Referenzen auf seine Umgebung hält.
Fallen euch Situationen ein, in denen ihr von der Verwendung von `exec` nicht abraten, sondern sie sogar empfehlen würdet? Insbesondere würden mich Faustregeln dazu interessieren, so dass sich diese Fälle leichter auf eigenen Code übertragen lassen.
Viele Grüße Stefan

On 08.12.2012 15:18, Stefan Schwarzer wrote:
On 2012-12-08 11:35, Mike Müller wrote:
Generell würde ich `exec` nur in sehr seltenen Fällen nehmen. Es gibt fast immer eine andere, oft bessere, Lösung.
das dachte ich auch - und denke ich tendenziell immer noch. Ich war aber überrascht, als ich neulich im `collections`-Modul sah, dass für `namedtuple` eine nicht ganz kleine Klasse mit `exec` erzeugt wird
Die Verwendung von exec für "namedtuple" ist eine Geschwindigkeits-Optimierung, und die sind ja oft nicht hübsch. Es gibt dazu auch ein (rejected) Ticket im Python-Roundup mit einer kurzen Diskussion.
http://bugs.python.org/issue3974
Ich habe das mal nachgemessen und mit der Implementierung ohne "exec" verglichen. Die Definierung der neuen namedtuple-Klasse ist dadurch zwar schneller aber die Instanzierung deutlich langsamer.
Chris

Hi Christopher,
On 2012-12-09 15:22, Christopher Arndt wrote:
On 08.12.2012 15:18, Stefan Schwarzer wrote:
On 2012-12-08 11:35, Mike Müller wrote:
Generell würde ich `exec` nur in sehr seltenen Fällen nehmen. Es gibt fast immer eine andere, oft bessere, Lösung.
das dachte ich auch - und denke ich tendenziell immer noch. Ich war aber überrascht, als ich neulich im `collections`-Modul sah, dass für `namedtuple` eine nicht ganz kleine Klasse mit `exec` erzeugt wird
Die Verwendung von exec für "namedtuple" ist eine Geschwindigkeits-Optimierung, und die sind ja oft nicht hübsch. Es gibt dazu auch ein (rejected) Ticket im Python-Roundup mit einer kurzen Diskussion.
nach der Argumentation dort ist es ja nicht nur die Geschwindigkeit, die für die Implementierungs-Variante mit `exec` spricht. Raymond Hettinger schreibt in einem Ticket-Kommentar, "Earlier versions used other approaches and they proved unnecessarily complex and had unexpected problems."
(Das heißt jetzt natürlich nicht _allgemein_, dass Lösungen mit `exec` generell besser sind. Wir hatten das ja schon so ähnlich zu `global` in diesem Thread: Dass es mitunter _keine_ gute Lösung ist, heißt nicht, dass es generell schlecht ist. Manchmal ist die Verwendung von `global` der sauberste Ansatz.)
Ich habe das mal nachgemessen und mit der Implementierung ohne "exec" verglichen. Die Definierung der neuen namedtuple-Klasse ist dadurch zwar schneller aber die Instanzierung deutlich langsamer.
Vielen Dank für den Benchmark!
Ich gehe davon aus, dass viel öfter Instanzen von von `namedtuple` abgeleiteten Klassen benutzt werden als die abgeleiteten Klassen anfänglich zu erzeugen. Von daher ist der Fokus auf die _Verwendung_ der erzeugten Klasse schon vernünftig. Natürlich hängt es zudem immer vom Einzelfall ab, ob so ein Benchmark-Ergebnis für eine bestimmte Python-Anwendung relevant ist. Es kann gut sein, dass die wenigsten Anwendungen von dem Geschwindigkeitsvorteil profitieren.
Viele Grüße Stefan

Ich glaube dem OP geht's weniger um exec. Sondern darum, ob Funktionsdefinitionen weitere Seiteneffekte haben können, die zur ausführung von Code führen.
Ich denke nicht - mit der Ausnahme von Dekoratoren natürlich.
Diez
Mobile Mail. Excuse brevity.
Am 08.12.2012 um 11:35 schrieb Mike Müller mmueller@python-academy.de:
Hallo Albert,
Am 08.12.12 10:40, schrieb Albert Hermeling:
Guten Morgen,
ich Beschäftige mich gerade mit mit den Internas von Python Funktionen. Beim Nachdenken über Funktionen, habe ich mich gefragt, ob man Code beim erzeugen einer Funktion unbemerkt ausführen kann. Klinkt jetzt ein bisschen verworren, deshalb hier ein Beispiel:
s = """ def printer(): print("Böse Funktion: ", dir()) """
Diese Funktion liegt als String vor und wenn ich jetzt aus dem String mit exec eine Funktion erzeuge (Instantiiere (?)) habe ich eine Funktion printer im aktuellen Namensraum. So lange ich diese Funktion nicht aufrufe, passiert nichts, rufe ich Sie auf passiert was. Ist es jetzt eigentlich möglich, das bei der Erzeugung (exec(s) genau jetzt), also noch vor dem Aufrufen der selbigen, Schadcode ausgeführt werden kann?
Die Funktion wird erst beim Aufruf ausgeführt. Kannst aber garantieren, dass nicht auch außerhalb der Funktion Anweisungen kommen? Zum Beispiel:
s = """ print('haha') def printer(): print("Böse Funktion: ", dir()) """
Generell würde ich `exec` nur in sehr seltenen Fällen nehmen. Es gibt fast immer eine andere, oft bessere, Lösung. Kannst du mal kurz erklären warum die Funktion als String vorliegt und was genau passieren soll. Dann bietet sich vielleicht eine andere Lösung an.
Viele Grüße Mike
python-de maillist - python-de@python.org http://mail.python.org/mailman/listinfo/python-de

Am 08.12.2012 11:35, schrieb Mike Müller:
Hallo Mike,
ups die Mail sollte eigentlich nur an die Liste geschickt werden und nicht nur an Mike Sorry.
Ich habe eine Anwendung geschrieben die es Erlaubt Daten Strukturiert zu speichern. Das für sich alleine ist überflüssig, dafür gibt es XML und noch einiges Andere. Die Anwendung kann deshalb noch einiges mehr. Ich möchte auf das "einiges mehr" nicht näher eingehen, das würde nicht zum Thema passen. Nur soviel sei gesagt, es handelt sich um Textdateien die von einem Parser verarbeitet werden. Die Daten selber werden in verschachtelten Objekten der Klasse 'SectionXXX' hierarchisch gespeichert. Es werden schon eine Reihe von Datentypen unterstützt, weitere sollen als Plug-in realisiert werden. Die Textdateien sind als "Scripte" anzusehen, sie werden von Programmieren geschrieben, die diese Bibliothek anwenden wollen. Sie sind somit genau so sicher oder unsicher wie jedes andere Python Script auch sein kann.
Meine Überlegung ist jetzt folgende, um Objeke der Klasse SectionXXX um Methoden zu ergänzen, sollen diese als Funktions-Strings in der zugrunde legenden Textdatei eingebettet werden. Dabei kann jede Sektion eigene spezielle Funktionen haben. Man braucht also nicht eigene Klassen von SectionXXX abzuleiten. Aus den Code Strings sollen per exec Funktions-Objekte erzeugt werden, diese sollen per sec1.sub1.myMethod = types.MethodType(myMethod, func) in ihre jeweilige Sektion eingefügt werden. Da ich die Textdateien als sicher ansehe, könnte ich jetzt einfach exec(string) aufrufen und das wer es gewesen. Aber wie ich nun mal bin, ich fange an Nachzudenken und dabei kam mir halt dieser Gedanke.
Die Funktion wird erst beim Aufruf ausgeführt. Kannst aber garantieren, dass nicht auch außerhalb der Funktion Anweisungen kommen? Zum Beispiel:
s = """ print('haha') def printer(): print("Böse Funktion: ", dir()) """
Vieleicht so:
def teste(s): l = s.strip().splitlines() func_line = l.pop(0) if not func_line.startswith("def ") and not func_line.endswith("):\n"): raise SyntaxWarning("Will ich nicht haben") for item in l: if not item.startswith(" "): raise SyntaxWarning("Will ich nicht haben") return s
Mit freundlichen Grüßen
Albert

Hallo Albert,
On 2012-12-08 22:01, Albert Hermeling wrote:
Ich habe eine Anwendung geschrieben die es Erlaubt Daten Strukturiert zu speichern. Das für sich alleine ist überflüssig, dafür gibt es XML und noch einiges Andere. Die Anwendung kann deshalb noch einiges mehr. Ich möchte auf das "einiges mehr" nicht näher eingehen, das würde nicht zum Thema passen. Nur soviel sei gesagt, es handelt sich um Textdateien die von einem Parser verarbeitet werden. Die Daten selber werden in verschachtelten Objekten der Klasse 'SectionXXX' hierarchisch gespeichert. Es werden schon eine Reihe von Datentypen unterstützt, weitere sollen als Plug-in realisiert werden. Die Textdateien sind als "Scripte" anzusehen, sie werden von Programmieren geschrieben, die diese Bibliothek anwenden wollen. Sie sind somit genau so sicher oder unsicher wie jedes andere Python Script auch sein kann.
Meine Überlegung ist jetzt folgende, um Objeke der Klasse SectionXXX um Methoden zu ergänzen, sollen diese als Funktions-Strings in der zugrunde legenden Textdatei eingebettet werden. Dabei kann jede Sektion eigene spezielle Funktionen haben. Man braucht also nicht eigene Klassen von SectionXXX abzuleiten. Aus den Code Strings sollen per exec Funktions-Objekte erzeugt werden, diese sollen per sec1.sub1.myMethod = types.MethodType(myMethod, func) in ihre jeweilige Sektion eingefügt werden. Da ich die Textdateien als sicher ansehe, könnte ich jetzt einfach exec(string) aufrufen und das wer es gewesen. Aber wie ich nun mal bin, ich fange an Nachzudenken und dabei kam mir halt dieser Gedanke.
werden diese eingelesenen Funktionen nicht in deinem Programm ausgeführt? Falls ja, klingt es für mich nicht sinnvoll, Seiteneffekte beim _Definieren_ der Funktionen zu vermeiden, wenn nachher beim _Ausführen_ der Funktion sowieso alles Mögliche passieren kann.
Was du beschreibst, macht zudem den Eindruck, als würdest du einen Teil der Funktionalität, die Python schon bietet, noch mal implementieren. So nett DSLs (domain-specific languages) auch scheinen mögen: Nach meiner Erfahrung handelt man sich mit deren Entwicklung und Einsatz oft einen relativ großen Aufwand (in Entwicklung und Fehlersuche) mit relativ wenig Zusatznutzen gegenüber "normalem" Python-Code ein.
Wenn die anderen Programmierer sich nicht mit Python auskennen, werden sie vermutlich lästige Fehler in ihrem Code einbauen. Wenn sie sich an dich wenden, darfst du unter Umständen diese Mischung aus DSL und dem anderen Code debuggen. Wenn die Programmierer dagegen erfahrener sind, werden sie voraussichtlich vorziehen, "ganz normales" Python zu schreiben, ohne sich Gedanken über abweichende Ausführungsmodelle machen zu müssen.
Fazit: Ich würde eher versuchen, ein Design zu entwickeln, dass sich gut in die normale Entwicklung mit Python einfügt.
Die Funktion wird erst beim Aufruf ausgeführt. Kannst aber garantieren, dass nicht auch außerhalb der Funktion Anweisungen kommen? Zum Beispiel:
s = """ print('haha') def printer(): print("Böse Funktion: ", dir()) """
Vieleicht so:
def teste(s): l = s.strip().splitlines() func_line = l.pop(0) if not func_line.startswith("def ") and not func_line.endswith("):\n"):
Das schließt auch Funktionen aus, bei denen die Argumentliste nicht komplett in einer Zeile steht:
def my_func(langer_bezeichner, noch_ein_langer_bezeichner, und_noch_einer): ...
(Nebenbei: `splitlines` entfernt die Zeilenende-Zeichen; `\n` sollte also nicht Bestandteil des Strings sein.)
raise SyntaxWarning("Will ich nicht haben") for item in l: if not item.startswith(" "): raise SyntaxWarning("Will ich nicht haben") return s
Mir fällt zumindest eine "legale" Variante ein, bei der der Funktionsblock nur teilweise eingerückt ist:
def my_func(): print """\ Erste Zeile Zweite Zeile"""
Das sieht natürlich nicht übersichtlich aus; daher ist es verständlich, wenn du "das nicht haben willst". ;-)
Viele Grüße Stefan

Am 09.12.2012 02:55, schrieb Stefan Schwarzer:
Hallo Stefan,
Hallo Albert,
On 2012-12-08 22:01, Albert Hermeling wrote:
Ich habe eine Anwendung geschrieben die es Erlaubt Daten Strukturiert zu speichern. Das für sich alleine ist überflüssig, dafür gibt es XML und noch einiges Andere. Die Anwendung kann deshalb noch einiges mehr. Ich möchte auf das "einiges mehr" nicht näher eingehen, das würde nicht zum Thema passen. Nur soviel sei gesagt, es handelt sich um Textdateien die von einem Parser verarbeitet werden. Die Daten selber werden in verschachtelten Objekten der Klasse 'SectionXXX' hierarchisch gespeichert. Es werden schon eine Reihe von Datentypen unterstützt, weitere sollen als Plug-in realisiert werden. Die Textdateien sind als "Scripte" anzusehen, sie werden von Programmieren geschrieben, die diese Bibliothek anwenden wollen. Sie sind somit genau so sicher oder unsicher wie jedes andere Python Script auch sein kann.
Meine Überlegung ist jetzt folgende, um Objeke der Klasse SectionXXX um Methoden zu ergänzen, sollen diese als Funktions-Strings in der zugrunde legenden Textdatei eingebettet werden. Dabei kann jede Sektion eigene spezielle Funktionen haben. Man braucht also nicht eigene Klassen von SectionXXX abzuleiten. Aus den Code Strings sollen per exec Funktions-Objekte erzeugt werden, diese sollen per sec1.sub1.myMethod = types.MethodType(myMethod, func) in ihre jeweilige Sektion eingefügt werden. Da ich die Textdateien als sicher ansehe, könnte ich jetzt einfach exec(string) aufrufen und das wer es gewesen. Aber wie ich nun mal bin, ich fange an Nachzudenken und dabei kam mir halt dieser Gedanke.
werden diese eingelesenen Funktionen nicht in deinem Programm ausgeführt? Falls ja, klingt es für mich nicht sinnvoll, Seiteneffekte beim _Definieren_ der Funktionen zu vermeiden, wenn nachher beim _Ausführen_ der Funktion sowieso alles Mögliche passieren kann.
Also ich möchte keine Seiteneffekte vermeiden, es ist Sache des Programmierers sich vorher Gedanken zu machen, was er mit den Daten in einer Sektion (und den Sub-Sektionen) tun möchte oder nicht. Schließlich, wenn der Programmierer eine "Normale Klasse" Foo schreibt und Methoden implementiert um die Daten zu bearbeiten, sollte er wissen was diese mit seinen Daten machen. Aber trotzdem wird es ein paar Restriktionen geben. Zum Beispiel dürfen die Schlüsselwörter class global import nicht vorkommen. Class nicht, weil es dafür das Plug-in System geben wird. Import nicht weil diese zentral über eine Config-Datei gesteuert werden und weil ich es nicht mag Imports in einer Klasse zu **verstreuen**. Global nicht, weil das schlechter Still ist und ich nicht x globale Variablen überall stehen haben will.
Was du beschreibst, macht zudem den Eindruck, als würdest du einen Teil der Funktionalität, die Python schon bietet, noch mal implementieren. So nett DSLs (domain-specific languages) auch scheinen mögen: Nach meiner Erfahrung handelt man sich mit deren Entwicklung und Einsatz oft einen relativ großen Aufwand (in Entwicklung und Fehlersuche) mit relativ wenig Zusatznutzen gegenüber "normalem" Python-Code ein.
Ich glaub jetzt muss ich mal ein kleines Beispiel bringen um das ganze etwas näher zu erläutern:
---Dateianfang---
DOCTYPE = "VERSION : 1.3.0, CHARSET : UTF8, ESC : !/" # Sprachversion und Kodierung;
[f # Normale Sektion f] in_f_1 = <"1" "2" "3"> # Das ist eine Python Liste; in_f_2 = ("10" "20" "30") # Das ist ein Python Tuple; in_f_3 = {"100" "200"} # Das ist ein Python Set [g # Normale Sektion g] in_g_1 = "Hallo Welt" # Ein String mit Leerzeichen ohne Umbruch; [SubS # Eine weitere Subsektion] namen = ("albert" "martin" "heinz"); text = """Das hier ist Text der einen Zeilenumbruch enthält. Der wird von drei ' oder " Umschlossen """ # Leerzeichen links von " werden automatisch entfernt; hallo = "Hallo Erde "; printer = |printer""" def printer(self, multiplikator): print(self.hallo * multiplikator) """ # Geplannt: Embedded Code; finePrinter = ||Printer"""((arg1, arg2), {kw1 = "foo", kw2 = "bar})""" # Geplannt Plug-in; [/SubS] [/g] [h ("datatype : int") # Sektion h die nur Zahlen enthält] # Enthalten die Daten (rechts vom Gleichheitszeichen) keine # Leerzeichen können die Anführungszeichen weggelassen werden a = 1; b = 2; c = 3; e = 4; f = (1 2 3 4) # Container mit Zahlen sind erlaubt; [/h] [/f]
---Dateiende---
Eingelesen wird die Datei so obj = poc_read("test.poc")
Auf die Attribute greift man so zu:
obj.f.in_f_1,
oder so
x = getattr(obj, "f.g.SubS.namen")
Attribute können so neu belegt werden:
obj.f.in_f_1 = "Neuer Wert"
aber auch so:
obj.f.newAttribute("Neuer Wert", "Mit Kommentar")
aber auch so:
setattr(obj, "f.g.SubS.name", ("foo", "bar", "egg"))
Sektionen werden so angelegt:
obj.f.newSection("Foobar", "Sektion Foobar", datatype = "txt")
Gespeichert wird die POC-Hierarchie so:
poc_write(obj)
Erstellen kann man eine POC-Hierachie per Hand oder per poc_new die genaue Syntax erspare ich mir hier mal.
Was ist daran so Unpythonisch das ein Programmierer das nicht anwenden kann wenn er es denn will! ;-)
Wenn die anderen Programmierer sich nicht mit Python auskennen, werden sie vermutlich lästige Fehler in ihrem Code einbauen. Wenn sie sich an dich wenden, darfst du unter Umständen diese Mischung aus DSL und dem anderen Code debuggen. Wenn die Programmierer dagegen erfahrener sind, werden sie voraussichtlich vorziehen, "ganz normales" Python zu schreiben, ohne sich Gedanken über abweichende Ausführungsmodelle machen zu müssen.
Also ich sehe POC als normales Python an. Man benützt diese POC-Hierarchie in weiten Teilen, so wie man eine ganz normale Objekt-Hierarchie benützen würde.
Fazit: Ich würde eher versuchen, ein Design zu entwickeln, dass sich gut in die normale Entwicklung mit Python einfügt.
Meiner Meinung nach habe ich das gemacht. Aber na ja Geschmäcker sind verschieden; trotzdem hoffe ich, das ihr mein POC nicht in völlig in der Luft zerreißen werdet.:-)
Die Funktion wird erst beim Aufruf ausgeführt. Kannst aber garantieren, dass nicht auch außerhalb der Funktion Anweisungen kommen? Zum Beispiel:
s = """ print('haha') def printer(): print("Böse Funktion: ", dir()) """
Vieleicht so:
def teste(s): l = s.strip().splitlines() func_line = l.pop(0) if not func_line.startswith("def ") and not func_line.endswith("):\n"):
Das schließt auch Funktionen aus, bei denen die Argumentliste nicht komplett in einer Zeile steht:
def my_func(langer_bezeichner, noch_ein_langer_bezeichner, und_noch_einer): ...
(Nebenbei: `splitlines` entfernt die Zeilenende-Zeichen; `\n` sollte also nicht Bestandteil des Strings sein.)
raise SyntaxWarning("Will ich nicht haben") for item in l: if not item.startswith(" "): raise SyntaxWarning("Will ich nicht haben") return s
Mir fällt zumindest eine "legale" Variante ein, bei der der Funktionsblock nur teilweise eingerückt ist:
def my_func(): print """\ Erste Zeile Zweite Zeile"""
Das sieht natürlich nicht übersichtlich aus; daher ist es verständlich, wenn du "das nicht haben willst". ;-)
Das Stimmt, aber ich will mal nicht so Pingelig sein :-) . Bei alledem kann es mir nicht um ein sicheres exec gehen, das wird es unter Python nicht geben können.
Viele Grüße
Albert

Hi Albert,
On 2012-12-09 10:03, Albert Hermeling wrote:
Am 09.12.2012 02:55, schrieb Stefan Schwarzer:
Was du beschreibst, macht zudem den Eindruck, als würdest du einen Teil der Funktionalität, die Python schon bietet, noch mal implementieren. So nett DSLs (domain-specific languages) auch scheinen mögen: Nach meiner Erfahrung handelt man sich mit deren Entwicklung und Einsatz oft einen relativ großen Aufwand (in Entwicklung und Fehlersuche) mit relativ wenig Zusatznutzen gegenüber "normalem" Python-Code ein.
Ich glaub jetzt muss ich mal ein kleines Beispiel bringen um das ganze etwas näher zu erläutern:
---Dateianfang---
DOCTYPE = "VERSION : 1.3.0, CHARSET : UTF8, ESC : !/" # Sprachversion und Kodierung;
[f # Normale Sektion f] in_f_1 = <"1" "2" "3"> # Das ist eine Python Liste; in_f_2 = ("10" "20" "30") # Das ist ein Python Tuple; in_f_3 = {"100" "200"} # Das ist ein Python Set [...] ---Dateiende---
für mich sieht das JSON so ähnlich, dass ich mich frage, ob du nicht lieber das als "Grundformat" nehmen und dann nur etwas per Software nachbearbeiten willst. JSON wird seit Python 2.6 in der Standardbibliothek unterstützt. [1]
Eingelesen wird die Datei so obj = poc_read("test.poc")
Auf die Attribute greift man so zu:
obj.f.in_f_1,
oder so
x = getattr(obj, "f.g.SubS.namen")
Attribute können so neu belegt werden:
obj.f.in_f_1 = "Neuer Wert"
aber auch so:
obj.f.newAttribute("Neuer Wert", "Mit Kommentar")
aber auch so:
setattr(obj, "f.g.SubS.name", ("foo", "bar", "egg"))
Sektionen werden so angelegt:
obj.f.newSection("Foobar", "Sektion Foobar", datatype = "txt")
Gespeichert wird die POC-Hierarchie so:
poc_write(obj)
Sind diese Aufrufe alles normale Python-Aufrufe oder musst du das selbst parsen und in echten Python-Code umsetzen ( `getattr(obj, "f.g.SubS.namen")` sieht mir schon stark nach der zweiten Variante aus)?
Falls letzteres, würde ich dringend davon abraten. Du baust damit eine Sprache, die sich so ähnlich wie Python verhält, aber nicht Python ist. _Gerade_ wenn du übliche Python-Syntax verwendest, werden sich Anwender deiner DSL vermutlich früher oder später wundern, warum sie in diesem Kontext nicht beliebige Python-Konstrukte verwenden können.
Wie willst du mit Erweiterungswünschen "deiner" Anwender umgehen? Sagst du, "geht nicht", oder bildest du mittel- bis langfristig immer mehr von Python nach? (Oder noch unangenehmer: etwas, was nicht Python, sondern nur "so ähnlich" ist.)
Was ist daran so Unpythonisch das ein Programmierer das nicht anwenden kann wenn er es denn will! ;-)
Unpythonisch wäre es für mich schon mal, wenn es kein Python wäre. ;-)
Wenn die anderen Programmierer sich nicht mit Python auskennen, werden sie vermutlich lästige Fehler in ihrem Code einbauen. Wenn sie sich an dich wenden, darfst du unter Umständen diese Mischung aus DSL und dem anderen Code debuggen. Wenn die Programmierer dagegen erfahrener sind, werden sie voraussichtlich vorziehen, "ganz normales" Python zu schreiben, ohne sich Gedanken über abweichende Ausführungsmodelle machen zu müssen.
Also ich sehe POC als normales Python an. Man benützt diese POC-Hierarchie in weiten Teilen, so wie man eine ganz normale Objekt-Hierarchie benützen würde.
Das "in weiten Teilen" lässt mich auch wieder aufhorchen. Ein Anwender muss sich bei einem Python-Konstrukt, das er gern verwenden würde, also überlegen, ob das in deiner Sprache überhaupt geht oder anders als in Python geschrieben werden muss. Das ist zusätzliche Denkarbeit, die du bei einer mit "normalem" Python implementierten Schnittstelle nicht hättest.
Fazit: Ich würde eher versuchen, ein Design zu entwickeln, dass sich gut in die normale Entwicklung mit Python einfügt.
Meiner Meinung nach habe ich das gemacht. Aber na ja Geschmäcker sind verschieden; trotzdem hoffe ich, das ihr mein POC nicht in völlig in der Luft zerreißen werdet.:-)
Nach dem, was ich bisher gesehen habe, empfehle ich umso mehr, dass du deinen Ansatz noch mal überdenkst.
Hast du mal recherchiert, wie woanders Plugin-Systeme entworfen und implementiert wurden? Ich denke, du solltest, falls du es noch nicht getan hast, erst mal allgemein zum Thema Plugin-Architekturen in Python recherchieren und dann zu speziellen Projekten. An Python-Programmen mit Plugin-Schnittstelle fallen mir schon mal Trac [2] und Mercurial [3] ein. Möglicherweise ist eine Plugin-Schnittstelle viel leichter zu implementieren als du denkst. Vielleicht reicht für dich eine ganz triviale Implementierung.
Meine Vermutung ist, dass das _langfristig_ weitaus besser zu warten sein wird als ein DSL-Ansatz, auch wenn dir dieser im Moment reizvoller erscheint.
[1] http://docs.python.org/2/library/json.html [2] http://trac.edgewall.org/ http://trac.edgewall.org/wiki/TracDev/PluginDevelopment [3] http://mercurial.selenic.com/ http://mercurial.selenic.com/wiki/WritingExtensions
Viele Grüße Stefan

Hi Albert,
Nach dem, was ich bisher gesehen habe, empfehle ich umso mehr, dass du deinen Ansatz noch mal überdenkst.
Ich kann mich Stefans Ausführungen nur anschließen und möchte noch ein paar Gedanken hinzufügen:
* Rein optisch ist die Sprache schlecht zu lesen. bei Texten wie
in_f_1 = <"1" "2" "3">
gehen mir die Augen über, weil die Kommas zwischen den Strings fehlen.
* Wen Du wirklich "embedded code" prüfen willst, empfehle ich dringend, das `compiler.parse` zu verwenden. Sonst enden Deine Versuche, einige Schlüsselwörter zu filtern irgendwann darin, dass Du einen eigenen Python-Parser schreibst.

Am 09.12.2012 12:45, schrieb Hartmut Goebel:
Hi Albert,
Nach dem, was ich bisher gesehen habe, empfehle ich umso mehr, dass du deinen Ansatz noch mal überdenkst.
Ich kann mich Stefans Ausführungen nur anschließen und möchte noch ein paar Gedanken hinzufügen:
Rein optisch ist die Sprache schlecht zu lesen. bei Texten wie
in_f_1 = <"1" "2" "3">
gehen mir die Augen über, weil die Kommas zwischen den Strings fehlen.
Das sollen eigentlich Zahlen sein und nicht Strings das ist ein Bug:-[ . Die Anführungszeichen sind da überflüssig. So ist es besser "test = <1 2 3 4>". Kommas habe ich da absichtlich weggelassen. Ich habe mir gedacht Leerraum reicht als Abtrennung der einzelnen Werte. Ansonsten verwende ich Anführungszeichen so wie es in Python üblich ist.
- Wen Du wirklich "embedded code" prüfen willst, empfehle ich
dringend, das `compiler.parse` zu verwenden. Sonst enden Deine Versuche, einige Schlüsselwörter zu filtern irgendwann darin, dass Du einen eigenen Python-Parser schreibst.
Ich wollte das Python ast Modul verwenden.
Viele Grüße
Albert

Am 09.12.2012 12:27, schrieb Stefan Schwarzer:
Hallo Stefan,
für mich sieht das JSON so ähnlich, dass ich mich frage, ob du nicht lieber das als "Grundformat" nehmen und dann nur etwas per Software nachbearbeiten willst. JSON wird seit Python 2.6 in der Standardbibliothek unterstützt. [1]
Ja ist es und dann wieder nicht. Es gibt schon einige Unterschiede.
Eingelesen wird die Datei so obj = poc_read("test.poc")
Auf die Attribute greift man so zu:
obj.f.in_f_1,
oder so
x = getattr(obj, "f.g.SubS.namen")
Attribute können so neu belegt werden:
obj.f.in_f_1 = "Neuer Wert"
aber auch so:
obj.f.newAttribute("Neuer Wert", "Mit Kommentar")
aber auch so:
setattr(obj, "f.g.SubS.name", ("foo", "bar", "egg"))
Sektionen werden so angelegt:
obj.f.newSection("Foobar", "Sektion Foobar", datatype = "txt")
Gespeichert wird die POC-Hierarchie so:
poc_write(obj)
Sind diese Aufrufe alles normale Python-Aufrufe
Sind alles ganz normale Python aufrufe dort wird kein parser eingesetzt. getattr, setattr, sind die Originalen Funkionen von Python. Das getattr(obj, "a.b.c") darfst du machen must du aber nicht. Du kast getattr auch mehrmals hintereinander aufrufen. Alle Datentypen wie tuple, set, list usw. sind Original Python Objekte und verhalten sich auch so.
oder musst du das selbst parsen und in echten Python-Code umsetzen ( `getattr(obj, "f.g.SubS.namen")` sieht mir schon stark nach der zweiten Variante aus)?
Das einzige was ich parsen muss ist die Datei sonst nichts.
Wie willst du mit Erweiterungswünschen "deiner" Anwender umgehen? Sagst du, "geht nicht", oder bildest du mittel- bis langfristig immer mehr von Python nach? (Oder noch unangenehmer: etwas, was nicht Python, sondern nur "so ähnlich" ist.)
Ich brauche kein Python nachbilden es ist Python! und nichts anderes.
Was ist daran so Unpythonisch das ein Programmierer das nicht anwenden kann wenn er es denn will! ;-)
Unpythonisch wäre es für mich schon mal, wenn es kein Python wäre. ;-)
Na das freut mich jetzt aber ungemein, es ist ja Python und nichts anderes. :-)
Wenn die anderen Programmierer sich nicht mit Python auskennen, werden sie vermutlich lästige Fehler in ihrem Code einbauen. Wenn sie sich an dich wenden, darfst du unter Umständen diese Mischung aus DSL und dem anderen Code debuggen. Wenn die Programmierer dagegen erfahrener sind, werden sie voraussichtlich vorziehen, "ganz normales" Python zu schreiben, ohne sich Gedanken über abweichende Ausführungsmodelle machen zu müssen.
Also ich sehe POC als normales Python an. Man benützt diese POC-Hierarchie in weiten Teilen, so wie man eine ganz normale Objekt-Hierarchie benützen würde.
Das "in weiten Teilen" lässt mich auch wieder aufhorchen.
Das "in weiten Teilen" ist ein sau blöder Satz. Entschuldige bitte, ich war da wohl noch nicht ganz ausgeschlafen. Die Weinachsfeier gestern Abend, war doch anstrengender als ich dachte. ; Die Sektions Objekte verhalten sich wie Python Objekte. Das einzigste was Du nicht machen kannst diese Überschreiben, willst du das, musst Du dieser erst löschen. Neu anlegen geht am einfachsten mit newSection.
Ein Anwender muss sich bei einem Python-Konstrukt, das er gern verwenden würde, also überlegen, ob das in deiner Sprache überhaupt geht oder anders als in Python geschrieben werden muss. Das ist zusätzliche Denkarbeit, die du bei einer mit "normalem" Python implementierten Schnittstelle nicht hättest.
Fazit: Ich würde eher versuchen, ein Design zu entwickeln, dass sich gut in die normale Entwicklung mit Python einfügt.
Ich sage es noch mal es ist keine neue oder andere Programmiersprache es ist Python!
Nach dem, was ich bisher gesehen habe, empfehle ich umso mehr, dass du deinen Ansatz noch mal überdenkst.
Hast du mal recherchiert, wie woanders Plugin-Systeme entworfen und implementiert wurden? Ich denke, du solltest, falls du es noch nicht getan hast, erst mal allgemein zum Thema Plugin-Architekturen in Python recherchieren und dann zu speziellen Projekten. An Python-Programmen mit Plugin-Schnittstelle fallen mir schon mal Trac [2] und Mercurial [3] ein. Möglicherweise ist eine Plugin-Schnittstelle viel leichter zu implementieren als du denkst. Vielleicht reicht für dich eine ganz triviale Implementierung.
Schön das zumindest die Idee eines Plug-in Systems deine Zustimmung findet.
Aber warum ist es so schlimm wenn ich meine Klassen vor Veränderung Schützen möchte und stattdessen embedded-code zulassen will?
Viele Grüße
Albert

Hallo,
Na das freut mich jetzt aber ungemein, es ist ja Python und nichts anderes. :-)
Ich sage es noch mal es ist keine neue oder andere Programmiersprache es ist Python!
auch die Wiederholung macht das nicht wahrer. Es ist *nicht* Python. Es ist eine eigene Sprache, die natuerlich eine Abbildung in Python-Konstrukte erfaehrt. Aber mit dem Argument ist Python auch nicht Python, sondern irgendwie C was wiederum eigentlich Maschinensprache ist. Denn am Ende ist alles irgendwie ausfuehrbarer Code - sonst hilft's ja nix.
Und darum ist so eine Argumentation auch hinfaellig. Wenn ich wasauchimmeresist das POCs braucht verwende, kann ich *KEIN* Python schreiben. Ich muss neue Syntax und Semantik lernen. Es ist also *nicht* Python.
Schön das zumindest die Idee eines Plug-in Systems deine Zustimmung findet.
Aber warum ist es so schlimm wenn ich meine Klassen vor Veränderung Schützen möchte und stattdessen embedded-code zulassen will?
Zum einen stellt sich die Frage, warum du das tun willst. Andere Programmiersprachen kennen das Konzept der Privatheit. Python nicht. Das kann man debattieren, ob das sinnvoll ist oder nicht - aber jemand, der Python programmieren soll, sollte man auch Python programmieren *lassen*. Und nicht eine Chimaere aus irgendwie xml-basierten Objektbaeumen und daran angeflanschte Ueberladungen. Wenn es dir also so wichtig ist - dann nutze eine dieser Sprachen, dann musst du da keine Klimmzuege machen.
Zum zweiten hast du mit exec eh "alles" drin, was Python kann. Das mag anstrengender sein, als es einfach zuzulassen. Und genau darum ist das "schlimm", denn dadurch stellst du dich in den Weg der Anwender, ohne wirklich etwas zu verbessern/verhindern.
Ein Beispiel, wo das auch grauenvoll ist und unnoetige Anstrengungen verursacht: ZOPEs Script-Methoden die kuenstlich limitiert sind, und die dann durch Extensions erweitert werden muessen, die am Ende nix als "normaler" Python-Code sind, aber dafuer muss man dann halt den Server neustarten, wenn man eine Zeile veraendert hat. Super. Ueber diesen Mist habe ich so manches meiner inzwischen spaerlichen Haare verloren.
Aber am wichtigsten ist die Frage: was fuer ein Problem versuchst du hier ueberhaupt zu loesen? Du stellst einen Haufen Technik vor, der aber so erstmal zweckfrei daherkommt. Hast du das Problem, dass du mit Code von nicht vertrauenswuerdiger Seite hantieren musst? Klang bisher nicht so. Hast du Leute, die nicht wirklich programmieren koennen, und denen du darum "weichgekochte" Programmierung ermoeglichen willst? Sieht so auch nicht aus, ist alles erstmal komplizierter als "normal", und wartet auch nicht wirklich mit simpleren Konstrukten auf.
Oder hast du in der taeglichen Arbeit mit dem System und seinen Anwendern solche "schaedlichen" Verhaltensmuster ausgemacht, denen du jetzt begegnen willst?
Alles in allem sieht das ganze nach einer Loesung fuer Probleme aus, die du bestenfalls antizipiert hast. Da mag ich mich irren. Aber es hat sich eigentlich in der modernen Software-Entwicklung durchgesetzt, Probleme erstmal nur im Problem-Raum zu diskutieren, und die Loesungen - und mit ihnen ihre Einschraenkungen und Zwänge - beiseite zu lassen, bis man das Problem richtig verstanden hat.
Wie waere es also, wenn du uns *das* mal schilderst?
Diez

Hi Albert,
On 2012-12-09 13:37, Albert Hermeling wrote:
Am 09.12.2012 12:27, schrieb Stefan Schwarzer:
für mich sieht das JSON so ähnlich, dass ich mich frage, ob du nicht lieber das als "Grundformat" nehmen und dann nur etwas per Software nachbearbeiten willst. JSON wird seit Python 2.6 in der Standardbibliothek unterstützt. [1]
Ja ist es und dann wieder nicht. Es gibt schon einige Unterschiede.
Klar, sonst _wäre_ es ja schon JSON. ;-) Ich meinte, ich kann mir vorstellen, dass es sich relativ einfach auf JSON übertragen ließe.
Eingelesen wird die Datei so obj = poc_read("test.poc")
Auf die Attribute greift man so zu:
obj.f.in_f_1,
oder so
x = getattr(obj, "f.g.SubS.namen")
Attribute können so neu belegt werden:
obj.f.in_f_1 = "Neuer Wert"
aber auch so:
obj.f.newAttribute("Neuer Wert", "Mit Kommentar")
aber auch so:
setattr(obj, "f.g.SubS.name", ("foo", "bar", "egg"))
Sektionen werden so angelegt:
obj.f.newSection("Foobar", "Sektion Foobar", datatype = "txt")
Gespeichert wird die POC-Hierarchie so:
poc_write(obj)
Sind diese Aufrufe alles normale Python-Aufrufe
Sind alles ganz normale Python aufrufe dort wird kein parser eingesetzt. getattr, setattr, sind die Originalen Funkionen von Python. Das getattr(obj, "a.b.c") darfst du machen must du aber nicht. Du kast getattr auch mehrmals hintereinander aufrufen. Alle Datentypen wie tuple, set, list usw. sind Original Python Objekte und verhalten sich auch so. [...]
Ich will nicht ausschließen, dass für `getattr` die normale Python-Builtin-Funktion verwendet wird. Das Problem, was ich bei diesem Design sehe, ist, dass es, selbst wenn es (nach einem relativ einfachen Parse-Schritt) Python ist, nicht wie Python aussieht. In Python würdest du normalerweise _nicht_ auf _Attribute_ "f.g" zugreifen. Das ist definitiv etwas anderes als `obj.f.g`, was `getattr(getattr(obj, "f"), "g")` entspräche. Also ziemlich exotisch.
Klar kannst du `__getattr__`- und/oder `__getattribute__`-Methoden so definieren, dass beides äquivalent ist, aber das finde ich ziemlich gruselig.
Was ist daran so Unpythonisch das ein Programmierer das nicht anwenden kann wenn er es denn will! ;-)
Unpythonisch wäre es für mich schon mal, wenn es kein Python wäre. ;-)
Na das freut mich jetzt aber ungemein, es ist ja Python und nichts anderes. :-)
Dass es Python-Code ist, ist meines Erachtens nur eine notwendige, aber keine hinreichende Bedingung, um "pythonic" zu sein. :)
Fazit: Ich würde eher versuchen, ein Design zu entwickeln, dass sich gut in die normale Entwicklung mit Python einfügt.
Ich sage es noch mal es ist keine neue oder andere Programmiersprache es ist Python!
Jein. Wie gesagt, sogar wenn man das anfängliche Parsen der Grobstruktur mal außer Acht lässt, sieht es anders als Python aus und hat andere/zusätzliche Regeln gegenüber üblichem Python-Code.
Vielleicht mal ein Vergleich: Wenn du deutsche Redewendungen mit den gleichen Wörtern ins Englische überträgst, wird das einen Englisch-Muttersprachler verwirren, selbst wenn Rechtschreibung und Grammatik üblichen Englisch-Regeln folgen (bis auf Ausnahmen, wo Deutsch und Englisch sinngemäß die gleichen Wörter verwenden).
Hast du mal recherchiert, wie woanders Plugin-Systeme entworfen und implementiert wurden? Ich denke, du solltest, falls du es noch nicht getan hast, erst mal allgemein zum Thema Plugin-Architekturen in Python recherchieren und dann zu speziellen Projekten. An Python-Programmen mit Plugin-Schnittstelle fallen mir schon mal Trac [2] und Mercurial [3] ein. Möglicherweise ist eine Plugin-Schnittstelle viel leichter zu implementieren als du denkst. Vielleicht reicht für dich eine ganz triviale Implementierung.
Schön das zumindest die Idee eines Plug-in Systems deine Zustimmung findet.
Das habe ich nicht gemeint. Ich fände ein Python-Plugin-System zwar besser als eine spezielle Syntax, wie du sie in deinen Ursprungsdateien verwendest. Ich stimme aber mit Mike überein, dass vielleicht auch schon ein Plugin-System für deine Anwendung zu viel des guten ist.
Aber warum ist es so schlimm wenn ich meine Klassen vor Veränderung Schützen möchte und stattdessen embedded-code zulassen will?
Weil es von üblichen Python-Gewohnheiten deutlich abweicht und der Anwender dieses Systems deshalb auf Besonderheiten gegenüber üblichem Python-Code achten muss. Ich denke, dass die subjektiven Vorteile diesen Nachteil bei Weitem nicht rechtfertigen.
Viele Grüße Stefan

Also ich sehe POC als normales Python an. Man benützt diese POC-Hierarchie in weiten Teilen, so wie man eine ganz normale Objekt-Hierarchie benützen würde.
Und warum benutzt man dann nicht einfach eine *echte* Python Objekthierarchie?
Fazit: Ich würde eher versuchen, ein Design zu entwickeln, dass sich gut in die normale Entwicklung mit Python einfügt.
Meiner Meinung nach habe ich das gemacht. Aber na ja Geschmäcker sind verschieden; trotzdem hoffe ich, das ihr mein POC nicht in völlig in der Luft zerreißen werdet.:-)
Ich wuerde es schon gerne, aber ich fürchte, das ist Code, der dir am Herzen liegt…
Doch ich versuch's trotzdem mal, dir das auszureden.
Im Java-Umfeld gibt es - ob der geringen Flexibilitaet der Sprache - oft XML als Konfigurations-Sprache, die an Maechtiggkeit den Umfang einer "echten" Programmiersprache annimmt.
Mich erinnert das ganze an alte ANT-Skripte, die ich schreiben musste. Im Grunde XML, aber dank "BeanShell" konnte man Jython einbetten. Und weil es ein paar Funktionalitaeten gab, die ANT nicht unterstuetzt hat, musste man das machen. Und es war ..schlimm.
Und POC ist das IMHO auch. Denn es faengt schonmal damit an, dass XML zu schreiben Menschen nicht zugemutet werden sollte. XML ist ein Serialisierungsformat, dass gut zwischen zwei Maschinen funktioniert. Aber es von Hand zu erstellen ist anstrengend. Wer zB mal Apache mit NGINX Konfigurationsdateien verglichen hat, weiss wovon ich rede.
Dann darf ich zwar Python schreiben, aber nicht so richtig, weil du bestimmte Dinge 'doof' findest wie globals oder lokale Importe. Ich kann es nicht im Emacs bearbeiten mit all den Vorteilen von entweder einem XML-Modus oder einem Python-Modus. Oder zB mit Altova XMLSPY. Ich kann nicht unit-testen, ich kann nicht wiederverwenden, ich kann keine komplexeren Strukturen bauen.
Fuer bestimmte Python-Strukturen gibt es aequivalente Konstrukte - eine unnoetige Doppelung. Es gibt sogar noch eine dritte Syntax mit Semikola als Statement-Trenner, Python-Code ist irgendwie komisch in Strings einzubetten usw.
Ich wuerde mich sehr bedanken, wenn ich so etwas vorgesetzt bekomme. Du verraetst uns ja nicht, *wozu* du das geschrieben hast. Ich wuerde aber eher versuchen, sowas wie zB LEO oder Protegé
http://webpages.charter.net/edreamleo/front.html http://protege.stanford.edu/
herzunehmen, und die dadurch erstellten Dokumente dann irgendwie weiterverarbeiten. Denn dein Datenformat ist natuerlich egal, wenn du einen vernuenftigen Editor darueber legst. Dann geht auch XML, wie zb OpenOffice Dokumente. Aber von Hand schreiben, mit Python verwurstet darin? Nein, das ist wirklich schmerzhaft.
Diez

Am 09.12.2012 12:45, schrieb Diez B. Roggisch:
Hallo Diez,
Also ich sehe POC als normales Python an. Man benützt diese POC-Hierarchie in weiten Teilen, so wie man eine ganz normale Objekt-Hierarchie benützen würde.
Und warum benutzt man dann nicht einfach eine *echte* Python Objekthierarchie?
Tust du doch. Wie ich Stefan schon geschrieben habe ist der Satz "verunglückt" Entschuldige bitte.
Fazit: Ich würde eher versuchen, ein Design zu entwickeln, dass sich gut in die normale Entwicklung mit Python einfügt.
Meiner Meinung nach habe ich das gemacht. Aber na ja Geschmäcker sind verschieden; trotzdem hoffe ich, das ihr mein POC nicht in völlig in der Luft zerreißen werdet.:-)
Ich wuerde es schon gerne, aber ich fürchte, das ist Code, der dir am Herzen liegt…
Ja das tut er...
Doch ich versuch's trotzdem mal, dir das auszureden.
... hätte mich gewundert wenn nicht. :-D
Im Java-Umfeld gibt es - ob der geringen Flexibilitaet der Sprache - oft XML als Konfigurations-Sprache, die an Maechtiggkeit den Umfang einer "echten" Programmiersprache annimmt.
Mich erinnert das ganze an alte ANT-Skripte, die ich schreiben musste. Im Grunde XML, aber dank "BeanShell" konnte man Jython einbetten. Und weil es ein paar Funktionalitaeten gab, die ANT nicht unterstuetzt hat, musste man das machen. Und es war ..schlimm.
Und POC ist das IMHO auch. Denn es faengt schonmal damit an, dass XML zu schreiben Menschen nicht zugemutet werden sollte. XML ist ein Serialisierungsformat, dass gut zwischen zwei Maschinen funktioniert. Aber es von Hand zu erstellen ist anstrengend. Wer zB mal Apache mit NGINX Konfigurationsdateien verglichen hat, weiss wovon ich rede.
Also ANT kenne ich nicht dazu kann ich nichts Schreiben. Aber du behauptest das es schwer ist eine POC Datei zu schreiben, dann probiere ich das jetzt mal aus:
Quelle der Nachfolgenden Daten ist die Wikipedia: http://de.wikipedia.org/wiki/Die_Simpsons die Textauszüge sind als Zitate zu verstehen
---Dateianfang---
DOCTYPE = "VERSION : 1.3.0, CHARSET : UTF8, ESC : !/" # Sprachversion und Kodierung;
[Simpsons] [Familie] [Eltern] vater = ("Homer Jay Simpson " 01.01.1970 Sicherheitsinspektor); vater_beschreibung = """ Homer Jay Simpson ist das Familienoberhaupt der Simpsons, Ehemann von Marge und Vater von Bart, Lisa und Maggie. Sein Alter schwankt je nach Episode zwischen 36 und 42 Jahren.... """; mutter = ("Marjorie !/„Marge!/“ Simpson", 1.1.1978 "Hausfrau und Mutter); mutter_beschreibung = """ Marjorie „Marge“ Simpson, geborene Bouvier, die 34-jährige Ehefrau von Homer und Mutter von Bart, Lisa und Maggie, ist die gute Seele im Hause Simpson. Sie lebt in aufopfernder Zuwendung für ihre... """; [/Eltern] [Kinder] bart = ("Bartholomew !/„Bart!/“ Jo-Jo Simpson" 01.1.2002 Schüler); bart_beschreibung = """ Bartholomew „Bart“ Jo-Jo Simpson, alias „El Barto“, alias „Bartman“, ist der zehnjährige Sohn von Homer und Marge und zwei Jahre und 38 Tage älter als Lisa. """; lisa = ("Lisa Marie Simpson" 1.1.2004 Schüler); lisa_beschreibung = """ Lisa Marie Simpson, acht Jahre alt, ist das zweite der Simpson-Kinder und mit einem IQ von 159 hochbegabt. """; maggie = ("Margaret !/„Maggie!/“ Simpson" 01.01.2011); maggie_beschreibung = """ Margaret „Maggie“ Simpson ist mit einem Jahr das jüngste Mitglied der Familie """; [/Kinder] [/Familie] [Serie] staffel1 = ("Die komplette 1. Staffel." " 27. September 2001" "13 Folgen") # Gekürzt; staffel2 = ("Die komplette 2. Staffel." " 6. Juni 2002" "22 Folgen") # Gekürzt; [/Serie] [/Simposons]
---Dateiende---
So das soll erst mal Reichen für das ganze habe ich 20 Minuten gebraucht und das obwohl ich Schwer-behindert bin und die Hände nicht immer machen was sie sollen. Das ist auch der Grund warum in listen, tuple, sets keine Kommas zwischen den Elementen stehen. Als ich wieder anfing zu Programmieren viel es mir noch schwerer als heute.
Dann darf ich zwar Python schreiben, aber nicht so richtig, weil du bestimmte Dinge 'doof' findest wie globals oder lokale Importe. Ich kann es nicht im Emacs bearbeiten mit all den Vorteilen von entweder einem XML-Modus oder einem Python-Modus. Oder zB mit Altova XMLSPY. Ich kann nicht unit-testen, ich kann nicht wiederverwenden, ich kann keine komplexeren Strukturen bauen.
Ist schon seltsam ich lese diese Liste schon lange und immer wenn jemand global gebrauchen will um globale Variablen anzulegen wird im davon abgeraten. Jetzt wo ich konsequenter Weise die Verwendung untersagen will wird das als Beschränkung empfunden ;-)
Ach ja uni-testen kannst Du es :-) die ganze Bibliothek wird per unittest getestet und zwar sehr ausführlich.
Fuer bestimmte Python-Strukturen gibt es aequivalente Konstrukte - eine unnoetige Doppelung. Es gibt sogar noch eine dritte Syntax mit Semikola als Statement-Trenner, Python-Code ist irgendwie komisch in Strings einzubetten usw.
Du verraetst uns ja nicht, *wozu* du das geschrieben hast.
In erster Linie habe ich es für mich geschrieben. Nach meiner schweren Krankheit brauchte ich etwas was mich aufrichtet, etwas was mich Fesselt und Fasziniert. Wie ich dazu gekommen bin genau das zu scheiben kann ich heute nicht mehr sagen.
Viele Grüße
Albert

Hallo Albert,
Also ANT kenne ich nicht dazu kann ich nichts Schreiben. Aber du behauptest das es schwer ist eine POC Datei zu schreiben, dann probiere ich das jetzt mal aus:
Quelle der Nachfolgenden Daten ist die Wikipedia: http://de.wikipedia.org/wiki/Die_Simpsons die Textauszüge sind als Zitate zu verstehen
---Dateianfang---
DOCTYPE = "VERSION : 1.3.0, CHARSET : UTF8, ESC : !/" # Sprachversion und Kodierung;
[Simpsons] [Familie] [Eltern] vater = ("Homer Jay Simpson " 01.01.1970 Sicherheitsinspektor); vater_beschreibung = """ Homer Jay Simpson ist das Familienoberhaupt der Simpsons, Ehemann von Marge und Vater von Bart, Lisa und Maggie. Sein Alter schwankt je nach Episode zwischen 36 und 42 Jahren.... """; mutter = ("Marjorie !/„Marge!/“ Simpson", 1.1.1978 "Hausfrau und Mutter); mutter_beschreibung = """ Marjorie „Marge“ Simpson, geborene Bouvier, die 34-jährige Ehefrau von Homer und Mutter von Bart, Lisa und Maggie, ist die gute Seele im Hause Simpson. Sie lebt in aufopfernder Zuwendung für ihre... """; [/Eltern] [Kinder] bart = ("Bartholomew !/„Bart!/“ Jo-Jo Simpson" 01.1.2002 Schüler); bart_beschreibung = """ Bartholomew „Bart“ Jo-Jo Simpson, alias „El Barto“, alias „Bartman“, ist der zehnjährige Sohn von Homer und Marge und zwei Jahre und 38 Tage älter als Lisa. """; lisa = ("Lisa Marie Simpson" 1.1.2004 Schüler); lisa_beschreibung = """ Lisa Marie Simpson, acht Jahre alt, ist das zweite der Simpson-Kinder und mit einem IQ von 159 hochbegabt. """; maggie = ("Margaret !/„Maggie!/“ Simpson" 01.01.2011); maggie_beschreibung = """ Margaret „Maggie“ Simpson ist mit einem Jahr das jüngste Mitglied der Familie """; [/Kinder] [/Familie] [Serie] staffel1 = ("Die komplette 1. Staffel." " 27. September 2001" "13 Folgen") # Gekürzt; staffel2 = ("Die komplette 2. Staffel." " 6. Juni 2002" "22 Folgen") # Gekürzt; [/Serie] [/Simposons]
---Dateiende---
So das soll erst mal Reichen für das ganze habe ich 20 Minuten gebraucht und das obwohl ich Schwer-behindert bin und die Hände nicht immer machen was sie sollen. Das ist auch der Grund warum in listen, tuple, sets keine Kommas zwischen den Elementen stehen. Als ich wieder anfing zu Programmieren viel es mir noch schwerer als heute.
Ich finde das schon ziemlich "schwer". Natuerlich sind das alles nur Tastendrücke, und nicht den Berg raufgerollte Steinbrocken. Aber warum muss ich zB ueberhaupt Klammern um die Tupel machen, wieso die artifizielle Untterscheidung zwischen Schluesseln als Tags ([Eltern], [Kinder], …) und dann einfach als <schluessel=wert>-Paare - das ist inkonsistent, und wenn ich zB noch Hobbies von den Kindern einfuehren will - dann muss ich lisa zum Tag umschreiben? Das ist dann aber deutlich anstrengender als es gut ist.
Und wenn man das in purem Python machen wuerde, saehe das ungefaehr so aus:
# Bunch Recipe, wird natuerlich importiert. Oder man nimmt namedtuple, das habe ich aber noch nie getan ;) class Bunch(object):
def __init__(self, **kwargs): self.__dict__.update(kwargs)
n = Bunch # n fuer node oder so
simpsons = n( familie=n( eltern=n( vater=n(name="Homer", beschreibung="..."), mutter=n(name="Marge", bescreibung="..."), ), kinder=n( bart=... ) ), serie=n( staffel1=... ) )
Du siehst, ich habe auch einiges weggelassen- aus Zeitgruenden. Aber ohne auch nur eine einzige Zeile Parser-Code schreiben zu muessen. Und mein Emacs rueckt mir alles schick ein. Und natuerlich koennte Bunch auch Methoden haben, und ich koennte abgeleitete Klassen erzeugen. Code *inline* zu erweitern ist etwas schwieriger, das liegt an Python's Art, keine multi-statement Lambdas zuzulassen.
Ich hab's auch mal als JSON gemacht, mit dem JS2-mode vom Emacs werden dir dann auch oefnnende/schliessende Klammern und Anfuehrungszeichen erzeugt. Zeigen muss ich das aber denke ich nicht, sieht letzlich aus wie Python dictionairies.
Und wenn du wirklich auf die Reduzierung von Tippvorgaengen aufgrund einer Behinderung aus bist - gerade *dann* ist doch alles, was XML-basiert ist, hoch nervend. Denn fuer die 3 1/2 gesparten Kommas in den Tupeln hast du dir die Notwendigkeit eingefangen, jedes Tag mit vorangestelltem / schliessen zu müssen.
Es gibt so viele bessere Formate als XML, gerade *weil* es so verbos ist und einen viel mehr tippen laesst, als notwendig.
Siehe zB hier:
http://haml.info/ http://www.yaml.org/
Dann darf ich zwar Python schreiben, aber nicht so richtig, weil du bestimmte Dinge 'doof' findest wie globals oder lokale Importe. Ich kann es nicht im Emacs bearbeiten mit all den Vorteilen von entweder einem XML-Modus oder einem Python-Modus. Oder zB mit Altova XMLSPY. Ich kann nicht unit-testen, ich kann nicht wiederverwenden, ich kann keine komplexeren Strukturen bauen.
Ist schon seltsam ich lese diese Liste schon lange und immer wenn jemand global gebrauchen will um globale Variablen anzulegen wird im davon abgeraten. Jetzt wo ich konsequenter Weise die Verwendung untersagen will wird das als Beschränkung empfunden ;-)
Das ist doch nicht das Argument. Wenn global komplett und voellig schlecht wäre - dann waere es doch in Python nicht mehr drin… es gibt aber durchaus sinnvolle Anwendungen davon. Die sind rar, und man sollte gerade als Anfaenger davon absehen, weil man die Konsquenzen nicht abschaetzen kann.
Aber es zu verbieten ist eben eine schlechte Idee fuer die handvoll notwendigen Anwendungen, die es hat.
Aehnliches laesst sich uebrigens auch fuer try/except sagen.
Ach ja uni-testen kannst Du es :-) die ganze Bibliothek wird per unittest getestet und zwar sehr ausführlich.
Ich kann meinen eingebetteten Code unittesten?
Fuer bestimmte Python-Strukturen gibt es aequivalente Konstrukte - eine unnoetige Doppelung. Es gibt sogar noch eine dritte Syntax mit Semikola als Statement-Trenner, Python-Code ist irgendwie komisch in Strings einzubetten usw.
Du verraetst uns ja nicht, *wozu* du das geschrieben hast.
In erster Linie habe ich es für mich geschrieben. Nach meiner schweren Krankheit brauchte ich etwas was mich aufrichtet, etwas was mich Fesselt und Fasziniert. Wie ich dazu gekommen bin genau das zu scheiben kann ich heute nicht mehr sagen.
Gut, das beantwortet dann ja auch meine Frage aus der anderen Mail, die zwischendrin noch raus ging. Es ist halt ein reines Spass-Projekt. Ist ja auch ok, ich habe auch genug Code rumliegen, der nur aus der reinen Freude am ausprobieren entstanden ist.
Und in dem Sinne ist konstruktive Kritik daran auch ziemlich schwer, denn ohne Anwendungsfall, ohne Aussicht auf andere Benutzer, deren Wuensche und Probleme in das Design eingehen sollen, ist natuerlich alles erlaubt, was geht.
Aber wenn du uns um unsere Meinung bittest, ob das sinnvoll jenseits von persoenlicher Beschaeftigung ist - dann fuerchte ich ist die Antwort nein.
LG Diez

Am 09.12.2012 um 16:32 schrieb Diez B. Roggisch:
[...] Es gibt so viele bessere Formate als XML, gerade *weil* es so verbos ist und einen viel mehr tippen laesst, als notwendig. [...]
Hallo zusammen,
was Diez hier schreibt finde ich alles sehr richtig. Zu diesem einen Satz aber nur soviel: ich will XML an dieser Stelle nicht verteidigen, aber ich habe in diesem Zusammenhang eigentlich immer nur von XML als einem Format gehört, das "human readable" sein soll, aber nicht unbe- dingt "human writable". ;-) Und auch Ersteres ist eher "prinzipiell möglich", aber deshalb noch lange nicht immer auch unbedingt einfach.
Gruß,
Dinu

Am 09.12.12 10:03, schrieb Albert Hermeling:
Am 09.12.2012 02:55, schrieb Stefan Schwarzer:
Hallo Stefan,
Hallo Albert,
On 2012-12-08 22:01, Albert Hermeling wrote:
Ich habe eine Anwendung geschrieben die es Erlaubt Daten Strukturiert zu speichern. Das für sich alleine ist überflüssig, dafür gibt es XML und noch einiges Andere. Die Anwendung kann deshalb noch einiges mehr. Ich möchte auf das "einiges mehr" nicht näher eingehen, das würde nicht zum Thema passen. Nur soviel sei gesagt, es handelt sich um Textdateien die von einem Parser verarbeitet werden. Die Daten selber werden in verschachtelten Objekten der Klasse 'SectionXXX' hierarchisch gespeichert. Es werden schon eine Reihe von Datentypen unterstützt, weitere sollen als Plug-in realisiert werden. Die Textdateien sind als "Scripte" anzusehen, sie werden von Programmieren geschrieben, die diese Bibliothek anwenden wollen. Sie sind somit genau so sicher oder unsicher wie jedes andere Python Script auch sein kann.
Meine Überlegung ist jetzt folgende, um Objeke der Klasse SectionXXX um Methoden zu ergänzen, sollen diese als Funktions-Strings in der zugrunde legenden Textdatei eingebettet werden. Dabei kann jede Sektion eigene spezielle Funktionen haben. Man braucht also nicht eigene Klassen von SectionXXX abzuleiten. Aus den Code Strings sollen per exec Funktions-Objekte erzeugt werden, diese sollen per sec1.sub1.myMethod = types.MethodType(myMethod, func) in ihre jeweilige Sektion eingefügt werden. Da ich die Textdateien als sicher ansehe, könnte ich jetzt einfach exec(string) aufrufen und das wer es gewesen. Aber wie ich nun mal bin, ich fange an Nachzudenken und dabei kam mir halt dieser Gedanke.
werden diese eingelesenen Funktionen nicht in deinem Programm ausgeführt? Falls ja, klingt es für mich nicht sinnvoll, Seiteneffekte beim _Definieren_ der Funktionen zu vermeiden, wenn nachher beim _Ausführen_ der Funktion sowieso alles Mögliche passieren kann.
Also ich möchte keine Seiteneffekte vermeiden, es ist Sache des Programmierers sich vorher Gedanken zu machen, was er mit den Daten in einer Sektion (und den Sub-Sektionen) tun möchte oder nicht. Schließlich, wenn der Programmierer eine "Normale Klasse" Foo schreibt und Methoden implementiert um die Daten zu bearbeiten, sollte er wissen was diese mit seinen Daten machen. Aber trotzdem wird es ein paar Restriktionen geben. Zum Beispiel dürfen die Schlüsselwörter class global import nicht vorkommen. Class nicht, weil es dafür das Plug-in System geben wird. Import nicht weil diese zentral über eine Config-Datei gesteuert werden und weil ich es nicht mag Imports in einer Klasse zu **verstreuen**. Global nicht, weil das schlechter Still ist und ich nicht x globale Variablen überall stehen haben will.
Was du beschreibst, macht zudem den Eindruck, als würdest du einen Teil der Funktionalität, die Python schon bietet, noch mal implementieren. So nett DSLs (domain-specific languages) auch scheinen mögen: Nach meiner Erfahrung handelt man sich mit deren Entwicklung und Einsatz oft einen relativ großen Aufwand (in Entwicklung und Fehlersuche) mit relativ wenig Zusatznutzen gegenüber "normalem" Python-Code ein.
Ich glaub jetzt muss ich mal ein kleines Beispiel bringen um das ganze etwas näher zu erläutern:
---Dateianfang---
DOCTYPE = "VERSION : 1.3.0, CHARSET : UTF8, ESC : !/" # Sprachversion und Kodierung;
[f # Normale Sektion f] in_f_1 = <"1" "2" "3"> # Das ist eine Python Liste; in_f_2 = ("10" "20" "30") # Das ist ein Python Tuple; in_f_3 = {"100" "200"} # Das ist ein Python Set [g # Normale Sektion g] in_g_1 = "Hallo Welt" # Ein String mit Leerzeichen ohne Umbruch; [SubS # Eine weitere Subsektion] namen = ("albert" "martin" "heinz"); text = """Das hier ist Text der einen Zeilenumbruch enthält. Der wird von drei ' oder " Umschlossen """ # Leerzeichen links von " werden automatisch entfernt; hallo = "Hallo Erde "; printer = |printer""" def printer(self, multiplikator): print(self.hallo * multiplikator) """ # Geplannt: Embedded Code; finePrinter = ||Printer"""((arg1, arg2), {kw1 = "foo", kw2 = "bar})""" # Geplannt Plug-in; [/SubS] [/g] [h ("datatype : int") # Sektion h die nur Zahlen enthält] # Enthalten die Daten (rechts vom Gleichheitszeichen) keine # Leerzeichen können die Anführungszeichen weggelassen werden a = 1; b = 2; c = 3; e = 4; f = (1 2 3 4) # Container mit Zahlen sind erlaubt; [/h] [/f]
---Dateiende---
Eingelesen wird die Datei so obj = poc_read("test.poc")
Auf die Attribute greift man so zu:
obj.f.in_f_1,
oder so
x = getattr(obj, "f.g.SubS.namen")
Attribute können so neu belegt werden:
obj.f.in_f_1 = "Neuer Wert"
aber auch so:
obj.f.newAttribute("Neuer Wert", "Mit Kommentar")
aber auch so:
setattr(obj, "f.g.SubS.name", ("foo", "bar", "egg"))
Sektionen werden so angelegt:
obj.f.newSection("Foobar", "Sektion Foobar", datatype = "txt")
Gespeichert wird die POC-Hierarchie so:
poc_write(obj)
Ich sehe nichts was nicht viel besser mit JSON, YAML oder XML direkt abzubilden wäre. Dafür gibt es ausgereifte Werkzeuge zum Lesen und Schreiben sowie Modi in Editoren, die die Beratung wesentlich erleichtern.
Interessant wird es ja erst, wenn es an das Plugin geht. Was soll das nun genau machen? Muss dass überhaupt ein Plugin sein oder reicht einfach eine Klasse/Funktion, die von außen die Daten verändert (hübsch druckt zum Beispiel)? Wenn der Nutzer sowieso den Code, den du oben gezeigt hast schreibt, kann er doch gleich eine selbst geschriebene Funktion auf die geparsten Daten loslassen. Damit hätte sich alles um das Plugin erledigt und du bietest einfach ein Python-Paket, das die Dateien, in welchen Format auch immer, Lesen, Schreiben und Manipulieren kann. Der Nutzer kann dann halt auch eigene Funktionen schreiben, die die Daten manipulieren.
Ich würde immer den einfachsten Ansatz nehmen, der das Problem sinnvoll löst. Wobei einfach natürlich relativ ist. ;)
Viele Grüße Mike
Erstellen kann man eine POC-Hierachie per Hand oder per poc_new die genaue Syntax erspare ich mir hier mal.
Was ist daran so Unpythonisch das ein Programmierer das nicht anwenden kann wenn er es denn will! ;-)
Wenn die anderen Programmierer sich nicht mit Python auskennen, werden sie vermutlich lästige Fehler in ihrem Code einbauen. Wenn sie sich an dich wenden, darfst du unter Umständen diese Mischung aus DSL und dem anderen Code debuggen. Wenn die Programmierer dagegen erfahrener sind, werden sie voraussichtlich vorziehen, "ganz normales" Python zu schreiben, ohne sich Gedanken über abweichende Ausführungsmodelle machen zu müssen.
Also ich sehe POC als normales Python an. Man benützt diese POC-Hierarchie in weiten Teilen, so wie man eine ganz normale Objekt-Hierarchie benützen würde.
Fazit: Ich würde eher versuchen, ein Design zu entwickeln, dass sich gut in die normale Entwicklung mit Python einfügt.
Meiner Meinung nach habe ich das gemacht. Aber na ja Geschmäcker sind verschieden; trotzdem hoffe ich, das ihr mein POC nicht in völlig in der Luft zerreißen werdet.:-)
Die Funktion wird erst beim Aufruf ausgeführt. Kannst aber garantieren, dass nicht auch außerhalb der Funktion Anweisungen kommen? Zum Beispiel:
s = """ print('haha') def printer(): print("Böse Funktion: ", dir()) """
Vieleicht so:
def teste(s): l = s.strip().splitlines() func_line = l.pop(0) if not func_line.startswith("def ") and not func_line.endswith("):\n"):
Das schließt auch Funktionen aus, bei denen die Argumentliste nicht komplett in einer Zeile steht:
def my_func(langer_bezeichner, noch_ein_langer_bezeichner, und_noch_einer): ...
(Nebenbei: `splitlines` entfernt die Zeilenende-Zeichen; `\n` sollte also nicht Bestandteil des Strings sein.)
raise SyntaxWarning("Will ich nicht haben") for item in l: if not item.startswith(" "): raise SyntaxWarning("Will ich nicht haben") return s
Mir fällt zumindest eine "legale" Variante ein, bei der der Funktionsblock nur teilweise eingerückt ist:
def my_func(): print """\ Erste Zeile Zweite Zeile"""
Das sieht natürlich nicht übersichtlich aus; daher ist es verständlich, wenn du "das nicht haben willst". ;-)
Das Stimmt, aber ich will mal nicht so Pingelig sein :-) . Bei alledem kann es mir nicht um ein sicheres exec gehen, das wird es unter Python nicht geben können.
Viele Grüße
Albert _______________________________________________ python-de maillist - python-de@python.org http://mail.python.org/mailman/listinfo/python-de

Albert Hermeling wrote:
Guten Morgen,
ich Beschäftige mich gerade mit mit den Internas von Python Funktionen. Beim Nachdenken über Funktionen, habe ich mich gefragt, ob man Code beim erzeugen einer Funktion unbemerkt ausführen kann. Klinkt jetzt ein bisschen verworren, deshalb hier ein Beispiel:
s = """ def printer(): print("Böse Funktion: ", dir()) """
Diese Funktion liegt als String vor und wenn ich jetzt aus dem String mit exec eine Funktion erzeuge (Instantiiere (?)) habe ich eine Funktion printer im aktuellen Namensraum. So lange ich diese Funktion nicht aufrufe, passiert nichts, rufe ich Sie auf passiert was. Ist es jetzt eigentlich möglich, das bei der Erzeugung (exec(s) genau jetzt), also noch vor dem Aufrufen der selbigen, Schadcode ausgeführt werden kann?
Ich hoffe das klingt jetzt nicht zu bizarr.
Zählt die Erzeugung von Defaultwerten?
def printer(default=print("gotcha")):
... pass ... gotcha

Hallo,
On 2012-12-08 17:40, Peter Otten wrote:
Albert Hermeling wrote:
Diese Funktion liegt als String vor und wenn ich jetzt aus dem String mit exec eine Funktion erzeuge (Instantiiere (?)) habe ich eine Funktion printer im aktuellen Namensraum. So lange ich diese Funktion nicht aufrufe, passiert nichts, rufe ich Sie auf passiert was. Ist es jetzt eigentlich möglich, das bei der Erzeugung (exec(s) genau jetzt), also noch vor dem Aufrufen der selbigen, Schadcode ausgeführt werden kann?
Ich hoffe das klingt jetzt nicht zu bizarr.
Zählt die Erzeugung von Defaultwerten?
def printer(default=print("gotcha")):
... pass ...
wobei jetzt noch subtilere Sachen möglich sind, zum Beispiel, wenn in
def printer(default=x.y): ...
`x` ein Objekt einer Klasse ist, bei dem `__getattribute__` definiert wurde und dieses Seiteneffekte hat. ;-)
Viele Grüße Stefan

Am 08.12.2012 17:40, schrieb Peter Otten:
Hallo Peter,
auch diese ist erst mal Falsch abgesandt worden Sorry Peter.
Also das würde ich jetzt dazu zählen schließlich könnte man das gebrauchen um bösen Code auszuführen.
Albert Hermeling wrote:
Guten Morgen,
ich Beschäftige mich gerade mit mit den Internas von Python Funktionen. Beim Nachdenken über Funktionen, habe ich mich gefragt, ob man Code beim erzeugen einer Funktion unbemerkt ausführen kann. Klinkt jetzt ein bisschen verworren, deshalb hier ein Beispiel:
s = """ def printer(): print("Böse Funktion: ", dir()) """
Diese Funktion liegt als String vor und wenn ich jetzt aus dem String mit exec eine Funktion erzeuge (Instantiiere (?)) habe ich eine Funktion printer im aktuellen Namensraum. So lange ich diese Funktion nicht aufrufe, passiert nichts, rufe ich Sie auf passiert was. Ist es jetzt eigentlich möglich, das bei der Erzeugung (exec(s) genau jetzt), also noch vor dem Aufrufen der selbigen, Schadcode ausgeführt werden kann?
Ich hoffe das klingt jetzt nicht zu bizarr.
Zählt die Erzeugung von Defaultwerten?
def printer(default=print("gotcha")):
... pass ... gotcha
python-de maillist - python-de@python.org http://mail.python.org/mailman/listinfo/python-de
participants (8)
-
Albert Hermeling
-
Christopher Arndt
-
Diez B. Roggisch
-
Dinu Gherman
-
Hartmut Goebel
-
Mike Müller
-
Peter Otten
-
Stefan Schwarzer