Python 3中星号导入的函数形式是什么?

24

在Python中,使用函数(可能是从importlib导入的)有没有相当于import *的等效方式?

我知道你可以使用mod = __import__(...)来导入模块,它将委托给当前配置的实现。你也可以这样做:

mod_spec = importlib.utl.spec_from_file_location(...)
mod = importlib.util.module_from_spec(mod_spec)
mod_spec.loader.exec_module(mod)

这允许您做一些疯狂的事情,比如在调用 exec_module 之前插入它们以将它们注入模块。(参考自https://dev59.com/anVD5IYBdhLWcg3wKYP-#67692https://stackoverflow.com/a/38650878/2988730)

然而,我的问题仍然存在。在函数形式中,import * 如何工作?哪个函数根据 __all__ 的存在/内容来确定从模块加载哪些名称?


3
据我所知,from mod import * 并没有以某种方式暴露出来,它有一个特殊的字节码生成,并由 C 代码处理。 - Dimitris Fasarakis Hilliard
@JimFasarakis-Hilliard。虽然有可能,但我会继续等待答案。Importlib公开或至少复制了一些非常详细的功能。我一直认为它具有完整的加载机制,但是还没有找到这个特定的部分。 - Mad Physicist
移除了通用的Python标签。 - Mad Physicist
1
我也不确定,所以我选择了留言。为什么要删除Python标签?这样会排除许多不在“3.x”标签中潜伏的人看到它。 - Dimitris Fasarakis Hilliard
1
@JimFasarakis-Hilliard。我的问题特别与Python3有关,但我想你说得很对。已经恢复。 - Mad Physicist
3
所有与 python 相关的问题都应该打上通用的 python 标签。如果一个问题是关于特定版本的,可以在通用标签之外再添加一个更具体的标签。请注意,这个更具体的标签只是作为补充,而不是替代通用标签。 - juanpa.arrivillaga
1个回答

22

没有from whatever import *的功能。实际上,也没有import whatever的功能!当你这样做时:

mod = __import__(...)

__import__函数只负责部分工作。它提供了一个模块对象,但您必须单独将该模块对象分配给变量。没有函数可以像import whatever那样同时导入模块并将其分配给变量。


from whatever import *中,有两个部分:

  • whatever准备模块对象
  • 分配变量

"准备模块对象"部分与import whatever几乎相同,并且可以由同一函数__import__处理。唯一的差异是import *将加载包中__all__列表中尚未加载的任何子模块;如果您提供fromlist=['*'],则__import__会为您处理此操作:

module = __import__('whatever', fromlist=['*'])

命名赋值是存在巨大差异的部分,同样,你需要自己处理。只要你在全局范围内,这是相当简单明了的。

if hasattr(module, '__all__'):
    all_names = module.__all__
else:
    all_names = [name for name in dir(module) if not name.startswith('_')]

globals().update({name: getattr(module, name) for name in all_names})

函数作用域不支持在运行时确定变量赋值。


我同意没有函数可以完全替换这两个语句,但是有一个等效的函数调用(或者一些调用)可以完成相同的事情。我非常惊讶(并且有点怀疑)你提供的选择代码在importlib中不存在。 - Mad Physicist
@MadPhysicist:他们不会提供一个为你分配变量的函数。这太神奇了,而且它只能在全局或类范围内使用。(Python 3 的常规 import * 只能在全局范围内使用,但是函数内部的常规 import * 可以在编译时被捕获)。 - user2357112
那很有道理。我会等一天左右,然后选择你的答案。 - Mad Physicist
1
只是最后处理了 fromlist=['*']。那是唯一的非平凡部分,所以特别感谢您。 - Mad Physicist
只是为了明确 - 如果没有__all__指令,那么如果whatever是一个包,from whatever import *会导入_所有子模块_还是只有whatever/__init__.py中的名称? - Mr_and_Mrs_D
1
@Mr_and_Mrs_D:它将导入在 __init__.py 结束时被加载的任何子模块。这些子模块取决于程序中已执行了哪些其他导入操作。 - user2357112

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接