Python:如何在递归层级1的__repr__中返回对象的__str__表示?
实现支持递归且用__str__替代默认占位符的自定义__repr__
完全可行,我们可以通过自定义递归跟踪装饰器,或者改造reprlib.recursive_repr的行为,让递归引用时返回对象的__str__结果,既避免递归错误,又提升可读性和辨识度。
方案一:自定义递归跟踪装饰器
这个方案逻辑清晰、灵活性强,能精准控制递归时的输出逻辑:
from functools import wraps def recursive_repr_with_str(fillvalue_func=str): def decorator(repr_func): seen = set() @wraps(repr_func) def wrapper(self): obj_id = id(self) if obj_id in seen: return fillvalue_func(self) seen.add(obj_id) try: return repr_func(self) finally: seen.remove(obj_id) return wrapper return decorator # 定义带__str__的类 class Foo: def __init__(self, bar): self.bar = bar @recursive_repr_with_str() def __repr__(self): return f'Foo({self.bar})' def __str__(self): return 'my_foo_object' # 自定义的友好标识 @property def bar(self): return self._bar @bar.setter def bar(self, bar_instance): if bar_instance is not None: bar_instance._foo = self self._bar = bar_instance class Bar: def __init__(self, foo=None): self.foo = foo @recursive_repr_with_str() def __repr__(self): return f'Bar({self.foo})' def __str__(self): return 'my_bar_object' @property def foo(self): return self._foo @foo.setter def foo(self, foo_instance): if foo_instance is not None: foo_instance._bar = self self._foo = foo_instance # 测试 bar = Bar() foo = Foo(bar) print(repr(foo)) # 输出: Foo(Bar(my_foo_object)) print(repr(bar)) # 输出: Bar(Foo(my_bar_object))
方案二:扩展reprlib.recursive_repr
如果想基于官方库的实现修改,可以通过包装方式让fillvalue动态调用对象的__str__:
from reprlib import recursive_repr class DynamicRecursiveRepr: def __call__(self, func): # 复用recursive_repr的基础逻辑 decorator = recursive_repr(fillvalue='') wrapped = decorator(func) def wrapper(self): # 临时替换fillvalue为当前对象的__str__结果 original_fillvalue = wrapped.fillvalue wrapped.fillvalue = str(self) try: return wrapped(self) finally: wrapped.fillvalue = original_fillvalue return wrapper # 使用自定义装饰器 class Foo: def __init__(self, bar): self.bar = bar @DynamicRecursiveRepr() def __repr__(self): return f'Foo({self.bar})' def __str__(self): return 'my_foo_object' # 省略属性定义(同方案一) class Bar: def __init__(self, foo=None): self.foo = foo @DynamicRecursiveRepr() def __repr__(self): return f'Bar({self.foo})' def __str__(self): return 'my_bar_object' # 省略属性定义(同方案一) # 测试结果与方案一一致 bar = Bar() foo = Foo(bar) print(repr(foo)) # Foo(Bar(my_foo_object))
关键说明
- 两种方案都通过跟踪对象ID避免递归调用,当检测到已处理过的对象时,返回其
__str__结果而非继续递归执行__repr__ - 你可以根据需求自定义
__str__的内容,比如包含对象ID、核心属性摘要等,进一步提升辨识度 - 方案一的自定义装饰器逻辑更独立,便于后续扩展;方案二基于官方库实现,兼容性更好
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

