Python: avoiding infinite loops in __getattribute__

前端 未结 3 1640
北恋
北恋 2020-12-14 07:05

The method __getattribute__ needs to be written carefully in order to avoid the infinite loop. For example:

class A:
    def __init__(self):
            


        
相关标签:
3条回答
  • 2020-12-14 07:56

    Write it like this (C inherits from object):

    class C(object):
       def __init__(self):
           self.x = 100
    
       def __getattribute__(self, x):
           return object.__getattribute__(self, x)
    

    Now you see why object.__getattribute__(self, x) works - you are calling parent object.

    0 讨论(0)
  • 2020-12-14 07:58

    When you do this:

        return object.__getattribute__(self, x)
    

    you are calling a specific function -- the one defined in the object class, and not the one defined in A, so there is no recursion.

    When you do this:

        return self.x
    

    you are letting python choose which function to call, and it calls the one from A, and you have an infinite recursion.

    0 讨论(0)
  • 2020-12-14 08:09

    You seem to be under the impression that your implementation of __getattribute__ is merely a hook, that if you provide it Python will call it, and otherwise the interpreter will do its normal magic directly.

    That is not correct. When python looks up attributes on instances, __getattribute__ is the main entry for all attribute access, and object provides the default implementation. Your implementation is thus overriding the original, and if your implementation provides no alternative means of returning attributes it fails. You cannot use attribute access in that method, since all attribute access to the instance (self) is channelled again through type(self).__getattribute__(self, attr).

    The best way around this is by calling the overridden original again. That's where super(C, self).__getattribute__(attr) comes in; you are asking the next class in the class-resolution order to take care of the attribute access for you.

    Alternatively, you can call the unbound object.__getattribute__() method directly. The C implementation of this method is the final stop for attribute access (it has direct access to __dict__ and is thus not bound to the same limitations).

    Note that super() returns a proxy object that'll look up whatever method can be found next in the method-resolution ordered base classes. If no such method exists, it'll fail with an attribute error. It will never call the original method. Thus Foo.bar() looking up super(Foo, self).bar will either be a base-class implementation or an attribute error, never Foo.bar itself.

    0 讨论(0)
提交回复
热议问题