对比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和shell实现的校验IP地址合法性脚本分享
Oct 23 Python
在Python操作时间和日期之asctime()方法的使用
May 22 Python
python实现class对象转换成json/字典的方法
Mar 11 Python
Python实现读取机器硬件信息的方法示例
Jun 09 Python
为什么str(float)在Python 3中比Python 2返回更多的数字
Oct 16 Python
Windows系统下PhantomJS的安装和基本用法
Oct 21 Python
详解Python数据可视化编程 - 词云生成并保存(jieba+WordCloud)
Mar 26 Python
Python使用pyserial进行串口通信的实例
Jul 02 Python
Pytorch修改ResNet模型全连接层进行直接训练实例
Sep 10 Python
Python Pandas对缺失值的处理方法
Sep 27 Python
python实现密码验证合格程序的思路详解
Jun 01 Python
python3.7 openpyxl 在excel单元格中写入数据实例
Sep 01 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 5.3新特性命名空间规则解析及高级功能
2010/03/11 PHP
php带密码功能并下载远程文件保存本地指定目录 修改加强版
2010/05/16 PHP
Laravel 5框架学习之表单验证
2015/04/08 PHP
php构造方法中析构方法在继承中的表现
2016/04/12 PHP
php 类中的常量、静态属性、非静态属性的区别
2017/04/09 PHP
PHP 无限级分类
2017/05/04 PHP
JavaScript中的对象化编程
2008/01/16 Javascript
javascript 限制输入脚本大全
2009/11/03 Javascript
UserData用法总结 lanyu出品
2010/07/01 Javascript
js 判断checkbox是否选中的操作方法
2012/11/09 Javascript
extjs两个tbar问题探讨
2013/08/08 Javascript
js加入收藏夹代码(兼容ie/ff/op)
2014/05/16 Javascript
nodejs URL模块操作URL相关方法介绍
2015/03/03 NodeJs
Node.js 应用跑得更快 10 个技巧
2016/04/03 Javascript
AngularJS表单详解及示例代码
2016/08/17 Javascript
JS创建Tag标签的方法详解
2017/06/09 Javascript
Angularjs中ng-repeat的简单实例
2017/08/25 Javascript
Vue 仿QQ左滑删除组件功能
2018/03/12 Javascript
JavaScript碰撞检测原理及其实现代码
2020/03/12 Javascript
python爬虫入门教程--利用requests构建知乎API(三)
2017/05/25 Python
wxPython的安装图文教程(Windows)
2017/12/28 Python
python 获取指定文件夹下所有文件名称并写入列表的实例
2018/04/23 Python
python利用百度AI实现文字识别功能
2018/11/27 Python
pandas DataFrame的修改方法(值、列、索引)
2019/08/02 Python
python打包成so文件过程解析
2019/09/28 Python
Python语法垃圾回收机制原理解析
2020/03/25 Python
用 Python 制作地球仪的方法
2020/04/24 Python
基于TensorFlow的CNN实现Mnist手写数字识别
2020/06/17 Python
Python3中FuzzyWuzzy库实例用法
2020/11/18 Python
竞职演讲稿范文
2014/01/11 职场文书
晋江市委常委班子四风问题整改工作方案
2014/10/26 职场文书
2015公务员试用期工作总结
2014/12/12 职场文书
个人专业技术总结
2015/03/05 职场文书
2015年党风建设工作总结
2015/04/29 职场文书
MySQL 角色(role)功能介绍
2021/04/24 MySQL
MySQL Shell的介绍以及安装
2021/04/24 MySQL