You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

调试与运行模式下__subclasses__()返回子类不一致问题咨询

Python调试模式与普通模式下__subclasses__()返回结果差异的原因

我正在学习Python继承机制,编写了一个可视化类子类结构的PrintClassTree函数,代码如下:

def PrintClassTree(thisclass, nest=0):
    if nest > 1:
        print('   |' * (nest - 1), end='')

    if nest > 0:
        print('   +---', end='')

    print(thisclass.__name__)

    for subclass in thisclass.__subclasses__():
        PrintClassTree(subclass, nest+1)

PrintClassTree(dict)

运行结果差异

  • 普通运行模式输出:
dict
   +---OrderedDict
   +---defaultdict
   +---Counter
  • **PyCharm调试模式/直接调用dict.__subclasses__()**输出:
dict
   +---OrderedDict
   +---defaultdict
   |   +---Quoter
   +---Counter
   +---_EnumDict
   +---_QByteMap
   +---StgDict
   +---_ReqExtras
   +---ZipManifests
   |   +---MemoizedZipManifests
   +---TypedDict

测试list类时也存在同样情况,仅调试模式能获取完整子类,而BaseException类在两种模式下结果正常。

差异原因

核心原因是Python的惰性导入机制:

  • Python不会在启动时加载所有模块和类,只有当代码显式导入对应模块时,模块内定义的子类才会被注册到父类的__subclasses__()列表中。
  • 调试模式下,PyCharm的调试器为实现变量查看、断点追踪等功能,会自动导入大量普通运行时不会加载的模块(比如enum、typing、zipfile及调试相关内部模块),这些模块中定义的dict/list子类会被自动注册,因此__subclasses__()能返回完整列表。
  • 普通运行模式下,这些模块未被导入,对应的子类自然不会出现在返回结果里。
  • 而BaseException的子类都是Python启动时默认加载的核心异常类,无论调试还是普通运行都会被初始化,所以两种模式下结果一致。

验证方法

在普通运行的代码开头手动导入相关模块,再调用函数就能得到完整子类列表:

import enum
import typing
import zipfile
# 可按需导入其他调试器会加载的模块

def PrintClassTree(thisclass, nest=0):
    if nest > 1:
        print('   |' * (nest - 1), end='')

    if nest > 0:
        print('   +---', end='')

    print(thisclass.__name__)

    for subclass in thisclass.__subclasses__():
        PrintClassTree(subclass, nest+1)

PrintClassTree(dict)

内容的提问来源于stack exchange,提问作者Theresa M

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 16:57:34