0

I want to display a list of all accessible attribute of an instance, so i try this

class Test:
    a=2     #initializing some attribute
    b=1     #initializing some attribute
    def some_method(self):
        attr=[]                 
        for k in [i for i in dir(self) if not i.startswith('__')]:
            attr.append(f'{k}={getattr(self,k)}')      #to collect all attributes and their values pair
        return attr
    def __repr__(self):                                #because i want to overload print behavior
        return str(self.some_method())
some_instance=Test()
print(some_instance) 

And it returned an error:

RecursionError: maximum recursion depth exceeded while calling a Python object

Why did that happen ? And how to fix that ?

  • Well if there is a cycle in your object (for example the list contains a reference to `self`, or one of the elements somehow aims to print `self`), then you get in a recursive loop. – Willem Van Onsem Jul 27 '19 at 11:15
  • @WillemVanOnsem `a`,`b`,`some_method` are everything i have in the instance, which of them cause this problem ? – Tuấn Đoàn Jul 27 '19 at 11:20
  • 3
    @TuanDoan: usually `dir` has more than only these attributes. For example `some_method`, etc. The `repr(..)` of `Test().some_method` is ` – Willem Van Onsem Jul 27 '19 at 11:23

2 Answers2

1

As pointed out in the comments, repr(Test().some_method) calls repr of the object where it lives, yielding in a never ending son-father repr method call stack. If you are not really interested in showing callable members you can filter them out so that they never get asked to be part of a string:

class Test:
    a=2     #initializing some attribute
    b=1     #initializing some attribute
    def some_method(self):
        attr=[]                 
        for k in dir(self):
            val = getattr(self, k)
            if not k.startswith('__') and not callable(val):
                attr.append(f'{k}={val}')      #to collect all attributes and their values pair
        return attr
    def __repr__(self):                                #because i want to overload print behavior
        return str(self.some_method())
some_instance=Test()

Then print(some_instance) shows

['a=2', 'b=1']
josoler
  • 1,393
  • 9
  • 15
1

You can use __str__ instead of __repr__ to overload printing. In case you must use __repr__ then use the isinstance() to compare the type of attribute values against types.MethodType in the standard library.