On 24/05/2023 15:37, A KR wrote:
It is perfectly explained in the standards here [1] saying that:

<quote>
In order to avoid infinite recursion in this method, its implementation should 
always call the base class method with the same name to access any attributes 
it needs, for example, object.__getattribute__(self, name).
</quote>

Therefore, I wrote a code following what the standard says:

<code>
class Sample():
     def __init__(self):
         self.a = -10

     def __getattribute__(self, name):
         if name == 'a':
             return object.__getattribute__(self, name)

         raise AttributeError()

s = Sample()
result = s.a
print(result)
</code>
I did not fall into recursion, and the output was
-10

While this works it's not how I understand the recommended pattern. I'd
rather treat "special" attributes first and then use the
__getattribute__ method of the base class as a fallback:

>> class Demo:
        def __getattribute__(self, name):
                if name == "answer":
                        return 42
                return super().__getattribute__(name)

That way your special arguments,

>>> d = Demo()
>>> d.answer
42


missing arguments

>>> d.whatever
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    d.whatever
  File "<pyshell#10>", line 5, in __getattribute__
    return super().__getattribute__(name)
AttributeError: 'Demo' object has no attribute 'whatever'

and "normal" arguments are treated as expected

>>> d.question = "What's up?"
>>> d.question
"What's up?"

Eventual "special" arguments in the superclass would also remain accessible.


However, when I try the code without deriving from a class:

class AnyClassNoRelation:
     pass

class Sample():
     def __init__(self):
         self.a = -10

     def __getattribute__(self, name):
         if name == 'a':
             return AnyClassNoRelation.__getattribute__(self, name)

         raise AttributeError()

s = Sample()

result = s.a
print(result)
and calling __getattribute__ via any class (in this example class 
AnyClassNoRelation) instead of object.__getattribute__(self, name) as the 
standard says call using the base class, I get the same output: no recursion 
and -10.

So my question:

How come this is possible (having the same output without using the base 
class's __getattribute__? Although the standards clearly states that 
__getattribute__ should be called from the base class.


AnyClassNoRelation does not override __getattribute__, so

>>> AnyClassNoRelation.__getattribute__ is object.__getattribute__
True


There is no sanity check whether a method that you call explicitly is
actually in an object's inheritance tree,

>>> class NoRelation:
        def __getattribute__(self, name):
                return name.upper()


>>> class Demo:
        def __getattribute__(self, name):
                return "<{}>".format(NoRelation.__getattribute__(self, name))


>>> Demo().some_arg
'<SOME_ARG>'

but the only purpose I can imagine of actually calling "someone else's"
method is to confuse the reader...
<quote>
In order to avoid infinite recursion in this method, its implementation should 
always call the base class method with the same name to access any attributes 
it needs, for example, object.__getattribute__(self, name).
</quote>

Literally, I can call __getattribute__ with anyclass (except Sample cause it 
will be infinite recursion) I define and it works just fine. Could you explain 
me why that happens?


--
https://mail.python.org/mailman/listinfo/python-list

Reply via email to