Python getattr,getattribute,getitem,get的区别
性质
object.__getitem__(self,name)
给予对象类似 dict 的 obj[‘name’]的访问能力.
正常 dict:
a={"1":1,"2":2}
#__getitem__
a["1"]
#__getitem__
a["3"] =3
#__getattr__,dict报错
a.1
要使用a.1
?,自然是实现__setattr__
object.__getattr__(self, name)
发生在再访问默认 attribute 找不到,引起 AttributeError 之前: attribute 的默认访问顺序:
instance.__dict__-->type(instance).__dict__-->baseClass.__dict -->__getattr__()-->raise AttributeError
__setattr__
自然是在 self.dict里添加内容:
self.__dict__['name']=value
即最终调用了 self.dict的__setitem__
.
object.__getattribute__(self, name)
属性访问都无条件地先通过它
. 如果重写了,最好用 object.getattribute(self, name)
AttributeDict 的例子
class AttributeDict(dict):
def __setitem__(self,name,value):
print('__setitem__,')
return super().__setitem__(name,value)
def __getitem__(self,name):
print('__getitem__, find in dict data-structure')
return super().__getitem__(name)
def __setattr__(self,name,value):
print('__setattr__ , put name:value in instance.__dict__')
return super().__setattr__(name,value)
def __getattr__(self,name):
print('__getattr__ if finally not find anything, come for me')
try:
# goto self.__getitem__
value = self[name]
except KeyError:
print('None exsited key')
return None
if isinstance(value,dict):
value = AttributeDict(value)
return value
def __getattribute__(self,name):
print('__getarrtribute__ I handle all attribute at very first')
#通过object显示调用__getattr__
# 如果不显示使用,除非属性找不到,否则不再调用__getattr__
return object.__getattribute__(self,name)
AttributeDict 的 key-val,通过 attribute 能访问到, 是因为上面__getattr__
的实现里间接调用了__getitem__
:
a = AttributeDict({"name":"Bob", "year":1986})
print(a.name)
__getarrtribute__ I handle all attribute at very first
__getattr__ if finally not find anything, come for me
__getitem__, find in dict data-structure
Bob
不存在的 attribute,dict 里也没有该数据,最终也不会有:
a.what
_getarrtribute__ I handle all attribute at very first
__getattr__ if finally not find anything, come for me
__getitem__, find in dict data-structure
None exsited key
增加 what 属性到 intance.dict中,调用了__setattr__
:
a.what = 666
__setattr__ , put name:value in instance.__dict__
a.__dict__
{'what': 666}
a[‘what’]仅查 dict 的数据,不会查 attribute,所以找不到:
a['what']
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getitem__, find in dict data-structure
---------------------------------------------------------------------------
KeyError Traceback (most recent call last)
<ipython-input-639-4aceedcebab4> in <module>
----> 1 a['what']
<ipython-input-632-361f168d5d96> in __getitem__(self, name)
6 def __getitem__(self,name):
7 print('__getitem__, find in dict data-structure')
----> 8 return super().__getitem__(name)
9
10 def __setattr__(self,name,value):
KeyError: 'what'
‘what’:123 放在 dict 里:
a['what'] = 123
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__setitem__,
正常字典访问:
a['what']
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getarrtribute__ I handle all attribute at very first
__getitem__, find in dict data-structure
123
属性访问,访问到 a.dict中:
a.what
__getarrtribute__ I handle all attribute at very first
666
属性访问不到,但最终通过getitem找到了 what_again 的值:
a['what_again'] = 999
a['what_again']
__getarrtribute__ I handle all attribute at very first
__getattr__ if finally not find anything, come for me
__getitem__, find in dict data-structure
999
dict 里的值,并没有属性 what:666:
a.items()
__getarrtribute__ I handle all attribute at very first
dict_items([('name', 'Bob'), ('year', 1986), ('what', 123), ('what_again', 999)])
dict 的 str 和 repr 默认就是 item():
str(a)
"{'name': 'Bob', 'year': 1986, 'what': 123, 'what_again': 999}"
__get__与描述符类
__get__
和上面的 3 个不是 1 个概念,和是描述符有关.
什么是描述符:python descriptors
实现了下面任一函数的类,即遵循了描述符协议,是 1 个描述符类:
object.__get__(self, instance, owner)
object.__set__(self, instance, value)
object.__delete__(self, instance)
object.__set_name__(self, owner, name)
仅定义get(),为 non-data descriptor,让属性read only
.python 的classmethod staticmethod
就是 non-data descriptor.
定义了set(),delete(),为 data descriptor,read and write
.python 的property
就是 data descriptor.
前面讲了 attribute 的访问顺序.当访问某个属性,而这个恰好又是 1 个实现了描述符协议的 object 时,将直接调用get等方法,跳过默认的属性访问顺序,相当于属性访问路由到了get的函数调用,并由这个函数来控制这个属性的值(也即函数的返回值,在返回前,可以做定制化的操作.
类似还有个 LazyProperty,即延迟初始化的属性.