How to determine what is imported via `from m import *`?

好久不见. 提交于 2021-02-10 06:48:47

问题


I'm doing some patching of import statements, and I need to know exactly what members are imported by from m import *. The documentation seems to indicate that when __all__ is absent, all members will be imported that do not begin with an underscore. Is this exactly correct under all circumstances? I know that inspect.getmembers(), dir(), and m.__dict__ all have slightly different logic, so I'm not completely sure which (if any) will provide the same list as import *.


回答1:


Let's take a look at what that from m import * statement does:

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

The key here is that it actually invokes a dedicated opcode IMPORT_STAR, and this is implementation specific to the interpreter that will execute this code. This operator was originally specified in PEP-0221 but the implementation details specified is in the comments introduced by this specific commit.

In CPython, this is found in /Python/ceval.c (Python 3.7.2) and it in turns call import_all_from which shows the general logic on what that actually does inside the bytecode interpreter.

In PyPy, this is found in /pypy/interpreter/pyopcode.py, and again much like the C implementation it invokes the import_all_from function defined in RPython, which again has a similar logic but in a more familiar syntax for Python programmers.

In both the CPython and pypy implementation, if __all__ is presented as a list of names inside the imported module, all matching assignments will be added to the current local scope, including those names that are prefixed with an underscore (_). Otherwise, every assignment inside the module that do not start with an underscore will be added to the current local scope.




回答2:


I'm currently using the following function to get a list of names and calling getattr(m, name) on each 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:


This is probably the hackiest thing you'll see all day, but it might do the trick.

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


来源:https://stackoverflow.com/questions/54798679/how-to-determine-what-is-imported-via-from-m-import

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!