【问题标题】:How to determine what is imported via `from m import *`?如何确定通过`from m import *`导入的内容?
【发布时间】:2019-02-21 03:14:31
【问题描述】:

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

【问题讨论】:

  • docs.python.org/2/tutorial/modules.html#more-on-modules "这会导入除下划线 (_) 开头的名称以外的所有名称。请注意,通常不赞成从模块或包中导入 * 的做法,因为它通常会导致可读性差代码。但是,可以使用它来节省交互式会话中的输入。”

标签: python python-3.x import


【解决方案1】:

让我们看一下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 引入的cmets 中。

在 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__ 在导入的模块中显示为名称列表,则所有匹配的分配都将添加到当前本地范围,包括前缀为下划线(@ 987654335@)。否则,模块内以下划线开头的每个赋值都将被添加到当前本地范围中。

【讨论】:

  • 关键点似乎是,如果__all__不存在,那么它会从m.__dict__中抓取key并调用getattr()。这与getmembers()dir()不同,甚至与m.__dict__.items()略有不同。
【解决方案2】:

我目前正在使用以下函数来获取名称列表并在每个名称上调用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('_')]

【讨论】:

    【解决方案3】:

    这可能是你一整天都会看到的最骇人听闻的东西,但它可能会奏效。

    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 ) )
    

    【讨论】:

      猜你喜欢
      • 2021-12-25
      • 2015-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多