python - 使方法在包中的更高级别可用

标签 python package

考虑以下包结构:

foo/                          # package name
    spam/                     # module name
        __init__.py
        eggs.py               # contains "bar" method
        exceptions.py         # contains "BarException" class

现在为了调用 bar 方法,我们必须做

import spam
spam.eggs.bar()

我想丢掉鸡蛋

现在我知道可以import ... as(和from ... import),但是没有办法让方法在更高层可用一棵树?

不想想诉诸的事情:

  • 很多 from ... import ...
  • 将我的 eggs.py 代码放在 __init__.py
  • 加星标的导入
  • spam.exceptions.BarException 这样的长名称(可能更长)

一个例子是在 exceptions.py 中定义我的异常类。

每当我想让用户可以使用它们时,我都不希望他们使用 spam.exceptions.BarException,而是能够使用 spam.BarException.

目标:

import spam
try:
    spam.bar()   # in this case throws BarException
except spam.BarException:
    pass

最佳答案

请注意,与您的评论相反,顶部 foo 不是包名称,它只是(大概)在您的 sys.path 某处的目录,并且spam不是模块名而是包名,eggs是模块名。所以:

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 中定义的,还是从其他地方导入的,这并不重要。

所以,如果你想让 spam.eggs.bar 函数作为 spam.bar 可用,你所要做的就是将这一行添加到 垃圾邮件/__init__.py:

from .eggs import bar

如果你在 spam/__init__.py 中有一个 __all__ 属性来定义 spam 的公共(public)属性,你会想要添加 bar 到那个列表:

__all__ = ['other', 'stuff', 'directly', 'in', 'spam', 'bar']

如果你想从 spam.eggs 中重新导出 everything public 作为 spam 的公共(public)部分,你可以这样做:

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 和流行的第三方包中很常见。有关一个很好的例子,请参阅 asyncio/__init__.py 的来源来自 Python 3.4。

但是,它只在这种确切情况下才真正常见:您希望您的用户能够将您的包视为一个简单的平面模块,但它实际上有一些内部结构(要么是因为否则实现会太复杂,要么是因为用户偶尔会需要这种结构)。如果您使用的是孙子、 sibling 或 parent 而不是 child 的名字,则您可能在滥用习语(或者至少您应该停下来并说服自己没有滥用)。

关于python - 使方法在包中的更高级别可用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30429022/

相关文章:

python - 添加行/列时维护公式

javascript - grunt "test command"在 npm init 上做了什么

Android: 错误调用:在 uid 10121 下指定包 **** 但它确实是 -1

python - 如何将线程添加到 PyQt5 GUI?

python - 为什么 inspect() 认为 map 不是内置的?

java - 在代码中检测 PDF 包或组合

delphi - 对 Delphi 中的运行时和设计时包大惊小怪

r - 如何正确安装和加载dplyr?

python - 使用 spotipy 提取艺术家流派和歌曲发布日期

python - 在 Django ORM 中使用 'and' 和使用 '&' 的区别