Qual é o escopo para classes importadas em Python?
Pergunta
Por favor, desculpe o vago título. Se alguém tiver uma sugestão, por favor me avise! Além disso, reponha com tags mais apropriadas!
O problema
Quero ter uma instância de uma classe importada poder ver as coisas no escopo (globais, habitantes locais) do importador. Como não tenho certeza do mecanismo exato em ação aqui, posso descrevê -lo muito melhor com trechos do que palavras.
## File 1
def f1(): print "go f1!"
class C1(object):
def do_eval(self,x): # maybe this should be do_evil, given what happens
print "evaling"
eval(x)
eval(x,globals(),locals())
Em seguida, execute este código de uma sessão iterativa, haverá muitos NameErrors
## interactive
class C2(object):
def do_eval(self,x): # maybe this should be do_evil, given what happens
print "evaling"
eval(x)
eval(x,globals(),locals())
def f2():
print "go f2!"
from file1 import C1
import file1
C1().do_eval('file1.f1()')
C1().do_eval('f1()')
C1().do_eval('f2()')
file1.C1().do_eval('file1.f1()')
file1.C1().do_eval('f1()')
file1.C1().do_eval('f2()')
C2().do_eval('f2()')
C2().do_eval('file1.f1()')
C2().do_eval('f1()')
Existe um idioma / padrão comum para esse tipo de tarefa? Estou latindo completamente a árvore errada?
Solução
Neste exemplo, você pode simplesmente entregar funções como objetos aos métodos em C1
:
>>> class C1(object):
>>> def eval(self, x):
>>> x()
>>>
>>> def f2(): print "go f2"
>>> c = C1()
>>> c.eval(f2)
go f2
No Python, você pode passar funções e classes para outros métodos e invocar/criá -los lá.
Se você deseja avaliar uma sequência de código, deve especificar o ambiente, como já mencionado por Thomas.
Seu módulo de cima, ligeiramente alterado:
## File 1
def f1(): print "go f1!"
class C1(object):
def do_eval(self, x, e_globals = globals(), e_locals = locals()):
eval(x, e_globals, e_locals)
Agora, no intérprete interativo:
>>> def f2():
>>> print "go f2!"
>>> from file1 import * # 1
>>> C1().do_eval("f2()") # 2
NameError: name 'f2' is not defined
>>> C1().do_eval("f2()", globals(), locals()) #3
go f2!
>>> C1().do_eval("f1()", globals(), locals()) #4
go f1!
Algumas anotações
- Aqui, inserimos todos os objetos de
file1
no espaço para nome deste módulo f2
não está no espaço de nome defile1
, portanto, temos umNameError
- Agora passamos pelo ambiente explicitamente, e o código pode ser avaliado
f1
está no espaço de nome deste módulo, porque nós o importamos
Editar: Amostra de código adicionada sobre como passar explicitamente o ambiente para eval
.
Outras dicas
As funções são sempre executadas no escopo em que são definidas, assim como métodos e corpos de classe. Eles nunca são executados em outro escopo. Como a importação é apenas mais uma declaração de atribuição, e tudo no Python é uma referência, as funções, classes e módulos nem sabem para onde são importados.
Você pode fazer duas coisas: passar explicitamente o 'ambiente' que deseja que eles usem ou use o Stack Hackery para acessar o espaço para nome do chamador. O primeiro é muito preferido sobre o último, pois não depende da implementação e frágil como o último.
Você pode olhar para a classe String.Template, que tenta fazer algo semelhante.