python对象 属性访问优先级:object.name
object.__getattribute__(self, name)
- 类 中的 数据描述符
object.__dict__.get(name)
自身属性字典object.__class__.__dict__.get(name)
类属性字典 / 非数据描述符object.__getattr__(name)
- 描述符:定义了
__get__()
的 类 #没有定义,返回描述符(普通类)实例 - 数据(覆盖型)描述符: 定义了
__set__()
或者__delete__()
中一个以上
类属性name如果是数据描述符,会截断 实例的属性访问和修改:
"self.name = value
";就变成了name.__set__(self, ins, value)
"self.name
";就变成了name.__get__(self, ins, ins.__class__ )
定义
__delete__()
没定义__set__()
,在实例赋值时就会报错定义
__set__()
没定义__delete__()
,在实例删除 就会报错
试验代码:
# -*- coding: utf-8 -*-# author: willowj# date: 2018-01-03 21:32:50# py2.7class Descdata(object): def __init__(self, name=''): self.name = name self.value = 0 # 常用dict,可根据不同的instance set不同的值,get 返回不同的值 # 相当于给每一个实例绑定了一个值 def __get__(self, instance, owner=None): print("Descdata:inst> %s__get__() is called---" % self.name, instance, owner) return self.value def __set__(self, instance, value): print("Descdata:inst> %s __set__() is called---" % self.name, instance, value) self.value = value def __delete__(self): print('Descdata inst %s: .__delete__---'% self.name) del selfclass Desc_not_data(object): def __init__(self, name='', value='as654'): self.name = name self.value = value def __get__(self, instance, owner=None): print("Desc_not_data:inst> %s__get__() is called---" % self.name, instance, owner) return self.valueclass Base(object): def __getattribute__(self, *args, **kwargs): print("Base __getattribute__() is called") return object.__getattribute__(self, *args, **kwargs)class Test(Base): a = 'abc' d_d = Descdata(name='d_d') # 数据描述符,如果实例有同名属性 会拦截 nd = Desc_not_data(name='nd') # 非数据描述符,如果实例有同名属性 不会拦截 nd2 = Desc_not_data(name='nd2') # 非数据描述符,如果实例有同名属性 不会拦截 def __init__(self, *args, **kwargs): self.d_d = 'Test_ins self d_d' # if cls.d_d 是数据描述符,这里就是调用数据描述符的 __set__ # 类属性name如果是数据描述符,会截断--实例ins: "self.name = value"; # 要是定义了 __delete__ 没定义 __set__,在实例赋值时就会报错 self.nd2 = 'Test_>nd2' # 优先于 非数据描述符 def __getattribute__(self, *args, **kwargs): print("Test __getattribute__() is called") return Base.__getattribute__(self, *args, **kwargs) def __getattr__(self, name): print("Test __getattr__() is called ") return name + " from __getattr__"q = Test() # __init__ : 赋值 数据描述符# ('Descdata:inst> d_d __set__() is called---', <__main__.Test object at 0x0000000002B69DD8>, 'Test_ins self d_d')print('-'*30,u'visit data descriptor')print 'q.d_d\n', q.d_d, '\n'# ('------------------------------', u'visit data descriptor')# q.d_d# Test __getattribute__() is called# Base __getattribute__() is called# ('Descdata:inst> d_d__get__() is called---', <__main__.Test object at 0x0000000002B69DD8>,)# Test_ins self d_dprint('-'*30,u'visit non data descriptor not overided by instance')print 'q.nd\n', q.nd, '\n'# ('------------------------------', u'visit non data descriptor')# q.nd# Test __getattribute__() is called# Base __getattribute__() is called# ('Desc_not_data:inst> nd__get__() is called---', <__main__.Test object at 0x0000000002B69DD8>, )# as654print('-'*30,u'visit non data descriptor overided by instance')print 'q.nd2\n', q.nd2, '\n'# ('------------------------------', u'visit non data descriptor overided by instance')# q.nd2# Test __getattribute__() is called# Base __getattribute__() is called# Test_>nd2print('-'*30,u"visit attr that not exist" )print 'q.nnnnnnnnnnnnn\n', q.nnnnnnnnnnnnn, '\n'# ('------------------------------', u'visit attr that not exist')# q.nnnnnnnnnnnnn# Test __getattribute__() is called# Base __getattribute__() is called# Test __getattr__() is called# nnnnnnnnnnnnn from __getattr__print('\n q.__dict__')print q.__dict__# q.__dict__# Test __getattribute__() is called# Base __getattribute__() is called# {'nd2': 'Test_>nd2'}print('-'*30,'\n',' Test.__dict__')a_dict_ = dict(Test.__dict__)for k in a_dict_: print k,' '*(20-len(k)),a_dict_[k]# ('------------------------------', '\n', ' Test.__dict__')# a abc# __module__ __main__# nd <__main__.Desc_not_data object at 0x0000000002AA9DA0># __getattribute__ # __getattr__ # d_d <__main__.Descdata object at 0x0000000002AA9D30># nd2 <__main__.Desc_not_data object at 0x0000000002AA9DD8># __doc__ None# __init__ print('-'*30)print Test.__dict__['__getattribute__'] ,type(Test.__dict__['__getattribute__'])#
推荐资料