我有一个适用于以下文件的包:
# 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__
变量他们,但我似乎无法弄清楚我想要的正确用途是什么。我错了吗?
答案 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__.py
和Obj1
的别名导入的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并不要求每个类都有自己的文件。由于您希望Obj1
和Obj2
类分别可以从package.sub1
和package.sub2
命名空间访问,因此组合{{1}中的文件可能更有意义将文件夹放入单个subX
文件中(用一个较大的模块替换子包)。