征服畏惧建立自信的最快最确实的方法,就是去做你害怕的事,直到你获得成功的经验!
反射的魔术方法
魔术方法 | 意义 |
---|---|
_getattr_() | 当通过搜索实例、实例的类及祖先类查不到属性,就会调用此方法 |
_setattr_() | 通过.访问实例属性,进行增加、修改都要调用它 |
_delattr_() | 当通过实例来删除属性时调用此方法 |
_getattribute_ (少用) | 实例所有的属性调用都从这个方法开始 |
属性查找顺序:
实例调用_getattribute() --> instance._dict --> instance._class._dict --> 继承的祖先类(直到
object)的_dict_ --> 调用_getattr_()
1. getattr
一个类的属性会按照继承关系找,如果找不到,就会执行 getattr() 方法,如果没有这个方法,就会抛出
AttributeError异常表示找不到属性。
查找属性顺序为:
instance.dict --> instance.class.dict --> 继承的祖先类(直到object)的dict ---找不到--> 调
用getattr()_getattr_跟类无关,只跟实例调用有关
属性不存在的情况下,参数作为item送入 getattr;
class B:
a = 200
class A(B):
z = 100
def __init__(self,x,y):
self.x = x
self.y = y
def __getattr__(self,item):
print('__getattr',item) #
return 'abc'
print(A.z)
A.z = 1000
print('-'*30)
a = A(1,2)
print(a.x)
print(a.y)
print(a.z)
print(getattr(a,'x'))
print('-'*30)
print(a.b)
print('-'*30)
print(getattr(a,'c')) # 等价于 a.c
#---------------------------------------------------------
100
------------------------------
1
2
1000
1
------------------------------
__getattr b
abc
------------------------------
__getattr c
abc
2. setattr
如果没有setattr方法,属性初始化init的赋值是成功的;
只要属性是赋值的方式,setattr它就参与;属性必须添加进setattr;
实例通过.点号设置属性,例如self.x = x,就会调用 setattr() ,属性要加到实例的 dict 中,就需要自己
完成。
class B:
b = 200
class A(B):
z = 100
def __init__(self,x,y):
self.x = x
setattr(self,'y',y)
self.__dict__['a'] = 5
def __getattr__(self,item): # 缺省属性;
print('__getattr~~~~~~~~',item) #
return self.d[item]
def __setattr__(self,key,value): # 添加属性; 只要实例是赋值的方式,它就参与;
print(key)
print(value)
self.__dict__[key] = value
a = A(4,5)
print(a.__dict__)
print(A.__dict__)
print(a.x)
print(a.a)
# -------------------------------------------------------------------
x
4
y
5
{'x': 4, 'y': 5, 'a': 5} # setattr 方法;
{'__module__': '__main__', 'z': 100, '__init__': <function A.__init__ at 0x000001C624D82950>, '__getattr__': <function A.__getattr__ at 0x000001C624D82AE8>, '__setattr__': <function A.__setattr__ at 0x000001C624D82A60>, '__doc__': None}
4
5
3. delattr
class A(B):
z = 100
def __init__(self,x,y):
self.x = x
setattr(self,'y',y)
self.__dict__['a'] = 5
def __getattr__(self,item): # 缺省属性;
print('__getattr~~~~~~~~',item) #
return self.d[item]
def __setattr__(self,key,value): # 添加属性; 只要实例是赋值的方式,它就参与;
print(key)
print(value)
self.__dict__[key] = value
def __delattr__(self,item):
print('can not del {}'.format(item))
a = A(4,5)
print(a.__dict__)
print(A.__dict__)
print(a.x)
print(a.a)
#del a.__dict__['a']
del a.a
print(a.__dict__)
#-------------------------------------------------------------------------
x
4
y
5
{'x': 4, 'y': 5, 'a': 5}
{'__module__': '__main__', 'z': 100, '__init__': <function A.__init__ at 0x000001C624F6BB70>, '__getattr__': <function A.__getattr__ at 0x000001C624F6BD08>, '__setattr__': <function A.__setattr__ at 0x000001C623D96BF8>, '__delattr__': <function A.__delattr__ at 0x000001C625216048>, '__doc__': None}
4
5
can not del a
{'x': 4, 'y': 5, 'a': 5}
4. getattribute 第一关 拦截属性的搜索
实例的所有的属性访问,第一个都会调用 _getattribute_ 方法,它阻止了属性的查找,该方法应该返回(计算后的)值或者抛出一个AttributeError异常。
- 它的return值将作为属性查找的结果。
- 如果抛出AttributeError异常,则会直接调用 _getattr_ 方法,因为表示属性没有找到
class B:
b = 200
class A(B):
z = 100
def __init__(self,x,y):
self.x = x
self.y = y
def __getattribute__(self,item):
print(item,'----------------------------')
return object.__getattribute__(self,item)
a = A(4,5)
print(a.__dict__)
print('-'*30)
print(a.x)
#--------------------------------------------------------
__dict__ ----------------------------
{'x': 4, 'y': 5}
------------------------------
x ----------------------------
4
_getattribute_ 方法中为了避免在该方法中无限的递归,它的实现应该永远调用基类的同名方法以访问需要的
任何属性,例如 object._getattribute(self, name) 。
注意,除非你明确地知道 _getattribute 方法用来做什么,否则不要使用它。
网友评论