python中导入的类的作用域是什么?

时间:2020-03-06 14:33:39  来源:igfitidea点击:

请原谅含糊不清的标题。如果有人有建议,请告诉我!另外,请使用更合适的标签重新标记!

问题

我希望有一个导入类的实例,以便能够查看导入器范围内的内容(全局,本地)。由于我不确定在这里工作的确切机制,因此我可以用摘要而不是文字来更好地描述它。

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

这类任务是否有共同的习惯用法/模式?我是否完全将错误的树吠叫?

解决方案

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

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

我们可能希望看一下string.Template类,它试图做类似的事情。

在这个例子中,我们可以简单地将函数作为对象移交给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环境的代码示例。