Chinaunix首页 | 论坛 | 博客
  • 博客访问: 170883
  • 博文数量: 31
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 425
  • 用 户 组: 普通用户
  • 注册时间: 2014-10-13 17:05
文章分类

全部博文(31)

文章存档

2016年(11)

2015年(20)

我的朋友

分类: LINUX

2016-01-14 13:31:43

介绍几个python中比较实用的魔法方法:

1. __getattribute__(self,name):当特性name被访问时自动调用(只能在新式类中使用) 无条件被调用,通过实例访问属性。如果类中定义了__getattr__(),则__getattr__()不会被调用(除非显示调用或者引发AttributeError异常)

2. __getattr__(self,name):当特性name被访问且对象没有响应的属性时被自动调用

3. __setattr__(self,name):当试图给属性name赋值时会自动被调用

4. __delattr__(self,name):当试图删除属性name时被自动调用

先看一个简单的例子:

  1. #!/usr/bin/python
  2. class storage(dict):
  3.     def __setattr__(self,key,value):
  4.     self[key] = value
  5.     def __getattr__(self,key):
  6.     try:
  7.      return self[key]
  8.     except KeyError,k:
  9.      return None
  10.     def __delattr__(self,key):
  11.     try:
  12.      del self[key]
  13.     except KeyError,k:
  14.      return None
  15.     def __call__(self,key):        # __call__方法用于实例自身的调用,达到()调用的效果
  16.     try:
  17.      return self[key]
  18.     except KeyError,k:
  19.      return None

  20. if __name__ == '__main__':
  21.     s =storage()
  22.     s.test = "hello"    # 这是自动调用__setattr__方法
  23.     print s('test')     # 这是自动调用__call__方法
  24.     print s.test        # 这是调用__getattr__方法
  25.     del s.test          # 这是调用__delattr__方法
  26.     print s('test')
  27.     print s.test
  28. [root@server1 python]# ./test1.py
  29. hello
  30. hello
  31. None
  32. None

例 2:

  1. #!/usr/bin/python
  2. class rectangle:
  3.     def __init__(self):
  4.     self.width = 0
  5.     self.height = 0
  6.     def __setattr__(self,name,value):        # 当试图给name赋值时,该方法自定调用
  7.     if name == 'size':
  8.      self.width,self.height = value
  9.     else:
  10.      self.__dict__[name] = value
  11.     def __getattr__(self,name):              # 当属性name被访问且对象没有响应的属性时,被调用
  12.     if name == 'size':
  13.      return self.width,self.height
  14.     else:
  15.      raise AttributeError

  16. if __name__ == '__main__':
  17.     r = rectangle()
  18.     r.size = 10,20
  19.     print r.size
  20.     print r.width
  21.     print r.height
  22.     r.abc = 1,2
  23.     print r.abc
  24.     print r.width
  25.     print r.height
  26. [root@server1 python]# ./test.py             # 运行结果
  27. (10, 20)        # 当r.size = 10,20
  28. 10              # r.width = 10
  29. 20              # r.height = 20
  30. (1, 2)          # r.abc = 1,2
  31. 10              # r.width 不变,因为if判断 name = ‘size’时,self.width,self.height = value
  32. 20

例 3:

  1. #!/usr/bin/python
  2. class C(object):
  3.     a = 'abc'
  4.     def __getattribute__(self,*args,**kwargs):
  5.     print ("__getattribute__() is called")
  6.     return object.__getattribute__(self,*args,**kwargs)
  7.     def __getattr__(self,name):
  8.     print ("__getattr__() is called")
  9.     return name + 'from getattr'
  10.     def __get__(self,instance,owner):
  11.     print ('__get__() is called',instance,owner)
  12.     return self
  13.     def foo(self,x):
  14.     print x

  15. class C2(object):
  16.     d = C()

  17. if __name__ == '__main__':
  18.     c = C()
  19.     c2 = C2()
  20.     print c.a            # 类变量a是存在的,自动调用__getattribute__()方法
  21.     print c.zzzzzzz      # 由于zzzzzzz变量属性不存在,因此调用__getattr__()方法
  22.     c2.d                
  23.     print c2.d.a         # 实例调用父类a变量
  24. [root@server1 python]# ./test3.py
  25. __getattribute__() is called
  26. abc
  27. __getattribute__() is called
  28. __getattr__() is called
  29. zzzzzzzfrom getattr
  30. ('__get__() is called', <__main__.C2 object at 0x7f494adf9190>, <class '__main__.C2'>)
  31. ('__get__() is called', <__main__.C2 object at 0x7f494adf9190>, <class '__main__.C2'>)
  32. __getattribute__() is called
  33. abc

小结:可以看出,每次通过实例访问属性,都会经过 __getattribute__函数,而当属性不存在时,仍然需要访问 __getattribute__() 不过接着就要访问 __getattr__() 就好像一个异常处理函数。
每次访问descriptor(即实现了__get__的类),都会先经过__get__函数。
需要注意的是,当使用类访问不存在的变量是,不会经过__getattr__函数。而descriptor不存在此问题,只是把instance标识为none而已。
阅读(1494) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~