C Python: Executando o código Python dentro de um contexto
A função da API do Python CPyEval_EvalCode
vamos executar código Python compilado. Eu quero executar um bloco de código Pythoncomo se estivesse executando dentro do escopo de uma função, de modo que ele tenha seu próprio dicionário de variáveis locais que não afetam o estado global.
Isso parece fácil de fazer, já quePyEval_EvalCode
permite fornecer um dicionário global e local:
PyObject* PyEval_EvalCode(PyCodeObject *co, PyObject *globals, PyObject *locals)
O problema que eu corri tem a ver com a forma como o Python procura nomes de variáveis. Considere o seguinte código, que eu executo comPyEval_EvalCode
:
myvar = 300
def func():
return myvar
func()
Este código simples, na verdade, gera um erro, porque o Python é incapaz de encontrar a variávelmyvar
de dentrofunc
. Apesar demyvar
está no dicionário local no escopo externo, o Python não o copia no dicionário local no escopo interno. A razão para isso é a seguinte:
Sempre que o Python procurar um nome de variável, primeiro ele verificalocals
, então verificaglobals
e finalmente verificabuiltins
. Noescopo do módulo, locals
eglobals
são o mesmo objeto do dicionário. Então a afirmaçãox = 5
no escopo do módulo irá colocarx
no olocals
dicionário, que é também oglobals
dicionário. Agora, uma função definida no escopo do módulo que precisa procurarx
não vai encontrarx
dentro do escopo da funçãolocals
, porque o Python não copia locals de escopo de módulo em locais de escopo de função. Mas isso normalmente não é um problema, porque pode encontrarx
emglobals
.
x = 5
def foo():
print(x) # This works because 'x' in globals() == True
É só comaninhado funções, que o Python parece copiar os locais do escopo externo em locais do escopo interno. (Também parece fazê-lo preguiçosamente, somente se forem necessários dentro do escopo interno).
def foo():
x = 5
def bar():
print(x) # Now 'x' in locals() == True
bar()
Então o resultado de tudo isso é que, ao executar o código emescopo do módulo, você precisa ter certeza de que seu dicionário global e dicionário local são o mesmo objeto, caso contrário, funções de escopo de módulo não poderão acessar variáveis de escopo de módulo.
Mas no meu caso, eu não quero que o dicionário global e o dicionário local sejam os mesmos. Então eu preciso de alguma maneira de dizer ao interpretador Python que estou executando o código no escopo da função. Existe alguma maneira de fazer isso? Olhei para oPyCompileFlags
bem como os argumentos adicionais paraPyEval_EvalCodeEx
e não consigo encontrar nenhuma maneira de fazer isso.