【问题标题】:How to import package modules as __main__ aliases inside __init__.py?如何在 __init__.py 中将包模块作为 __main__ 别名导入?
【发布时间】:2012-10-16 22:13:06
【问题描述】:

我想使用 __init__.py 将包中的所有模块作为别名导入 __main__ 中,以便可以简单地从交互模式调用它们。例如,这是一个示例文件树:

foobar/
    __init__.py
    foo.py
    bar.py

我希望能够从 python 解释器导入包并使用定义的别名访问所有模块,如下所示:

>>> import foobar
>>> <module 'foobar' from 'C:\...'>
>>> f.func()
>>> b.func()

这将要求 __init__.py 包含以下内容:

# __init__.py

from . import foo as f
from . import bar as b

# these will not work
__main__.f = f
__main__.b = b

我怎样才能做到这一点?

编辑

我不想使用from foobar import *,因为它不允许我使用别名。

为每个模块输入from foobar import foo as f,每次我启动交互模式时效率不高,因为可能有数百个模块。

【问题讨论】:

  • 在涉及导入数百个模块的交互模式下,您在做什么?如果这是您工作流程的一部分,那么您似乎正在制造自己的问题。您总是可以只创建一个模块来导入所有其他模块(如果需要,可以使用别名),然后从中导入。

标签: python


【解决方案1】:

在您的 __init__.py 文件中包含以下内容:

import foo
import bar as b

然后在交互式会话中使用:

>>> from foobar import *
>>> value = foo.some_func()
>>> instance = b.SomeClass()

我还应该提到from foobar import * 被大多数 python 程序员认为是不好的风格,虽然这在交互式会话中并不重要,但如果你想在模块或脚本中完成同样的事情,首选的方式是:

from foobar import b, foo

【讨论】:

  • from foobar import * 仅在 __all__ 在 __init__.py 中定义时才有效。而且它不允许我使用别名。有太多模块需要显式导入,而且它们在不断变化。这就是为什么我想在__init__.py 处理它。
  • 如果__all__ 不存在于__init__.py 中,__init__.py 中不以下划线开头的所有内容都将由from foobar import * 导入。
  • 不管怎样,我不想使用from foobar import *,因为前面提到的原因。
  • from foobar import * 是您想要的机制,我不清楚您这样做的确切问题是什么,但根据您的问题和 cmets,这正是您所需要的。也许你可以澄清你的问题。此外,您永远不会通过执行import foobar 获得您所要求的行为,该导入语句只允许在命名空间中创建一个新项目。
  • "它不允许我使用别名。" (从上面)
【解决方案2】:

如果一个模块在没有被明确告知这样做的情况下将内容添加到单独模块的命名空间中,那将是非常糟糕的行为。 Explicit is better than implicit,正如他们所说。

我建议您避免在 __init__.py 中使用任何复杂的内容,只需在主模块(或命令行)中执行此操作:

import foobar.foo as f, foobar.bar as b

编辑:

如果你真的需要的话,可能会弄乱主模块。虽然这可能不是一个好主意,但方法如下:

import sys

import foo, bar

main = sys.modules["__main__"]
main.f = foo
main.b = bar

现在,正如一些人所说,让导入模块产生这样的副作用通常不是一个好主意。至少,任何读过你的代码的人都会非常困惑。 “等等,这个f变量是从哪里来的?”

我建议不要让你的模块在你的全局命名空间中插入东西,而是让它在它自己的命名空间中做你想要的别名,然后在它上面使用from module import * 来获取你命名空间中的别名。

使foobar 的__init__.py 文件看起来像这样:

from . import foo as f
from . import bar as b

然后在你的主模块中,做:

from foobar import *
# now you can use f and b

如果您有数百个导入操作,请将它们全部放入 __init__.py。或者,如果它们与该包无关,请使用单独的模块来处理别名。

【讨论】:

  • 那么在不输入交互式提示的情况下就没有办法将模块导入__main__?
  • 我怀疑这是可能的,但如果是这样,那将是一个可怕的黑客攻击。我强烈怀疑这是值得的,只是为了避免额外的打字。如果您需要别名,请明确要求!
  • 假设每次启动 Python 交互式提示时我需要导入 100 个模块。我不只是想避免“一点”额外的输入。
  • @redreceipt:我已经扩展了我的答案,既可以做你说你想做的事情,也可以为任何试图阅读和理解它的人提供一个更好的选择。
  • 谢谢!!这正是我所需要的。我同意您的第二种方法要好得多,但是与大多数开发的代码一样,我的代码也有上级的要求。尽管如此,我将推动使用更安全、更连贯的解决方案。 PS,您能否将您在我的主要问题中的评论移至此评论线程。对于其他读者来说,没有上下文就没有任何意义。
【解决方案3】:

根本没有指定 Python 模块像那样突破其命名空间,并且因为 Python 实际上倾向于限制通常不是一个好主意的所有内容,所以这是不可能的。交互式控制台可能有启动钩子之类的东西,谁知道呢。

另一个可以让您的生活更轻松的想法:写入模块:

foo = "foo!"
bar = "bar!"

def add_to(obj):
    obj['f'] = foo
    obj['b'] = bar

在您的交互式控制台中:

>>> from stuff import add_to
>>> add_to(globals())

【讨论】:

  • 我喜欢这个主意。有没有办法让__main__.globals() 成为默认参数?我知道它不像写的那样存在。
猜你喜欢
  • 2013-07-29
  • 1970-01-01
  • 1970-01-01
  • 2013-04-21
  • 2018-10-27
  • 2012-11-25
  • 2016-06-14
  • 1970-01-01
  • 2013-09-03
相关资源
最近更新 更多