2009-03-09 1 views
1

Apropos This question, es gibt ein kleines Gerüst innerhalb des Interpreters, um Rahmenobjekte zu prüfen, die von sys._getframe() abgerufen werden können. Die Rahmenobjekte scheinen nur gelesen zu werden, aber ich kann in den Dokumenten, die dies explizit angeben, nichts Offensichtliches finden. Kann jemand bestätigen, ob diese Objekte schreibbar (in irgendeiner Weise) oder nur lesbar sind?Ist es möglich, in ein Python-Rahmenobjekt zu schreiben, das von sys._getframe() aus Python-Code zurückgegeben wird, der im Interpreter ausgeführt wird?

import sys 

def foobar(): 
    xx='foo' 
    ff = sys._getframe() 
    ff.f_locals['xx'] = 'bar' 
    print xx 

if __name__ == '__main__': 
    foobar() 

Dies gibt ‚foo‘ bei der Ausführung aber der Beitrag unten zeigt die Variable beschreibbar sein, wenn sie von dem aktuellen Frame in einer interaktiven Shell ausgeführt.

Antwort

9

Von CPython Quelle, Objects/frameobject.c:

static PyMemberDef frame_memberlist[] = { 
    {"f_back",  T_OBJECT,  OFF(f_back), RO}, 
    {"f_code",  T_OBJECT,  OFF(f_code), RO}, 
    {"f_builtins", T_OBJECT,  OFF(f_builtins),RO}, 
    {"f_globals", T_OBJECT,  OFF(f_globals), RO}, 
    {"f_lasti",  T_INT,   OFF(f_lasti), RO}, 
    {"f_exc_type", T_OBJECT,  OFF(f_exc_type)}, 
    {"f_exc_value", T_OBJECT,  OFF(f_exc_value)}, 
    {"f_exc_traceback", T_OBJECT, OFF(f_exc_traceback)}, 
    {NULL} /* Sentinel */ 
}; 
... 
static PyGetSetDef frame_getsetlist[] = { 
    {"f_locals", (getter)frame_getlocals, NULL, NULL}, 
    {"f_lineno", (getter)frame_getlineno, 
        (setter)frame_setlineno, NULL}, 
    {"f_trace",  (getter)frame_gettrace, (setter)frame_settrace, NULL}, 
    {"f_restricted",(getter)frame_getrestricted,NULL, NULL}, 
    {0} 
}; 

Für die PyMemberDef, die Fahnen RO oder READONLY bedeutet, es ist Attribute schreibgeschützt sind. Für die PyGetSetDef, wenn es nur einen Getter hat, ist es nur lesbar. Dies bedeutet, dass alle Attribute außer f_exc_type, f_exc_value, f_exc_traceback und f_trace nach der Erstellung schreibgeschützt sind. Dies wird auch in der Dokumentation unter Data model erwähnt.

Die Objekte, auf die sich die Attribute beziehen, sind nicht unbedingt schreibgeschützt. Sie können dies tun:

>>> f = sys._getframe() 
>>> f.f_locals['foo'] = 3 
>>> foo 
3 
>>> 

Obwohl dies in dem Dolmetscher arbeitet, schlägt es innerhalb von Funktionen. Die Ausführungs-Engine verwendet ein separates Array für lokale Variablen (f_fastlocals), das beim Zugriff auf f_locals zusammengeführt wird, aber die Umkehrung ist nicht wahr.

>>> def foo(): 
... x = 3 
... f = sys._getframe() 
... print f.f_locals['x'] 
... x = 4 
... print f.f_locals['x'] 
... d = f.f_locals 
... x = 5 
... print d['x'] 
... f.f_locals 
... print d['x'] 
... 
>>> foo() 
3 
4 
4 
5 
>>> 

Auf dem globalen Rahmen bezieht sich f_local auf f_globals, die diesen Trick Arbeit im Interpreter macht. Die Änderung f_globals funktioniert, betrifft jedoch das gesamte Modul.

+0

Interessant. Dies scheint das Verhalten einer interaktiven Shell zu sein, aber f_locals scheint nur in einem Skript gelesen zu werden. Siehe meine erweiterte Frage - dieser Codeausschnitt, der in einem Interpreter ausgeführt wird, scheint schreibgeschützt zu sein. – ConcernedOfTunbridgeWells

1

Das Beispiel f_locals ['foo'] von NXC funktioniert, weil der Code im Modulbereich ist. In diesem Fall ist f_locals f_globals, und f_globals ist sowohl modifizierbar als auch Änderungen werden im Modul widergespiegelt.

Innerhalb des Funktionsbereichs sind locals() und f_locals beschreibbar, aber "[Änderungen können sich nicht auf die Werte der vom Interpreter verwendeten lokalen Variablen auswirken." 1 Es ist eine Implementierung Wahl. In CPython gibt es einen optimierten Bytecode für lokale Variablen, LOAD_FAST. In Python sind lokale Variablen (fast immer) bekannt, sobald die Funktion definiert ist, und CPython verwendet eine Indexsuche, um den Variablenwert zu erhalten, anstatt eine Dictionary-Suche.

In der Theorie könnte die Wörterbuchsuche diese Tabelle ersetzen, aber das ist eine Menge Arbeit für wenig Gewinn.

Die Ausnahmen zu "lokalen Variablen sind bekannt" sind, wenn die Funktion eine exec-Anweisung verwendet, und die veraltete Fall von "von Modulimport *". Der erzeugte Bytecode ist für diese Fälle anders und langsamer.

Verwandte Themen