将Python包中的符号导入调用者命名空间
我有一个小的内部领域特定语言(DSL),它是用一个Python文件写的,随着时间的推移,它变得越来越复杂,我想把内容分散到多个不同的目录和文件中。
现在新的目录结构看起来是这样的:
dsl/
__init__.py
types/
__init__.py
type1.py
type2.py
每个类型的文件里都包含一个类(比如说 Type1
)。
我遇到的问题是,我希望使用这个DSL的代码尽可能简单,比如说:
import dsl
x = Type1()
...
这意味着所有重要的符号应该直接在用户的命名空间中可用。我尝试更新顶层的 __init__.py
文件,以导入相关的符号:
from types.type1 import Type1
from types.type2 import Type2
...
print globals()
输出显示符号确实被正确导入了,但在调用代码中(也就是执行 import dsl
的代码)仍然没有这些符号。我认为问题在于这些符号实际上是被导入到了 'dsl' 的命名空间中。我该如何改变这个,让类也能直接在调用者的命名空间中可用呢?
4 个回答
1
@Eli, @Daniel,谢谢你们的“恍然大悟”回答。我差不多明白了,但还需要一点额外的提示...
其实解决方案分为两个步骤:第一步是使用包的初始化器,把“导出的”二级符号拉到顶层的 dsl
包里(这一点我已经做到了),第二步是用 from dsl import *
把这些符号引入到调用者的代码中。这是合理的,因为调用者应该掌控自己想要引入到命名空间里的内容。
一般来说,from pkg import *
这种写法是不太被推荐的,但在这种情况下,我觉得这是个合理的解决方案,因为我这个包导出的符号数量会很有限。
2
我会这样做
在 dsl/init__.py 文件中,添加
def import_symbols(namespace):
namespace['type1'] = dsl.types.type1
namespace['type2'] = dsl.types.type2
从调用者那里,执行
import dsl
dsl.import_symbols(globals())
不仅可以从第二级包中导入符号到你当前的命名空间,通过定义你自己的 import_symbols()
,你还可以更明确地控制要导入哪些符号,而不是用 import *
一下子导入所有东西。
4
你需要这样说
from dsl import *