介绍几个python中比较实用的魔法方法:
1. __getattribute__(self,name):当特性name被访问时自动调用(只能在新式类中使用) 无条件被调用,通过实例访问属性。如果类中定义了__getattr__(),则__getattr__()不会被调用(除非显示调用或者引发AttributeError异常)
2. __getattr__(self,name):当特性name被访问且对象没有响应的属性时被自动调用
3. __setattr__(self,name):当试图给属性name赋值时会自动被调用
4. __delattr__(self,name):当试图删除属性name时被自动调用
先看一个简单的例子:
-
#!/usr/bin/python
-
class storage(dict):
-
def __setattr__(self,key,value):
-
self[key] = value
-
def __getattr__(self,key):
-
try:
-
return self[key]
-
except KeyError,k:
-
return None
-
def __delattr__(self,key):
-
try:
-
del self[key]
-
except KeyError,k:
-
return None
-
def __call__(self,key): # __call__方法用于实例自身的调用,达到()调用的效果
-
try:
-
return self[key]
-
except KeyError,k:
-
return None
-
-
if __name__ == '__main__':
-
s =storage()
-
s.test = "hello" # 这是自动调用__setattr__方法
-
print s('test') # 这是自动调用__call__方法
-
print s.test # 这是调用__getattr__方法
-
del s.test # 这是调用__delattr__方法
-
print s('test')
-
print s.test
-
[root@server1 python]# ./test1.py
-
hello
-
hello
-
None
-
None
例 2:
-
#!/usr/bin/python
-
class rectangle:
-
def __init__(self):
-
self.width = 0
-
self.height = 0
-
def __setattr__(self,name,value): # 当试图给name赋值时,该方法自定调用
-
if name == 'size':
-
self.width,self.height = value
-
else:
-
self.__dict__[name] = value
-
def __getattr__(self,name): # 当属性name被访问且对象没有响应的属性时,被调用
-
if name == 'size':
-
return self.width,self.height
-
else:
-
raise AttributeError
-
-
if __name__ == '__main__':
-
r = rectangle()
-
r.size = 10,20
-
print r.size
-
print r.width
-
print r.height
-
r.abc = 1,2
-
print r.abc
-
print r.width
-
print r.height
-
[root@server1 python]# ./test.py # 运行结果
-
(10, 20) # 当r.size = 10,20
-
10 # r.width = 10
-
20 # r.height = 20
-
(1, 2) # r.abc = 1,2
-
10 # r.width 不变,因为if判断 name = ‘size’时,self.width,self.height = value
-
20
例 3:
-
#!/usr/bin/python
-
class C(object):
-
a = 'abc'
-
def __getattribute__(self,*args,**kwargs):
-
print ("__getattribute__() is called")
-
return object.__getattribute__(self,*args,**kwargs)
-
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 foo(self,x):
-
print x
-
-
class C2(object):
-
d = C()
-
-
if __name__ == '__main__':
-
c = C()
-
c2 = C2()
-
print c.a # 类变量a是存在的,自动调用__getattribute__()方法
-
print c.zzzzzzz # 由于zzzzzzz变量属性不存在,因此调用__getattr__()方法
-
c2.d
-
print c2.d.a # 实例调用父类a变量
-
[root@server1 python]# ./test3.py
-
__getattribute__() is called
-
abc
-
__getattribute__() is called
-
__getattr__() is called
-
zzzzzzzfrom getattr
-
('__get__() is called', <__main__.C2 object at 0x7f494adf9190>, <class '__main__.C2'>)
-
('__get__() is called', <__main__.C2 object at 0x7f494adf9190>, <class '__main__.C2'>)
-
__getattribute__() is called
-
abc
小结:可以看出,每次通过实例访问属性,都会经过 __getattribute__函数,而当属性不存在时,仍然需要访问 __getattribute__() 不过接着就要访问 __getattr__() 就好像一个异常处理函数。
每次访问descriptor(即实现了__get__的类),都会先经过__get__函数。
需要注意的是,当使用类访问不存在的变量是,不会经过__getattr__函数。而descriptor不存在此问题,只是把instance标识为none而已。
阅读(1494) | 评论(0) | 转发(0) |