Code Explanation:
1. Defining the Class
class A:
A class named A is defined.
It customizes attribute access behavior by overriding special methods.
2. Overriding __getattribute__
def __getattribute__(self, name):
print("get", name)
return super().__getattribute__(name)
__getattribute__ is called for every attribute access, even for non-existing ones.
It prints "get <attribute_name>".
Then it delegates the actual lookup to the default implementation using super().
3. Defining __getattr__ as a Fallback
def __getattr__(self, name):
return 5
__getattr__ is only called if normal attribute lookup fails.
It returns 5 when an attribute is not found.
4. Creating an Object
print(A().x)
Step-by-step execution:
A() creates an object of class A.
Python evaluates A().x.
Python first calls __getattribute__(self, "x").
Inside __getattribute__, it prints:
get x
Then it calls super().__getattribute__("x").
Since x does not exist, super().__getattribute__ raises AttributeError.
Because __getattribute__ does not catch this error, Python does not fall back to __getattr__.
The program crashes.
5. Why __getattr__ Is Not Used Here
Normally, if attribute lookup fails, Python calls __getattr__.
But in this case:
__getattribute__ is overridden.
It calls super().__getattribute__ which raises AttributeError.
But since the error happens inside __getattribute__ and is not handled, __getattr__ is never triggered.
To allow fallback, you must handle the exception manually.
6. Final Output
get x
Then Python raises:
AttributeError: 'A' object has no attribute 'x'
Final Answer
✔ Output printed:
get x
Then program crashes with:
AttributeError: 'A' object has no attribute 'x'


0 Comments:
Post a Comment