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