Python模块布局,子目录名与file相同



我习惯了脚本语言,它是非常常见的布局模块,像这样:

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

表示包被导入。我想,包具有优先权的事实并不总是如此。最后,最好通过重命名文件或包来消除名称冲突。

相关内容

最新更新