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

时间:2015-07-16 22:33:37

标签: python import python-import

我有一个系统,它收集从某些基类派生的所有类,并将它们存储在字典中。我想避免必须指定哪些类可用(我想以编程方式发现它们),所以使用了from ModuleName import *语句。然后指示用户将要收集的所有测试放在ModuleName模块中。但是,我找不到以编程方式确定使用该import语句导入了哪些符号的方法。我已尝试使用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

3 个答案:

答案 0 :(得分:4)

由于您自己了解导入,因此您应该再次手动导入模块,然后检查模块的内容。如果定义了__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'))

答案 1 :(得分:3)

看一下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__

答案 2 :(得分:0)

请勿使用*形式的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