Python __repr__返回字符串但实例类型不为str问题排查
尝试使用__repr__特殊方法让自定义类实例输出为字符串形式,虽然交互环境下的输出看起来是字符串,但通过type()检测实例类型时,结果并非字符串类型,实际运行结果如下:
>>> ColumnSet.COL_A Out: "COL_A" >>> type(ColumnSet.COL_A) Out: __main__.Column >>> type(ColumnSet.COL_A) == str Out: False
期望实现的运行效果:
>>> ColumnSet.COL_A Out: "COL_A" >>> type(ColumnSet.COL_A) Out: str >>> type(ColumnSet.COL_A) == str Out: True
尝试在__repr__方法内部将返回值显式转换为字符串,无法解决问题。核心诉求是:既可以得到简洁的字符串展示效果,又能保留实例的属性访问能力,比如正常调用ColumnSet.COL_A.data_type这类属性。
当前实现代码:
from dataclasses import dataclass @dataclass class Column: column_name: str data_type: str description: str def __repr__(self) -> str: return str(self.column_name) @dataclass class ColumnSet: COL_A = Column( **{ "column_name": "COL_A", "data_type": "bool", "description": "Lorem Ipsum", } ) COL_B = Column( **{ "column_name": "COL_B", "data_type": "bool", "description": "Lorem Ipsum", } )
你对__repr__的作用存在误解:这个方法只负责定义实例被打印、在REPL环境输出时的展示文本,完全不会修改实例本身的类型。Column类实例化出的对象永远是Column类型,不可能因为__repr__返回字符串就变成原生str类型。
另外你提出的两个核心诉求存在本质冲突:
- 如果
ColumnSet.COL_A真的是原生str类型(即type(ColumnSet.COL_A) is str返回True),就不可能挂载.data_type这类自定义属性,Python原生str类型不支持动态添加自定义字段 - 只要实例能访问自定义属性,它就不可能是原生
str类型,type()检测必然返回对应的自定义类类型
你在交互环境看到的"COL_A"输出,只是REPL调用__repr__后打印的结果,不代表变量本身变成了字符串。
方案1:继承str实现自定义列类型(最接近预期效果)
通过继承str创建自定义子类,可以让实例在绝大多数场景下和原生字符串行为完全一致,同时支持挂载自定义属性,满足属性访问需求:
class Column(str): def __new__(cls, column_name: str, data_type: str, description: str): # 构造字符串实例时,用列名作为字符串本身的值 return super().__new__(cls, column_name) def __init__(self, column_name: str, data_type: str, description: str): self.column_name = column_name self.data_type = data_type self.description = description class ColumnSet: COL_A = Column( column_name="COL_A", data_type="bool", description="Lorem Ipsum", ) COL_B = Column( column_name="COL_B", data_type="bool", description="Lorem Ipsum", )
运行效果:
>>> ColumnSet.COL_A 'COL_A' >>> # 所有字符串场景可直接使用 >>> isinstance(ColumnSet.COL_A, str) True >>> f"选择列:{ColumnSet.COL_A}" '选择列:COL_A' >>> # 自定义属性可正常访问 >>> ColumnSet.COL_A.data_type 'bool'
注意:该方案下
type(ColumnSet.COL_A)会返回<class '__main__.Column'>,无法满足type(x) == str的判断——这是Python类型系统的限制,只要是带自定义属性的字符串对象,必然是str子类的实例,不可能是原生str。实际开发中类型判断应该优先用isinstance(),直接用type()做相等判断本身就是不符合Python编码规范的写法。
方案2:保留原有实现,仅优化展示
如果没有强需求要通过type() == str的判断,你原来的__repr__写法已经完全满足需求:实例可以正常访问所有自定义属性,输出时自动展示为简洁的列名,不需要做额外修改。
内容的提问来源于stack exchange,提问作者AaronDT

