可以在递归级别1的__repr__方法中返回对象的__str__表示。

huangapple go评论73阅读模式
英文:

Can you return a __str__ representation of an object within the __repr__ method at recursion level 1?

问题

以下是翻译好的部分:

I am looking for a way to implement a custom __repr__ function in Python, that handles recursion Pythonically, while maintaining readability.

我正在寻找一种在Python中实现自定义__repr__函数的方法,可以以Pythonic方式处理递归,同时保持可读性。

I have two classes (Foo and Bar) that point to each other in their attributes. Of course, simply putting e.g.:

我有两个类(Foo和Bar),它们在它们的属性中互相引用。当然,只是简单地放置如下代码:

Would result in a recursion error. Luckily, there's the @recursive_repr() from reprlib to the rescue. See my implementation below.

这将导致递归错误。幸运的是,有来自reprlib@recursive_repr()可以帮助解决这个问题。请看下面是我的实现。

However, the custom implementation with fillvalue='...' doesn't improve readability much, in my opinion. Also, this representation of e.g. the foo instance - although I know this isn't required - doesn't make it very reproducible, necessarily.

然而,根据我的看法,使用fillvalue='...'的自定义实现并没有显著提高可读性。此外,对于例如foo实例的表示,尽管我知道这并不是必需的,但并不一定能够很好地复现。

I am looking for an implementation where I can print a string representation of the foo instance, instead of printing the triple dots. I would want an output that'd be something like this: Foo(Bar(my_foo_object)) in which I'd be able to define my_foo_object as the return value of the Foo __str__ method.

我正在寻找一种实现,可以打印foo实例的字符串表示,而不是打印三个点。我希望得到的输出类似于Foo(Bar(my_foo_object)),其中我可以将my_foo_object 定义为Foo__str__方法的返回值。

Although in the above example this might not make a ton of sense, in my non-MWE it would provide a more intuitive perspective on the objects and their values.

虽然在上面的示例中这可能没有太多意义,但在我的非MWE中,它将提供更直观的对象及其值的视角。

In brief: is it possible to return a __str__ representation of an object within an object's recursive_repr at recursion level 1?

简而言之:在递归级别1中,是否可以在对象的recursive_repr中返回一个对象的__str__表示?

英文:

I am looking for a way to implement a custom __repr__ function in Python, that handles recursion Pythonically, while maintaining readability.

I have two classes (Foo and Bar) that point to each other in their attributes. Of course, simply putting e.g.:

class Foo:
    def __init__(self, bar):
        self.bar = bar

    def __repr__(self):
        return f'Foo({self.bar})'

    @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 = None

    def __repr__(self):
        return f'Bar({self.foo})'

    @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)

Would result in a recursion error. Luckily, there's the @recursive_repr() from reprlib to the rescue. See my implementation below.

from reprlib import recursive_repr


class Foo:
    def __init__(self, bar):
        self.bar = bar

    @recursive_repr()
    def __repr__(self):
        return f'Foo({self.bar})'

    @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 = None

    @recursive_repr()
    def __repr__(self):
        return f'Bar({self.foo})'

    @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)

However, the custom implementation with fillvalue='...' doesn't improve readability much, in my opinion. Also, this representation of e.g. the foo instance - although I know this isn't required - doesn't make it very reproducible, necessarily.

>>> bar = Bar()
>>> foo = Foo(bar)
>>> foo
... Foo(Bar(...))

I am looking for an implementation where I can print a string representation of the foo instance, instead of printing the triple dots. I would want an output that'd be something like this: Foo(Bar(my_foo_object)) in which I'd be able to define my_foo_object as the return value of the Foo __str__ method.

Although in the above example this might not make a ton of sense, in my non-MWE it would provide a more intuitive perspective on the objects and their values.

In brief: is it possible to return a __str__ representation of an object within an objects recursive_repr at recursion level 1?

答案1

得分: 2

I am looking for an implementation where I can print a string representation of the foo instance, instead of printing the triple dots. I would want an output that'd be something like this: Foo(Bar(my_foo_object)) in which I'd be able to define my_foo_object as the return value of the Foo __str__ method.

你需要为两个类定义自定义的 __str__ 方法:

def __str__(self):
    return "CustomBar"

以及在 __repr__ 中:

def __repr__(self):
    return f'Foo({self.bar})'

在Python中,f-strings 默认使用 __str__ 方法,所以不需要调用 str(self.bar)。在这种情况下,你不需要使用 @reprlib.recursive_repr 修饰你的 __repr__ 函数,因为实际上当自定义 __str__ 函数存在时,不会发生递归。

请注意,你可以重写 Repr.fillvalue 字符串,它默认为省略号 ...reprlib.recursive_repr(fillvalue='somethingCustomHere')

In brief: is it possible to return a __str__ representation of an object within an object's recursive_repr at recursion level 1?

定义 __str__ 方法会返回字符串表示形式,无需递归调用 __repr__,从而消除了使用 recursive_repr 处理递归的需要。

Hopefully this solves your problem.

英文:

> I am looking for an implementation where I can print a string
> representation of the foo instance, instead of printing the triple
> dots. I would want an output that'd be something like this:
> Foo(Bar(my_foo_object)) in which I'd be able to define my_foo_object
> as the return value of the Foo __str__ method.

You need to define custom __str__ for both classes:

def __str__(self):
    return "CustomBar"

and in __repr__:

def __repr__(self):
    return f'Foo({self.bar})'

fstrings in Python default to __str__ you don't need to call str(self.bar). In this case, you don't need to decorate your __repr__ functions with @reprlib.recursive_repr as no recursion is taking place essentially when custom __str__ functions are present.

Please note that you can override the Repr.fillvalue string which defaults to the ellipsis ... or reprlib.recursive_repr(fillvalue='somethingCustomHere').

> In brief: is it possible to return a __str__ representation of an
> object within an objects recursive_repr at recursion level 1?

Definig __str__ would return the string representation, the string returned by __str__, without necessitating the need of recursive call to __repr__ and thus eliminating the use of recursive_repr to handle recursion.

Hopefully this solves your problem.

huangapple
  • 本文由 发表于 2023年2月6日 18:26:53
  • 转载请务必保留本文链接:https://go.coder-hub.com/75360070.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定