2

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

问题

我想让一个导入类的实例能够查看导入器范围(全局、本地)内的东西。由于我不确定这里工作的确切机制,我可以用片段而不是文字来更好地描述它。

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

这类任务是否有共同的习语/模式?我是不是完全找错树了?

4

2 回答 2

2

在此示例中,您可以简单地将函数作为对象传递给以下方法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在这个模块的命名空间中,因为我们导入了它

编辑:添加了关于如何显式传递环境的代码示例eval

于 2008-09-22T20:32:17.863 回答
1

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

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

您可能希望查看 string.Template 类,它试图做类似的事情。

于 2008-09-22T19:58:10.813 回答