我正在尝试导入一个共享库,其中包含许多用于可视化程序的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的回答。
答案 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()