请原谅这个模糊的标题。如果有人有任何建议,请告诉我!另外请用更合适的标签重新标记!
问题
我希望导入类的实例能够查看导入器范围(全局,本地)中的内容。由于我不确定这里的确切机制,我可以用片段来描述它,而不是单词。
## 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()')
这类任务是否有共同的习语/模式?我完全吠叫了错误的树吗?
答案 0 :(得分:1)
函数总是在它们定义的范围内执行,方法和类体也是如此。它们永远不会在另一个范围内执行。因为导入只是另一个赋值语句,并且Python中的所有内容都是引用,所以函数,类和模块甚至不知道它们的导入位置。
您可以做两件事:明确传递您希望它们使用的'环境',或使用堆栈hackery访问其调用者的命名空间。前者比后者更受青睐,因为它不像后者那样依赖于实现和脆弱。
您可能希望查看string.Template类,它尝试执行类似的操作。
答案 1 :(得分:1)
在此示例中,您可以简单地将函数作为对象移交给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!
file1
中的所有对象插入到此模块的命名空间f2
不在file1
的名称空间中,因此我们得到NameError
f1
位于此模块的命名空间中,因为我们已将其导入 修改:添加了有关如何明确传递eval
环境的代码示例。