我需要在`__init __。py`文件中放置什么来简化这个包的界面?

时间:2016-08-11 22:37:30

标签: python

我有一个适用于以下文件的包:

# package/sub1/obj1.py
class Obj1:
    pass

# package/sub2/obj2.py
from ..sub1.obj1 import Obj1
class Obj2(Obj1):
    pass

目前,如果文件与package文件夹处于同一级别,我需要这样做:

from package.sub1.ob1 import Obj1
from package.sub2.ob2 import Obj2

我希望能够使用以下内容:

from package.sub1 import Obj1 # can reference package.sub1.Obj1
from package.sub2 import Obj2 # can reference package.sub2.Obj2
from package import * # Can reference both

我知道我需要编辑三个现有__init__.py文件中的一个或多个,我认为我需要在一个或多个中设置__all__变量他们,但我似乎无法弄清楚我想要的正确用途是什么。我错了吗?

2 个答案:

答案 0 :(得分:3)

假设您在__init__.py文件中没有其他任何内容,除了以下内容之外,这应该有效:

# package/sub1/__init__.py
from package.sub1.obj1 import Obj1

# package/sub2/__init__.py
from package.sub2.obj2 import Obj2

# package/__init__.py
from package.sub1 import Obj1
from package.sub2 import Obj2

在此之后,您的3个用例应该有效。除非__all__中有其他内容,否则您不应该需要__init__.py,请注意,这只会影响加载所有语法from package import *

使用package/__init__.pyObj1的别名导入的Obj2文件的一个好处是,您可以重新构建整个子包,而不必更改package/__init__.py只要package/sub*/__init__.py文件反映新结构。

编辑:平面与嵌套

(从其他答案的评论中复制)

对于您的软件包的用户来说,最好尽可能使您的软件包显得平整,但对于开发人员来说,它可能是任何结构。例如,如果您的包主要通过Obj1类使用,那么必须执行from package.sub1.obj1 import Obj1。另一方面,作为开发人员,必须将一个大型软件包/模块中的所有Obj1依赖项与其余软件包组织在一起。以我们所描述的方式使用导入将使其在下面组织时显得平坦。

答案 1 :(得分:3)

您可以通过将以下内容添加到__init__.py文件中来使其正常工作:

package/sub1/__init__.py

from .ob1 import Obj1

package/sub2/__init__.py

from .ob2 import Obj2

package/__init__.py

__all__ = ['sub1', 'sub2']

现在,顶级代码可以执行您询问的任何导入,并且他们会使package.subX.ObjX成为有效名称。

这是一个好设计吗?并不是的。优秀的Python设计原则之一是"flat is better than nested"。正如user2357112评论的那样,与其他语言不同,Python并不要求每个类都有自己的文件。由于您希望Obj1Obj2类分别可以从package.sub1package.sub2命名空间访问,因此组合{{1}中的文件可能更有意义将文件夹放入单个subX文件中(用一个较大的模块替换子包)。