-1

On Difference between __getattr__ vs __getattribute__ there are some nice examples to __getattr__ and _getattribute__.

Why is __getattribute__ called 19 times - after the code? Ok - it's a recursion ... but why?

class Count(object):

    def __init__(self,mymin,mymax):
        self.mymin=mymin
        self.mymax=mymax
        self.current=None

    def __getattr__(self, item):
            self.__dict__[item]=0
            return 0

    def __getattribute__(self, item):
        print("__getattribute__: ", item)          # only this line is new!!!!
        if item.startswith('cur'):
            raise AttributeError
        return object.__getattribute__(self,item)
        # or you can use ---return super().__getattribute__(item)
        # note this class subclass object

obj1 = Count(1,10)
print(obj1.mymin)
print(obj1.mymax)
print(obj1.current)
print("end")

Output:

__getattribute__:  mymin
1
__getattribute__:  mymax
10
__getattribute__:  current
__getattribute__:  __dict__
0
end
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
__getattribute__:  __class__
TrebledJ
  • 8,713
  • 7
  • 26
  • 48
  • Hi there, I made some changes to your code's format (please check that they are inline with your original question's intent). I can't seem to reproduce this though... On the IDLE, there's no output after `end`. – TrebledJ Jan 28 '19 at 15:03
  • From what you've shown, you don't ever call any of the functions within the count class apart from the constructor. Please elaborate with object is in class Count(object) – ZWang Jan 28 '19 at 15:05
  • @ZWang Each of the three attribute accesses in the calls to `print` triggers an implicit call to `Count.__getattribute__` – chepner Jan 28 '19 at 15:08
  • @MartinMeier This is probably related to garbage collection. – chepner Jan 28 '19 at 15:11
  • Ah sorry I'm being an idiot – ZWang Jan 28 '19 at 15:11

1 Answers1

0

With CPython 3.7, the only way I can reproduce your issue is when I put a breakpoint and debug in your code.

So, the multiple calls to Count.__getattribute__ is most probably caused by something else (in my case: the debugger) that try to access your class attributes.

For the record, here is the trace when I run your code the normal way :

__getattribute__:  mymin
1
__getattribute__:  mymax
10
__getattribute__:  current
__getattribute__:  __dict__
0
end

Note that no Exception trace is shown even when obj1.current is accessed. That is a specific behavior I cannot explain.

Antwane
  • 20,760
  • 7
  • 51
  • 84
  • obj1.current raises a AttributeError in \_\_getattribute\_\_. This is catched in Python, which then calls \_\_getattr\_\_ to resolve the unknown attribute. You only see an exception trace when \_\_getattr\_\_ also raises AttributeError. – mkiever Nov 19 '19 at 15:20