调试与运行模式下__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
相关产品推荐
相关产品推荐

