如何在Python中获取当前模块中所有类的列表?

mcc*_*ean 278 python reflection inspect

我已经看到很多人从模块中提取所有类的例子,通常是这样的:

# foo.py
class Foo:
    pass

# test.py
import inspect
import foo

for name, obj in inspect.getmembers(foo):
    if inspect.isclass(obj):
        print obj
Run Code Online (Sandbox Code Playgroud)

真棒.

但我无法找到如何从当前模块中获取所有类.

# foo.py
import inspect

class Foo:
    pass

def print_classes():
    for name, obj in inspect.getmembers(???): # what do I do here?
        if inspect.isclass(obj):
            print obj

# test.py
import foo

foo.print_classes()
Run Code Online (Sandbox Code Playgroud)

这可能是非常明显的事情,但我找不到任何东西.谁能帮我吗?

Nad*_*mli 358

试试这个:

import sys
current_module = sys.modules[__name__]
Run Code Online (Sandbox Code Playgroud)

在您的上下文中:

import sys, inspect
def print_classes():
    for name, obj in inspect.getmembers(sys.modules[__name__]):
        if inspect.isclass(obj):
            print(obj)
Run Code Online (Sandbox Code Playgroud)

甚至更好:

clsmembers = inspect.getmembers(sys.modules[__name__], inspect.isclass)
Run Code Online (Sandbox Code Playgroud)

因为inspect.getmembers()需要一个谓词.

  • 纳迪亚的答案几乎是正确的.更好:`inspect.getmembers(sys.modules [__ name __],lambda成员:inspect.isclass(成员)和成员.__ module__ == __name__` (14认同)
  • 如果我在模块级别(即,来自optparse import OptionParser`)导入此模块中的类,则这些模块将包含在打印列表中.我怎么能避免这种情况? (8认同)
  • @phasetwenty,而不是inspect.isclass,你可以有类似的东西:`inspect.getmembers(sys.modules [__ name __],lambda member:member .__ module__ == __name__ and isnpect.isclass)` (5认同)

Kra*_*rab 17

关于什么

g = globals().copy()
for name, obj in g.iteritems():
Run Code Online (Sandbox Code Playgroud)

  • 我更喜欢这个答案,因为即使当前模块没有被放入sys.modules中它也会有效,例如来自http://docs.python.org/2/library/functions.html#execfile (3认同)

int*_*nt3 14

我不知道是否有一种'正确'的方式来做,但你的片段是在正确的轨道上:只需添加import foo到foo.py,做inspect.getmembers(foo),它应该工作正常.

  • 没有获得循环依赖或导入循环的原因是,一旦导入模块,它就会添加到全局命名空间中。当执行导入的模块并进入“import foo”时,它会跳过导入,因为该模块已经在全局变量中可用。如果您将 foo 作为 main (作为脚本)执行,则该模块实际上会运行两次,因为当您执行“import foo”时,__main__ 将位于全局命名空间中,但不是 foo。在“import foo”之后,“__main__”和“foo”都将位于全局命名空间中。 (4认同)

Tho*_*ner 10

我能够从dir内置加上获得我所需要的一切getattr.

# Works on pretty much everything, but be mindful that 
# you get lists of strings back

print dir(myproject)
print dir(myproject.mymodule)
print dir(myproject.mymodule.myfile)
print dir(myproject.mymodule.myfile.myclass)

# But, the string names can be resolved with getattr, (as seen below)
Run Code Online (Sandbox Code Playgroud)

虽然,它确实看起来像一个毛球:

def list_supported_platforms():
    """
        List supported platforms (to match sys.platform)

        @Retirms:
            list str: platform names
    """
    return list(itertools.chain(
        *list(
            # Get the class's constant
            getattr(
                # Get the module's first class, which we wrote
                getattr(
                    # Get the module
                    getattr(platforms, item),
                    dir(
                        getattr(platforms, item)
                    )[0]
                ),
                'SYS_PLATFORMS'
            )
            # For each include in platforms/__init__.py 
            for item in dir(platforms)
            # Ignore magic, ourselves (index.py) and a base class.
            if not item.startswith('__') and item not in ['index', 'base']
        )
    ))
Run Code Online (Sandbox Code Playgroud)


Aus*_*lop 9

这是我用来获取当前模块中已定义的所有类(即未导入的类)的行。根据 PEP-8,它有点长,但您可以根据需要进行更改。

import sys
import inspect

classes = [name for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isclass) 
          if obj.__module__ is __name__]
Run Code Online (Sandbox Code Playgroud)

这将为您提供类名称列表。如果你想要类对象本身,只需保留 obj 即可。

classes = [obj for name, obj in inspect.getmembers(sys.modules[__name__], inspect.isclass)
          if obj.__module__ is __name__]
Run Code Online (Sandbox Code Playgroud)

根据我的经验,这更有用。


nco*_*lan 6

import pyclbr
print(pyclbr.readmodule(__name__).keys())
Run Code Online (Sandbox Code Playgroud)

请注意,stdlib的Python类浏览器模块使用静态源分析,因此它仅适用于由真实.py文件支持的模块.


Ben*_*lca 6

如果你想拥有属于当前模块的所有类,你可以使用这个:

import sys, inspect
def print_classes():
    is_class_member = lambda member: inspect.isclass(member) and member.__module__ == __name__
    clsmembers = inspect.getmembers(sys.modules[__name__], is_class_member)
Run Code Online (Sandbox Code Playgroud)

如果您使用 Nadia 的答案并且您正在模块上导入其他类,那么这些类也将被导入。

所以这就是为什么member.__module__ == __name__要添加到用于is_class_member. 该语句检查该类是否确实属于该模块。

谓词是一个函数(可调用),它返回一个布尔值。