导入共享库和全局命名空间

时间:2011-12-01 22:02:45

标签: python shared-libraries

我正在尝试导入一个共享库,其中包含许多用于可视化程序的Python包装器(VisIt是特定的)。这个库的实现方式是首先导入库,这使得一些函数可用,然后调用一个函数来启动visualisaion查看器并使其余的API可用于调用。例如,在下面的

form visit import *
print dir()
Launch()
print dir()

第一个print语句包含常用的内置函数和一些其他函数

['AddArgument', 'GetDebugLevel', 'Launch', 'SetDebugLevel', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__warningregistry__']

并且第二次打印产生

['ActivateDatabase', 'AddArgument', 'AddColorTable', 'AddOperator', 'AddPlot', ... ]

我希望在一个函数中调用Launch(这样我就可以处理并将参数传递给Launch)。但是,当我执行此操作时,在调用Launch之后可用的函数不在全局命名空间中,而是在函数本地的命名空间中。所以在下面的例子中

import sys
from visit import *

def main():

    Launch()
    print dir()
    if "Version" in dir()
        print Version() # This is made available by call to Launch() above

    return 0

if __name__=="__main__":
    ret = main()
    print dir()
    sys.exit(ret)

print中的main语句将打印

['ActivateDatabase', 'AddArgument', 'AddColorTable', 'AddOperator', 'AddPlot', ... ]

如上所述,而print之后的main被称为打印

['AddArgument', 'GetDebugLevel', 'Launch', 'SetDebugLevel', '__builtins__', '__doc__', '__file__', '__name__', '__package__', '__warningregistry__']

好像从未调用Launch

我的第一个问题是如何通过调用Launch来确保填充全局命名空间?

其次,对Version的调用实际上失败了,错误

  

NameError:未定义全局名称“版本”

即使print "Version" in dir()返回True。如果我解决了我的第一个问题,这个问题是否会得到解决,或者这完全是另一回事?

如果您需要有关共享库上方的更多信息,请与我们联系。我不太了解它是如何写的,但我可以试着找出来。

编辑:根据@voithos的回答,以下是我采用的解决方案。

如@voithos所述,“访问使用动态导入,将所有内容带到本地范围......假设您永远不会在全局范围之外调用visit.Launch()。”他的(初始)答案允许我使用visit.Launch()提供的函数在我的主例程之外(和之后)使用,使用前缀visit.和所有这些例程。

要将VisIt例程导入为from visit import *,以便可以在没有visit.前缀的情况下调用它们,我会修改@voithos在setattr中使用main以下内容

# Loop through the local namespace and add the names that were just
# imported to the module namespace
loc = locals()
for key in loc:
    setattr(sys.modules[__name__], key, loc[key])

然后VisIt例程在模块级别可用,一切似乎都很好。

感谢@voithos的回答。

2 个答案:

答案 0 :(得分:2)

似乎Visit使用动态导入,将所有内容都带到了本地范围。基本上,他们假设您永远不会在全局范围之外调用visit.Launch()。启动函数都是用C ++编写的,所以我不确定它是如何导入的。

一种解决方法是将名称从本地范围重新分配到另一个范围。 (例如,进入您导入的visit模块)以下是一个示例:

import sys
import visit

def main():
    visit.Launch()

    # Loop through the locals that were just imported
    # and assign the names to the visit module
    loc = locals()
    for key in loc:
        setattr(visit, key, loc[key])

    return 0

if __name__=="__main__":
    ret = main()
    print dir(visit)
    sys.exit(ret)

如果您想将名称分配给全局范围,则可以将循环修改为:

loc = locals()
glob = globals()

for key in loc:
    glob[key] = loc[key]

但请注意:执行此操作将覆盖之前定义的任何冲突符号名称。例如,如果您定义了Version()函数,则“访问”模块中的Version()将覆盖您定义的旧版本。因此,除非你真的需要,否则通常不要用名称来混淆全局范围。

答案 1 :(得分:0)

我从未使用过VisIt,但根据他们的文档,您需要这样做:

import visit

def main():    
    visit.Launch()

将所有函数导入'visit'命名空间。然后,您只需通过访问命名空间与库的功能进行交互。如:

visit.Version()