Python中导入类的作用域是什么?
请原谅我这个模糊的标题。如果有人有好的建议,请告诉我!另外,也请用更合适的标签重新标记一下!
问题
我想让一个导入的类的实例能够查看导入者的范围内的东西(全局变量和局部变量)。因为我不太确定这里的具体机制,所以用代码片段来描述会比用文字更清楚。
## 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()')
有没有什么常见的做法或模式可以解决这个问题?我是不是在完全错误的方向上?
2 个回答
1
函数总是在它们被定义的范围内执行,方法和类的主体也是如此。它们从来不会在其他范围内执行。因为导入其实就是另一种赋值语句,而在Python中,所有东西都是引用,所以函数、类和模块根本不知道它们被导入到哪里。
你可以做两件事:明确传递你想让它们使用的“环境”,或者使用一些技巧来访问调用者的命名空间。前者比后者更受欢迎,因为前者不那么依赖具体实现,也更稳定。
你可能想看看string.Template类,它试图做一些类似的事情。
2
在这个例子中,你可以把函数当作对象直接传给
>>> 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
的代码示例。