我习惯了脚本语言,它是非常常见的布局模块,像这样:
lib/Foo.pm
lib/Foo/Bar.pm
lib/Foo/Baz.pm
你有Foo。然后有一个名为Foo的目录,下面放置子模块。
在Python中,我尝试模仿这样的布局:
modules/foo.py
modules/foo/bar.py
modules/foo/baz.py
然而,这不会工作,因为当我这样做:
from foo import Foo
Python认为我导入的是一个名为'foo'的目录,而不是foo.py。我试图打乱init.py业务,但无济于事。
有办法绕过这个问题吗?我发现Python不能区分目录foo和文件foo.py,这很烦人。
编辑:我想我漏掉了一个重要的部分。我通过我的单元测试找到了模块/目录,所以整个目录结构看起来像这样:
modules/foo.py
modules/foo/bar.py
modules/foo/baz.py
tests/unit.py
在unit.py中,我有以下内容:
#!/usr/bin/python
import sys
import os
findbin = os.path.abspath(os.path.dirname(sys.argv[0]))
sys.path.append(findbin + "/../modules")
from foo import Foo
obj = Foo()
当我运行这个,我得到:
from foo import Foo
ImportError: cannot import name Foo
您想要创建的是包。
在文件夹foo
中放置一个名称为__init__.py
的空白文件。然后Python将foo视为一个包。如果modules
也要作为一个包装来处理,也要在里面放一个空白的__init__.py
。
那么从你的问题来看,如果包被正确地完成并且你有这样的结构:
modules/__init__.py
modules/foo/__init__.py
modules/foo/bar.py
modules/foo/baz.py
你可以这样做:
import module
from module import foo
from module.foo import bar
import module.foo.bar as foobar
还有很多其他的东西!
你必须做:
modules/foo/__init__.py # instead of foo.py
modules/foo/bar.py
modules/foo/baz.py
Perl的布局不工作;如果一个模块有子模块,根模块就在它们旁边。
对于它的价值,一些Python开发人员强烈认为您应该将__init__.py
保留为空(或至少最小化),因为每当导入任何子元素时,它都会首先导入。
这是可能的,你也有一些其他的问题,如果__init__.py
没有为你工作,特别是如果你真的有一个modules/
目录,但我无法诊断没有更多的细节:)
啊哈。不混淆sys.path
;总是表明你让自己的生活变得更艰难。(你是否必须使用sys.path
来导入其他人的代码?那么,既然它就在那里,你为什么还要自己去做呢?)
直接将它们放在源代码树的根目录中,如project.git/foo/bar.py
。只要您从根目录运行您的测试工具(或其他),您就可以导入它们而不会出现任何问题。
你可能还想尝试一个像pytest这样的测试库,它可以为你发现和一些各种各样的奇特的东西。
参见:Python项目的文件系统结构
或者是我的一个更实际的例子:https://github.com/eevee/dywypi
使用Python创建包可以使用__init__.py
文件完成,但了解导入优先级很重要。命令
from foo import Foo
将在sys.path
中查找名为foo
的内容,然后在foo
中查找名为Foo
的内容。例如,假设目录foo
中没有任何__init__.py
文件,而foo.py
文件包含
class Foo:
def __init__(self):
print 'hello'
在模块目录中输入命令from foo import Foo
就可以了。
>>> from foo import Foo
>>> f = Foo()
hello
如果您希望目录foo
是一个包(即相关模块的集合),那么您可以在foo
目录下放置一个空的__init__.py
文件。然而,这将使import
命令具有歧义性。我还没有找到任何声称包的导入优先级高于模块的文档,但您可以通过执行以下操作来验证Python正在导入包,
import foo
>>> foo.__file__
foo/__init__.py
表示包被导入。我想,包具有优先权的事实并不总是如此。最后,最好通过重命名文件或包来消除名称冲突。