如何确定通过`from m import *`导入什么?

时间:2019-02-21 03:14:31

标签: python python-3.x import

我正在对导入语句进行一些修补,我需要确切地知道from m import *导入了哪些成员。文档似乎表明缺少__all__时,将导入所有不以下划线开头的成员。在所有情况下这都是正确的吗?我知道inspect.getmembers()dir()m.__dict__的逻辑都略有不同,因此我不确定哪个(如果有的话)会提供与import *相同的列表

3 个答案:

答案 0 :(得分: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__作为导入模块内的名称列表出现,则所有匹配的分配都将添加到当前本地范围,包括那些带有下划线前缀的名称。 (_)。否则,模块内所有以下划线开头的分配都将添加到当前本地范围。

答案 1 :(得分: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('_')]

答案 2 :(得分: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 ) )