Reputation: 1247
The first code snippet:
class A:
def __init__(self):
print(self.__dict__)
def __getattr__(self, name):
print("get")
def __setattr__(self, name, value):
print("set")
# def __getattribute__(self, name):
# print("getatrr")
a = A()
It prints {}
and the function __getattr__
isn't invoked, which means the attribute__dict__
exists.
The second snippet:
class A:
def __init__(self):
print(self.__dict__)
def __getattr__(self, name):
print("get")
def __setattr__(self, name, value):
print("set")
def __getattribute__(self, name):
print("getatrr")
a = A()
It prints getatrr
and None
, which means the attribute __dict__
doesn't exist.
Why is __dict__
{}
in the first case, but None
in the second case?
Upvotes: 0
Views: 823
Reputation: 140186
the issue is that when you define this:
def __getattribute__(self, name):
print("getatrr")
you're overriding __getattribute__
which is supposed to return something. Since you're not returning anything, you get None
for every attribute you'll try.
Documentation states:
This method should return the (computed) attribute value or raise an AttributeError exception
A viable way to define it is to call object.__getattribute__
in the fallback case (in my example, I have added a small test on __dict__
which prints:
def __getattribute__(self, name):
if name == "__dict__":
print("get attribute invoked with __dict__")
return object.__getattribute__(self,name)
In the end, the hard attribute lookup work is done with object.__getattribute__
that invokes python runtime.
Upvotes: 1