请原谅这个模糊的标题。如果有人有任何建议,请告诉我!另外请用更合适的标签重新标记!

问题

我希望导入类的实例能够查看导入器范围(全局,本地)中的内容。由于我不确定这里的确切机制,我可以用片段来描述它,而不是单词。

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

然后从迭代会话中运行此代码,那里会有很多 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()')

这类任务是否有共同的习语/模式?我完全吠叫了错误的树吗?

有帮助吗?

解决方案

在这个例子中,您可以简单地将函数作为对象移交给 C1 中的方法:

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

在Python中,您可以将函数和类传递给其他方法,并在那里调用/创建它们。

如果您想要实际评估代码字符串,则必须指定环境,如Thomas所述。

上面的模块略有改动:

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

现在,在交互式解释器中:

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

一些注释

  1. 在这里,我们将 file1 中的所有对象插入到此模块的命名空间
  2. f2 不在 file1 的命名空间中,因此我们得到 NameError
  3. 现在我们明确地传递了环境,并且可以评估代码
  4. f1 位于此模块的命名空间中,因为我们导入了它
  5. 编辑:添加了有关如何为 eval 显式传递环境的代码示例。

其他提示

函数总是在它们定义的范围内执行,方法和类体也是如此。它们永远不会在另一个范围内执行。因为导入只是另一个赋值语句,并且Python中的所有内容都是引用,所以函数,类和模块甚至不知道它们的导入位置。

您可以做两件事:明确传递您希望它们使用的'环境',或使用堆栈hackery访问其调用者的命名空间。前者比后者更受青睐,因为它不像后者那样依赖于实现和脆弱。

您可能希望查看string.Template类,它尝试执行类似的操作。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top