在包中隐藏实现文件
我有一个叫做 spellnum
的模块。它可以作为命令行工具使用(因为里面有 if __name__ == '__main__':
这一部分),也可以像普通的 Python 模块一样被导入。
这个模块定义了一个叫 Speller
的类,长得像这样:
class Speller(object):
def __init__(self, lang="en"):
module = __import__("spelling_" + lang)
# use module's contents...
你可以看到,这个类的构造函数在运行时会加载其他模块。这些模块(比如 spelling_en.py
、spelling_es.py
等)和 spellnum.py
在同一个文件夹里。
除了 spellnum.py
,还有其他一些文件里有一些工具函数和类。我想把这些文件隐藏起来,因为我不想让用户看到它们,而且把这些随机文件放到 Python 的库目录里也不是个好主意。我知道的唯一方法就是创建一个包。
我为这个项目想出了这样的布局(灵感来自这个很棒的 教程):
spellnum/ # project root
spellnum/ # package root
__init__.py
spellnum.py
spelling_en.py
spelling_es.py
squash.py
# ... some other private files
test/
test_spellnum.py
example.py
文件 __init__.py
里只有一行:
from spellnum import Speller
有了这个新的布局,动态加载模块的代码也需要改一下:
class Speller(object):
def __init__(self, lang="en"):
spelling_mod = "spelling_" + lang
package = __import__("spellnum", fromlist=[spelling_mod])
module = getattr(package, spelling_mod)
# use module as usual
所以,按照这个项目布局,我可以做到以下几点:
在
example.py
中成功import spellnum
,并像简单模块一样使用它:# an excerpt from the example.py file import spellnum speller = spellnum.Speller(es) # ...
在测试中
import spellnum
,并从项目根目录运行这些测试,像这样:$ PYTHONPATH="`pwd`:$PYTHONPATH" python test/test_spellnum.py
问题
我无法直接用新的布局执行 spellnum.py
。当我尝试时,出现了以下错误:
Traceback (most recent call last):
...
File "spellnum/spellnum.py", line 23, in __init__
module = getattr(package, spelling_mod)
AttributeError: 'module' object has no attribute 'spelling_en'
问题
有什么好的方法来组织我模块所需的所有文件,以便用户可以从命令行和他们的 Python 代码中使用这个模块呢?
谢谢!
2 个回答
1
你的问题是,包的名字和你想要执行的Python文件名字是一样的,这样在导入的时候
from spellnum import spellnum_en
就会尝试从这个文件中导入,而不是从包中导入。你可以尝试使用相对导入的方法,但我不知道怎么和__import__
一起使用,所以我建议你试试下面的方法:
def __init__(self, lang="en"):
mod = "spellnum_" + lang
module = None
if __name__ == '__main__':
module = __import__(mod)
else:
package = getattr(__import__("spellnum", fromlist=[mod]), mod)
2
那我们要不要保留一下 spellnum.py
这个文件呢?
spellnum.py
spelling/
__init__.py
en.py
es.py