start
python Provides a series of special methods related to property access :__get__, __getattr__, __getattribute__, __getitem__. This article expounds their differences and usages .
Property access mechanism
In general , The default behavior of property access is to get from the object's dictionary , And when it is not available, it will search along a certain search chain . for example a.x The search chain of is , from a.__dict__['x'] , And then there was type(a).__dict__['x'] , Re pass type(a) Start looking for the base class of .
If the search chain cannot get the attribute , Throw out AttributeError abnormal .
One 、__getattr__ Method
This method is called when the property of the object does not exist . If object attributes can be found through normal mechanisms , Not invoke getattr Method .
class A:
a = 1
def __getattr__(self, item):
print('__getattr__ call')
return item
t = A()
print(t.a)
print(t.b)
# output
1
__getattr__ call
b
Two 、__getattribute__ Method
This method will be called unconditionally . Whether the attribute exists or not . If... Is also defined in the class getattr , Will not call getattr__() Method , Except in __getattribute Method __getattr__() Or throw it AttributeError .
class A:
a = 1
def __getattribute__(self, item):
print('__getattribute__ call')
raise AttributeError
def __getattr__(self, item):
print('__getattr__ call')
return item
t = A()
print(t.a)
print(t.b)
So in general , In order to retain getattr The role of ,__getattribute__() Method usually returns the method with the same name of the parent class :
def __getattribute__(self, item):
return object.__getattribute__(self, item)
Using methods of base classes to get properties can avoid infinite recursion in methods .
3、 ... and 、__get__ Method
This method is relatively simple , It has little to do with the previous .
If a class is defined __get__(), __set__() or __delete__() Any method in . The object of this class is called a descriptor .
class Descri(object):
def __get__(self, obj, type=None):
print("call get")
def __set__(self, obj, value):
print("call set")
class A(object):
x = Descri()
a = A()
a.__dict__['x'] = 1 # Not invoke __get__
a.x # call __get__
If the property to be searched is in the descriptor object , This descriptor will override the property access mechanism mentioned above , This is reflected in the difference in the search chain , The wording will be slightly different due to different calls :
Four 、__getitem__ Method
This call is also an unconditional call , With this getattribute Agreement . The difference lies in getitem Allow class instances [] operation , It can be understood in this way :
__getattribute__ For all . Operator ;
__getitem__ For all [] Operator .
class A(object): a = 1
def __getitem__(self, item):
print('__getitem__ call')
return item
t = A() print(t['a']) print(t['b'])
If you just want the object to be able to pass [] Getting object properties can be simple :
def __getitem(self, item):
return object.__getattribute__(self, item)
summary
When these methods appear at the same time, it may disturb you . I saw a good example on the Internet , A little change :
class C(object):
a = 'abc'
def __getattribute__(self, *args, **kwargs):
print("__getattribute__() is called")
return object.__getattribute__(self, *args, **kwargs)
# return "haha"
def __getattr__(self, name):
print("__getattr__() is called ")
return name + " from getattr"
def __get__(self, instance, owner):
print("__get__() is called", instance, owner)
return self
def __getitem__(self, item):
print('__getitem__ call')
return object.__getattribute__(self, item)
def foo(self, x):
print(x)
class C2(object):
d = C()
if __name__ == '__main__':
c = C()
c2 = C2()
print(c.a)
print(c.zzzzzzzz)
c2.d
print(c2.d.a)
print(c['a'])
It can be understood slowly in combination with the output , Inheritance is not involved here . All in all , Each with __get Methods prefixed with are hooks for getting internal data of objects , The names are different , There are also great differences in use , Only understand them in practice , To really master their usage .
The above is all the content shared this time , Want to know more python Welcome to official account :Python Programming learning circle , send out “J” Free access to , Daily dry goods sharing