如何通过`from m import *`确定导入的内容?

问题描述 投票:2回答:3

我正在修改import语句,我需要确切地知道from m import *导入的成员。文档似乎表明,当__all__不存在时,将导入所有不以下划线开头的成员。这在任何情况下都完全正确吗?我知道inspect.getmembers()dir()m.__dict__的逻辑都略有不同,所以我不完全确定哪个(如果有的话)会提供与import *相同的列表。

python python-3.x import
3个回答
4
投票

让我们来看看from m import *声明的作用:

>>> dis.dis(compile('from m import *', '<module>', 'single'))
  1           0 LOAD_CONST               0 (0)
              2 LOAD_CONST               1 (('*',))
              4 IMPORT_NAME              0 (m)
              6 IMPORT_STAR
              8 LOAD_CONST               2 (None)
             10 RETURN_VALUE

这里的关键是它实际上调用了一个专用的操作码IMPORT_STAR,这是执行此代码的解释器特有的实现。此运算符最初在PEP-0221中指定,但指定的实现细节在this specific commit引入的注释中。

在CPython中,这可以在/Python/ceval.c(Python 3.7.2)中找到,它依次调用import_all_from,它显示了字节码解释器中实际内容的一般逻辑。

在PyPy中,这可以在/pypy/interpreter/pyopcode.py中找到,并且很像C实现,它调用RPython中定义的import_all_from函数,它再次具有类似的逻辑,但是对于Python程序员来说是更熟悉的语法。

在CPython和pypy实现中,如果__all__在导入的模块中显示为名称列表,则所有匹配的赋值都将添加到当前本地范围,包括以下划线为前缀的名称(_)。否则,模块内不以下划线开头的每个赋值都将添加到当前本地范围。


0
投票

我目前正在使用以下函数获取名称列表并在每个名称上调用getattr(m, name)

def public_members(module):
    try:
        return module.__all__  # If not iterable, imports will break.
    except AttributeError:
        return [name for name in dir(module) if not name.startswith('_')]

0
投票

这可能是你整天都会看到的最讨厌的东西,但它可能会成功。

bound = globals().copy()
from module import *
for k, v in list( globals().items() ):
    if k not in bound or bound[ k ] != v:
        print( 'new', repr( k ), repr( v ) )
© www.soinside.com 2019 - 2024. All rights reserved.