如何以编程方式查找使用 Python import * 命令导入的符号?

How do I programatically find what symbols were imported with Python import * command?

我有一个系统可以收集所有从特定基数 类 派生的 类 并将它们存储在字典中。我想避免必须指定哪些 类 可用(我想以编程方式发现它们),因此使用了 from ModuleName import * 语句。然后指示用户将所有要收集的测试放在 ModuleName 模块中。但是,我找不到一种方法来以编程方式确定使用该导入语句导入了哪些符号。我已尝试使用 dir()__dict__,如下例所示,但无济于事。如何以编程方式找到以这种方式导入的符号(使用 import *)?我无法通过上述方法找到它们。

testTypeFigureOuterrer.py:

from testType1 import *
from testType2 import *

class TestFigureOuterrer(object):

    def __init__(self):
        self.existingTests = {'type1':{},'type2':{}}

    def findAndSortTests(self):

        for symbol in dir(): # Also tried: dir(self) and __dict__
            try:
                thing = self.__getattribute__(symbol)
            except AttributeError:
                continue
            if issubclass(thing,TestType1):
                self.existingTests['type1'].update( dict(symbol,thing) )
            elif issubclass(thing,TestType3):
                self.existingTests['type2'].update( dict(symbol,thing) )
            else:
                continue

if __name__ == "__main__":
    testFigureOuterrer = TestFigureOuterrer()
    testFigureOuterrer.findAndSortTests()

testType1.py:

class TestType1(object):
    pass

class TestA(TestType1):
    pass

class TestB(TestType1):
    pass

testType2.py:

class TestType2:
    pass

class TestC(TestType2):
    pass

class TestD(TestType2):
    pass

既然你自己知道导入,那么你应该再次手动导入模块,然后检查模块的内容。如果定义了 __all__ 属性,当您执行 from module import * 时,其内容将作为名称导入。否则,只需使用其所有成员:

def getImportedNames (module):
    names = module.__all__ if hasattr(module, '__all__') else dir(module)
    return [name for name in names if not name.startswith('_')]

这样做的好处是您无需遍历全局变量并过滤掉所有内容。由于您在设计时知道从中导入的模块,因此您也可以直接检查它们。

from testType1 import *
from testType2 import *

import testType1, testType2

print(getImportedNames(testType1))
print(getImportedNames(testType2))

或者,您也可以通过 sys.modules 中的模块名称查找模块,因此您实际上不需要额外的导入:

import sys
def getImportedNames (moduleName):
    module = sys.modules[moduleName]
    names = module.__all__ if hasattr(module, '__all__') else dir(module)
    return [name for name in names if not name.startswith('_')]
print(getImportedNames('testType1'))
print(getImportedNames('testType2'))

看一下this SO answer,里面介绍了如何判断加载的类的名称,可以得到模块上下文中定义的所有类的名称.

import sys, inspect
clsmembers = inspect.getmembers(sys.modules['testType1'], inspect.isclass)

现在定义为

[('TestA', testType1.TestA),
 ('TestB', testType1.TestB),
 ('TestType1', testType1.TestType1)]

当您在感兴趣的函数内时,您也可以将 testType1 替换为 __name__

不要使用 import* 形式。这会将导入的名称转储到脚本的全局命名空间中。他们不仅可以通过使用相同的名称来破坏一些重要的数据,而且您没有任何简单的方法来找出刚刚导入的名称。 (最简单的方法可能是拍摄 globals().keys() 之前和之后的快照。)

相反,只导入模块:

import testType1
import testType2

现在您可以轻松获得每个模块中的内容列表:

tests = dir(testType1)

并在模块对象上使用 getattr() 访问每个:

for testname in tests:
    test = getattr(testType1, testname)
    if callable(test):
        # do something with it