对比Python中__getattr__和 __getattribute__获取属性的用法


Posted in Python onJune 21, 2016

相信大家觉得大多数时候我们并不太需要关注getattribute和getattr的一些细节(至少我自己吧:)),
一般情况下消费我们自定义的类的时候,我们对类的结构都了解,不会刻意偏离,造成一些属性访问的错误。

不过作为一个有好奇心有追求有气质的python宝宝,怎么可能不稍稍研究一下呢。好吧,其实是在github上读到一个开源项目sinaweibopy的源码才看的,代码挺有意思,正好当作一个实用的例子,来看看如何自定义实现gettattr让代码更加的动态优雅:

# 例子在原来的基础上简化了一下,排除依赖和干扰,详细参见原项目
class UrlGenerator(object):
  def __init__(self, root_url):
    self.url = root_url

  def __getattr__(self, item):
    if item == 'get' or item == 'post':
      print self.url
    return UrlGenerator('{}/{}'.format(self.url, item))


url_gen = UrlGenerator('http://xxxx')
url_gen.users.show.get

>>> http://xxxx/users/show

充分利用getattr会在没有查找到相应实例属性时被调用的特点,方便的通过链式调用生成对应的url,源代码中在碰到http method的时候返回一个
可调用的对象更加的优雅,链式的操作不仅优雅而且还能很好的说明调用的接口的意义(restful的接口啦)。

示例
1.__getattr__示例:

class Test(object):
  def __init__(self,name):
    self.name = name
  def __getattr__(self, value):
    if value == 'address':
      return 'China'

if __name__=="__main__":
  test = Test('letian')
  print test.name
  print test.address
  test.address = 'Anhui'
  print test.address

运行结果:

letian
China
Anhui

如果是调用了一个类中未定义的方法,则__getattr__也要返回一个方法,例如:

class Test(object):
  def __init__(self,name):
    self.name = name
  def __getattr__(self, value):
    return len

if __name__=="__main__":
  test = Test('letian')
  print test.getlength('letian')

运行结果:
6

2.__getattribute__示例:

class Test(object):
  def __init__(self,name):
    self.name = name
  def __getattribute__(self, value):
    if value == 'address':
      return 'China'
    

if __name__=="__main__":
  test = Test('letian')
  print test.name
  print test.address
  test.address = 'Anhui'
  print test.address

运行结果:

None
China
China

深入思考
既然能通过定制类的getattr自定义方法来实现一些优雅的功能,自然我们也要对它有一些了解,包括和它相似的自定义方法getattribute

1. 用作实例属性的获取和拦截
当访问某个实例属性时, getattribute会被无条件调用,如未实现自己的getattr方法,会抛出AttributeError提示找不到这个属性,如果自定义了自己getattr方法的话,方法会在这种找不到属性的情况下被调用,比如上面的例子中的情况。所以在找不到属性的情况下通过实现自定义的getattr方法来实现一些功能是一个不错的方式,因为它不会像getattribute方法每次都会调用可能会影响一些正常情况下的属性访问:

class Test(object):
  def __init__(self, p):
    self.p = p

  def __getattr__(self, item):
    return 'default'

t = Test('p1')
print t.p
print t.p2

>>> p1
>>> default

2. 自定义getattribute的时候防止无限递归
因为getattribute在访问属性的时候一直会被调用,自定义的getattribute方法里面同时需要返回相应的属性,通过self.__dict__取值会继续向下调用getattribute,造成循环调用:

class AboutAttr(object):
  def __init__(self, name):
    self.name = name

  def __getattribute__(self, item):
    try:
      return super(AboutAttr, self).__getattribute__(item)
    except KeyError:
      return 'default'

这里通过调用绑定的super对象来获取队形的属性,对新式类来说其实和object.__getattribute__(self, item)一样的道理:

默认情况下自定义的类会从object继承getattribute方法,对于属性的查找是完全能用的
getattribute的实现感觉还是挺抽象化的,只需要绑定相应的实例对象和要查找的属性名称就行
3.同时覆盖掉getattribute和getattr的时候,在getattribute中需要模仿原本的行为抛出AttributeError或者手动调用getattr

class AboutAttr(object):
  def __init__(self, name):
    self.name = name

  def __getattribute__(self, item):
    try:
      return super(AboutAttr, self).__getattribute__(item)
    except KeyError:
      return 'default'
    except AttributeError as ex:
      print ex

  def __getattr__(self, item):
    return 'default'

at = AboutAttr('test')
print at.name
print at.not_exised

>>>test
>>>'AboutAttr' object has no attribute 'not_exised'
>>>None

上面例子里面的getattr方法根本不会被调用,因为原本的AttributeError被我们自行处理并未抛出,也没有手动调用getattr,所以访问not_existed的结果是None而不是default.

Python 相关文章推荐
Python查询阿里巴巴关键字排名的方法
Jul 08 Python
python+opencv轮廓检测代码解析
Jan 05 Python
Python实现的括号匹配判断功能示例
Aug 25 Python
celery4+django2定时任务的实现代码
Dec 23 Python
Django中如何防范CSRF跨站点请求伪造攻击的实现
Apr 28 Python
PyQt5实现让QScrollArea支持鼠标拖动的操作方法
Jun 19 Python
Python上下文管理器全实例详解
Nov 12 Python
Python FFT合成波形的实例
Dec 04 Python
Python configparser模块应用过程解析
Aug 14 Python
如何以Winsows Service方式运行JupyterLab
Aug 30 Python
python 实现朴素贝叶斯算法的示例
Sep 30 Python
python3.7.2 tkinter entry框限定输入数字的操作
May 22 Python
常见python正则用法的简单实例
Jun 21 #Python
小议Python中自定义函数的可变参数的使用及注意点
Jun 21 #Python
简单讲解Python编程中namedtuple类的用法
Jun 21 #Python
Python编程中实现迭代器的一些技巧小结
Jun 21 #Python
Centos Python2 升级到Python3的简单实现
Jun 21 #Python
Python的Django框架中forms表单类的使用方法详解
Jun 21 #Python
Python正则表达式使用经典实例
Jun 21 #Python
You might like
PHP 截取字符串 分别适合GB2312和UTF8编码情况
2009/02/12 PHP
PHP+AJAX实现投票功能的方法
2015/09/28 PHP
PHP用PDO如何封装简单易用的DB类详解
2017/07/30 PHP
PHP7扩展开发之基于函数方式使用lib库的方法详解
2018/01/15 PHP
Js callBack 返回前一页的js方法
2008/11/30 Javascript
javascript 实用的文字链提示框效果
2010/06/30 Javascript
php对mongodb的扩展(小试牛刀)
2012/11/11 Javascript
jquery遍历checkbox介绍
2014/02/21 Javascript
js限制checkbox选中个数以限制六个为例
2014/07/15 Javascript
jQuery满屏焦点图左右滚动特效代码分享
2015/09/07 Javascript
ionic js 模型 $ionicModal 可以遮住用户主界面的内容框
2016/06/06 Javascript
JS构造函数与原型prototype的区别介绍
2016/07/04 Javascript
Node.js 文件夹目录结构创建实例代码
2016/07/08 Javascript
gulp解决跨域的配置文件问题
2017/06/08 Javascript
VueAwesomeSwiper在VUE中的使用以及遇到的一些问题
2018/01/11 Javascript
Vue组件化开发思考
2018/02/02 Javascript
webpack之devtool详解
2018/02/10 Javascript
webpack优化的深入理解
2018/12/10 Javascript
JavaScript switch语句使用方法简介
2019/12/30 Javascript
JS写滑稽笑脸运动效果
2020/05/28 Javascript
python3 破解 geetest(极验)的滑块验证码功能
2018/02/24 Python
利用Python在一个文件的头部插入数据的实例
2018/05/02 Python
pyspark操作MongoDB的方法步骤
2019/01/04 Python
python 有效的括号的实现代码示例
2019/11/11 Python
pytorch中的inference使用实例
2020/02/20 Python
前端水印的简单实现代码示例
2020/12/02 HTML / CSS
2013年高中生自我评价
2013/10/23 职场文书
会计主管岗位职责范文
2013/11/08 职场文书
国贸专业个人求职信范文
2014/01/08 职场文书
招聘专员岗位职责
2014/03/07 职场文书
演讲稿祖国在我心中
2014/05/04 职场文书
幼儿园运动会口号
2014/06/07 职场文书
万能检讨书开头与结尾怎么写
2015/02/17 职场文书
寻找最美乡村教师观后感
2015/06/18 职场文书
Go语言操作数据库及其常规操作的示例代码
2021/04/21 Golang
MySQL中你可能忽略的COLLATION实例详解
2021/05/12 MySQL