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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 18:32:28