考虑以下包结构:
foo/ # package name
foo/ # module name
__init__.py
foo.py # contains "bar" method
exceptions.py # contains "BarException" class
现在为了调用bar方法,我们必须这样做(我想丢失一个foo
):
import foo
foo.foo.bar()
现在我知道有可能"导入... as" (和from ... import
),但是没有办法让方法在树中更高可用吗?
我 想要诉诸的事情:
from ... import ...
foo.py
代码改为__init__.py
一个例子是让foo.exceptions.BarException
定义我的异常类。
每当我想让用户可以使用它们时,我都不希望它们exceptions.py
,而是能够呼叫foo.exceptions.BarException
。
目标:
foo.BarException
答案 0 :(得分:2)
在__init__.py
中,您可以从包中的其他模块导入内容。如果您__init__.py
from .foo import bar
import foo
,那么有人可以foo.bar
访问__init__.py
。如果在from .exceptions import BlahException
import foo
foo.BlahException
,则有人可以Blah
然后执行from
。
但是,你应该警惕这一点太过分了。在包和模块中使用嵌套有一个目的,即创建单独的命名空间。明确地将一些常见的东西从子模块导入到顶层是很好的,但是如果你开始尝试隐式地使所有内容在顶层可用,那么你就会为自己设置名称冲突(例如,如果一个模块定义了一个名为__init__.py
然后另一个模块也会这样做,但没有意识到当它们都导入到顶级时它们会发生碰撞。
“强制”用户使用foo
并不是一个繁重的要求。如果使用你的库需要繁琐的导入,这可能表明你的包/模块结构过于繁琐,你应该结合一些东西,而不是将它们分成单独的目录/文件。
顺便提一下,您在帖子中指出的文件结构存在一些问题。您显示的顶级foo不是包,因为它没有foo
。第二级foo不是模块,因为它不是文件。在您的示例中,第二级foo.py
是一个包,其中包含一个名为foo
的模块(在文件Undefined symbols for architecture armv7:"_SecCertificateCopyData", referenced from:-[AFSecurityPolicy evaluateServerTrust:forDomain:] in AFSecurityPolicy.o
中);顶级[trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)];
目录在Python打包系统中没有状态。
答案 1 :(得分:2)
如果您的软件包和子模块名称不同,这将更容易理解,因此我会假装您这样做,并让您根据需要进行翻译。另请注意,与您的评论相反,前foo
不是软件包名称,它只是某个目录(可能是)在sys.path
某处,而且第二个foo
不是模块名称而是包名称,第三个foo
是模块名称。所以:
foo/ # directory package is in
spam/ # package name
__init__.py
eggs.py # contains "bar" method
exceptions.py # contains "BarException" class
您想要做的关键是:
spam/__init__.py
中的任何全局名称都是spam
包的成员。它们是否实际在__init__.py
或import
来自其他地方定义并不重要。因此,如果您想将spam.eggs.bar
功能设为spam.bar
,您只需将此行添加到spam/__init__.py
:
from .eggs import bar
如果__all__
中有spam/__init__.py
个属性来定义spam
的公共属性,则需要将bar
添加到该列表中:
__all__ = ['other', 'stuff', 'directly', 'in', 'spam', 'bar']
如果您想将spam.eggs
中的所有内容公开作为spam
的公开部分重新导出,您可以这样做:
from .eggs import *
__all__ = ['other', 'stuff', directly', 'in', spam'] + eggs.__all__
当然,您可以将其扩展到多个子模块:
from .eggs import *
from .exceptions import *
__all__ = (['other', 'stuff', directly', 'in', spam'] +
eggs.__all__ +
exceptions.__all__)
这在stdlib和流行的第三方软件包中很常见。有关一个很好的示例,请参阅Python 3.4中的asyncio/__init__.py
源代码。
然而,它只在这个完全的情况下才真正常见:你希望你的用途能够像对待一个简单的扁平模块那样对待你的包,但它实际上有一些内部结构(或者因为实现过于复杂,或者因为偶尔用户需要这种结构)。如果你从孙子,兄弟姐妹或父母而不是孩子那里取名,你可能会滥用这个成语(至少你应该停下来并说服自己,你不是)。