Python为何print输出eval(repr)生成的对象时调用__str__而非__repr__?
问题核心逻辑拆解
触发结果的本质原因
这个现象完全是由print函数的固定调用逻辑导致的,和eval、repr的组合过程没有关系。print函数在处理传入的对象时,会严格按照固定优先级获取用于输出的字符串:
- 第一优先级:调用对象的
__str__魔术方法,拿到面向用户的可读字符串 - 仅当对象没有实现
__str__方法时,才会回退调用对象的__repr__魔术方法获取输出内容
代码执行链路逐段对应
结合给出的测试代码,每一步的执行逻辑可以完全匹配实际运行结果:
- 执行
print(str(x))时,显式调用内置str()方法,触发x对象的__str__,输出友好格式的Name: Marvin, Build Year: 1979 - 执行
print(x)时,走print的默认对象转字符串逻辑,同样触发__str__,输出和上一步完全一致的内容 - 执行
print(repr(x))时,显式调用内置repr()方法,触发x对象的__repr__,拿到可用于重建对象的字符串Robot('Marvin', 1979),再把这个字符串本身打印出来 - 执行
new = eval(repr(x))时,把上一步拿到的可重建字符串作为Python代码执行,重新生成一个属性和x完全一致的Robot类实例。这个new对象是完全正常的类实例,和直接通过构造方法生成的对象没有任何区别,不存在特殊的“repr生成对象”的特殊属性 - 执行
print(new)时,走print的默认对象转字符串逻辑,优先触发new对象的__str__,自然输出友好格式的字符串,不会调用__repr__
常见认知偏差澄清
这个场景下的认知混淆,本质是把两个完全独立的流程错误绑定在了一起:误以为
eval(repr(x))生成的对象,在打印时会和生成它的repr字符串有特殊关联。实际上当new实例生成完成后,后续对它的所有操作都和之前的repr、eval流程没有任何绑定关系。
可以做个简单的对照验证:把Robot类里的__str__方法删除,再执行同样的print(new),此时由于类没有实现__str__,print会回退调用__repr__,输出Robot('Marvin', 1979)的内容,刚好反向印证print的优先级规则。
内容的提问来源于stack exchange,提问作者Lucky1234
相关产品推荐
相关产品推荐

