Pregunta

Disculpe el título vago.Si alguien tiene una sugerencia, ¡hágamela saber!¡También vuelva a etiquetar con etiquetas más apropiadas!

El problema

Quiero que una instancia de una clase importada pueda ver cosas en el ámbito (global, local) del importador.Como no estoy seguro del mecanismo exacto que funciona aquí, puedo describirlo mucho mejor con fragmentos que con palabras.

## 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())

Luego ejecute este código desde una sesión iterativa, habrá muchos 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 un modismo/patrón común para este tipo de tarea?¿Estoy ladrando al árbol equivocado por completo?

¿Fue útil?

Solución

En este ejemplo, puede simplemente entregar funciones como objetos a los métodos en C1:

>>> class C1(object):
>>>    def eval(self, x):
>>>        x()
>>>
>>> def f2(): print "go f2"
>>> c = C1()
>>> c.eval(f2)
go f2

En Python, puedes pasar funciones y clases a otros métodos e invocarlas/crearlas allí.

Si realmente desea evaluar una cadena de código, debe especificar el entorno, como ya mencionó Thomas.

Su módulo desde arriba, ligeramente cambiado:

## 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)

Ahora, en el intérprete interactivo:

>>> 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!

Algunas anotaciones

  1. Aquí insertamos todos los objetos de file1 en el espacio de nombres de este módulo
  2. f2 no está en el espacio de nombres de file1, por lo tanto obtenemos un NameError
  3. Ahora pasamos el entorno explícitamente y el código se puede evaluar.
  4. f1 está en el espacio de nombres de este módulo, porque lo importamos

Editar:Se agregó un ejemplo de código sobre cómo pasar explícitamente el entorno para eval.

Otros consejos

Las funciones siempre se ejecutan en el ámbito en el que están definidas, al igual que los métodos y los cuerpos de las clases.Nunca se ejecutan en otro ámbito.Debido a que importar es solo otra declaración de asignación, y todo en Python es una referencia, las funciones, clases y módulos ni siquiera saben a dónde se importan.

Puedes hacer dos cosas:pase explícitamente el 'entorno' que desea que usen, o use piratería de pila para acceder al espacio de nombres de la persona que llama.El primero es ampliamente preferido al segundo, ya que no depende tanto de la implementación ni es tan frágil como el segundo.

Es posible que desees mirar la clase string.Template, que intenta hacer algo similar.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top