2017-11-29 3 views
1

Ich mache ein Programm, das Code in Batches zufällig generiert und eine Eingabe gegeben, testet, ob dieser Code die gewünschte Ausgabe generiert. Ich möchte die Stapel generierten Codes ziemlich groß machen, sagen wir 10.000 zufällig generierte Dateien pro Batch, also möchte ich im Speicher arbeiten, anstatt sie mit dem Schreiben auf die Festplatte zu verschwenden. Ich möchte auch, dass der Compiler die ganze Arbeit für mich erledigt, wo die einmal erstellte Datei als ein Modul importiert wird, und dann die generierte Funktion in diesem Modul ausgeführt wird und das Ergebnis gegen die gewünschte Ausgabe getestet wird.Mounting Virtual Directory oder Ausführen von Code im Speicher für Python 3

Ich fand, dass Python tempfile.SpooledTemporaryFile() hat, mit dem ich ein dateiähnliches Objekt erstellen und bearbeiten kann, aber sobald ich es erstellt habe, möchte ich darauf zugreifen, als wäre es ein Python-Skript. Da die Datei jedoch im RAM ist und nach dem Schließen gelöscht wird, habe ich Schwierigkeiten, einen Weg zu finden. Was ich will so etwas wie dieses:

import os, tempfile, importlib, desiredInAndOut, codeGenerator 
generatedCodeAsAString = codeGenerator.generateCode() 
cwd = os.getcwd() 
successfulCode = [] 
batchSize = int(input(Enter desired batch size:)) 
runs = 0 
while runs < batchSize: 
    with tempfile.SpooledTemporaryFile(10240, 'w+b', None, None, '\n', '.py', 'tmp', cwd) as stf: 
     stf.write(generatedCodeAsAsAString.encode()) 
     import tmp #import the newly generated file (that maybe has a 'shortcut' in the cwd? Somehow?) 
     importlib.invalidate_caches() #make sure the compiler knows that there is a new module for the first time this runs 
     importlib.reload(tmp) #if the compiler gets smart and re-uses the module from the first import/first iteration of this loop, make sure it reloads/updates it to match the new file that was just created 
     out = tmp.generatedFunction(desiredInAndOut.GIVEN_INPUT) 
     if out == desiredInAndOut.DESIRED_OUTPUT: 
      successfulCode.append(generatedCodeAsAString+'\n'+'#BATCHFILE NO '+str(runs)) 
     runs += 1 
print(successfulCode) 

Trotz meiner Bemühungen ist die tmp-Datei in keiner Weise auf die aktuelle Arbeitsverzeichnis verknüpft, so dass der Import oben wird nicht funktionieren. Ich muss einen Weg finden, die Speicheradresse dieser temporären Datei an die import-Anweisung zu liefern, wo sie eine Standard-Datei "/foo/bar/tmp.py" erwarten würde, und stelle sicher, dass sie sie als Datei interpretiert.

Das Hinzufügen eines virtuellen Laufwerks direkt auf dem Computer ist aufgrund von Berechtigungsproblemen nicht möglich. Wenn Sie eine In-Python-Methode kennen, um so etwas ohne Administratorzugriff auf den Computer zu tun, bin ich ganz Ohr. Ich untersuche derzeit die Funktionalität der eingebauten Funktion exec - nicht sicher, wie es außerhalb der Shell reagieren wird. Ich hoffe, es wird funktionieren, aber wir werden sehen.

Gibt es einen richtigen/besseren Weg zu tun, was ich versuche? Genauer gesagt, gibt es eine Möglichkeit, den Compiler in die Richtung der im Speicher vorhandenen Datei zu lenken, so dass er manipuliert werden kann, als wäre er eine existierende Datei und/oder läuft er? Oder eine Python-formatierte Zeichenfolge, es muss nicht unbedingt eine Datei sein, wenn ich sie in Stringform ausführen kann.

Antwort

0

https://stackoverflow.com/a/2849077/6047611 (Wenn als SpooledTemporaryFile Manipulation)

UND

https://stackoverflow.com/a/3906309/6047611

versorgte mich mit Informationen, die diese Lösung macht den Einbau-exec() -Funktion:

import sys 
from io import StringIO 

def main(): 
    GIVEN_INPUT = input('Enter input as an integer:') 
    code = "def main():\n\tinput = "+GIVEN_INPUT+"\n\tprint(input + 3)\nmain()" 
    #this code would be randomly generated elsewhere. As is, simply adds 3 to GIVEN_INPUT 

    old_stdout = sys.stdout 
    redirected_output = StringIO() 
    sys.stdout = redirected_output 

    exec(code)#, sys._getframe(1).f_globals, sys._getframe(1).f_locals) 

    sys.stdout = old_stdout 

    print('function completed') 
    OUTPUT = redirected_output.getvalue().strip() 
    print(OUTPUT+' is the result of:\n'+ code) 

main() 

Zusammenfassend kann exec() keinen Wert zurückgeben, den ich sehen konnte, aber es kann stattdessen zu sys.stdout drucken Wenn Sie ein Ergebnis "zurückgeben", wird ein Ergebnis ausgegeben, und ich kann das, was gedruckt wird, abrufen, indem ich sys.stdout für einen neuen StringIO ausschalte, während der generierte Code ausgeführt wird, und ihn wieder auf normal zurückstellen, sobald er fertig ist der Inhalt dieses StringIO-Objekts. Wenn es in Dateiform sein müsste, könnte das leicht mit tempfile.SpooledTemporaryFile gemacht werden, siehe meinen ersten Link oben, aber ich erzeuge den Code bereits als String, so dass ich ihn nicht erst in Dateiform konvertieren muss es. Ich hoffe, dass exec() hat keine maximale Zeichen Grenze, die erhebliche Probleme verursachen könnte ...

Keine Importanweisungen zum Öffnen/Ausführen des generierten Codes benötigt, und kann viele Male ausgeführt werden, ohne mit einem zu verwirren virtuelles Verzeichnis oder sogar Dateiobjekte im Allgemeinen.

Verwandte Themen