C Python: Uruchamianie kodu Pythona w kontekście
Funkcja Python C APIPyEval_EvalCode
uruchommy skompilowany kod Pythona. Chcę wykonać blok kodu Pythonatak jakby był wykonywany w ramach funkcji, dzięki czemu ma swój własny słownik zmiennych lokalnych, które nie wpływają na stan globalny.
Wydaje się to łatwe, ponieważPyEval_EvalCode
pozwala dostarczyć słownik globalny i lokalny:
PyObject* PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
Problem, z którym się spotykam, dotyczy tego, jak Python wyszukuje nazwy zmiennych. Rozważmy następujący kod, który wykonujęPyEval_EvalCode
:
myvar = 300
def func():
return myvar
func()
Ten prosty kod powoduje błąd, ponieważ Python nie może znaleźć zmiennejmyvar
z wewnątrzfunc
. Nawet jeślimyvar
jest w lokalnym słowniku w zewnętrznym zasięgu, Python nie kopiuje go do lokalnego słownika w wewnętrznym zakresie. Powód tego jest następujący:
Ilekroć Python szuka nazwy zmiennej, najpierw sprawdzalocals
, to sprawdzaglobals
i wreszcie sprawdzabuiltins
. Wzakres modułu, locals
iglobals
są obiektem słownika SAME. Więc oświadczeniex = 5
w zakresie modułu zostanie umieszczonyx
w thelocals
słownik, który jest równieżglobals
słownik. Teraz funkcja zdefiniowana w zakresie modułu, który wymaga wyszukiwaniax
nie znajdziex
w zakresie funkcjilocals
, ponieważ Python nie kopiuje lokali z zakresu modułów do lokali z zakresu funkcji. Ale to zwykle nie jest problem, ponieważ może go znaleźćx
wglobals
.
x = 5
def foo():
print(x) # This works because 'x' in globals() == True
To tylko zzagnieżdżony funkcje, które Python wydaje się kopiować locals z zakresu zewnętrznego do locals zakresu wewnętrznego. (Wydaje się też, że robi to leniwie, tylko jeśli są potrzebne w wewnętrznym zakresie).
def foo():
x = 5
def bar():
print(x) # Now 'x' in locals() == True
bar()
Rezultatem tego wszystkiego jest to, że podczas wykonywania kodu wzakres modułu, MUSISZ upewnić się, że słownik globalny i słownik lokalny są obiektem SAME, w przeciwnym razie funkcje zakresu modułu nie będą mogły uzyskać dostępu do zmiennych zakresu modułu.
Ale w moim przypadku nie chcę, aby słownik globalny i słownik lokalny były takie same. Potrzebuję więc sposobu, aby powiedzieć interpreterowi Pythona, że wykonuję kod w zakresie funkcji. Czy jest jakiś sposób, aby to zrobić? Spojrzałem naPyCompileFlags
jak również dodatkowe argumentyPyEval_EvalCodeEx
i nie mogę znaleźć żadnego sposobu, aby to zrobić.