对比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中使用mysql数据库详细介绍
Mar 27 Python
Python实现的数据结构与算法之链表详解
Apr 22 Python
Python实现豆瓣图片下载的方法
May 25 Python
Python装饰器基础详解
Mar 09 Python
详解常用查找数据结构及算法(Python实现)
Dec 09 Python
教你用Python创建微信聊天机器人
Mar 31 Python
解决python写入mysql中datetime类型遇到的问题
Jun 21 Python
python 发送json数据操作实例分析
Oct 15 Python
python如何使用socketserver模块实现并发聊天
Dec 14 Python
pytorch载入预训练模型后,实现训练指定层
Jan 06 Python
浅谈Tensorflow 动态双向RNN的输出问题
Jan 20 Python
通用的Django注册功能模块实现方法
Feb 05 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关于array_multisort多维数组排序的使用说明
2011/01/04 PHP
PHP 时间日期操作实战
2011/08/26 PHP
Yii框架上传图片用法总结
2016/03/28 PHP
PHP mysqli事务操作常用方法分析
2017/07/22 PHP
php使用curl_init()和curl_multi_init()多线程的速度比较详解
2018/08/15 PHP
gearman中worker常驻后台,导致MySQL server has gone away的解决方法
2020/02/27 PHP
JQuery datepicker 使用方法
2011/05/20 Javascript
如何使用jQuery来处理图片坏链具体实现步骤
2013/05/02 Javascript
通过pjax实现无刷新翻页(兼容新版jquery)
2014/01/31 Javascript
解决json日期格式问题的3种方法
2014/02/02 Javascript
Jquery时间轴特效(三种不同类型)
2015/11/02 Javascript
JavaScript性能优化之函数节流(throttle)与函数去抖(debounce)
2016/08/11 Javascript
使用JavaScript触发过渡效果的方法
2017/01/19 Javascript
从对象列表中获取一个对象的方法,依据关键字和值
2017/09/20 Javascript
jQuery实现获取动态添加的标签对象示例
2018/06/28 jQuery
Vue中的循环及修改差值表达式的方法
2019/08/29 Javascript
layui 弹出层值回传解决方式
2019/11/14 Javascript
vue实现禁止浏览器记住密码功能的示例代码
2021/02/03 Vue.js
[52:08]DOTA2上海特级锦标赛主赛事日 - 3 败者组第三轮#2Fnatic VS OG第一局
2016/03/05 DOTA
[53:52]EG vs VGJ.T 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
解决python2.7用pip安装包时出现错误的问题
2017/01/23 Python
Python决策树分类算法学习
2017/12/22 Python
Python一行代码解决矩阵旋转的问题
2019/11/30 Python
Python实现钉钉订阅消息功能
2020/01/14 Python
Python3.8.2安装包及安装教程图文详解(附安装包)
2020/11/28 Python
KARATOV珠宝在线商店:俄罗斯珠宝品牌
2019/03/13 全球购物
ECHT官方网站:男女健身服
2020/02/14 全球购物
成人继续教育实施方案
2014/03/01 职场文书
教师党员一句话承诺
2014/03/28 职场文书
2014年教师学期工作总结
2014/11/08 职场文书
酒店财务总监岗位职责
2015/04/03 职场文书
结婚司仪主持词
2015/06/29 职场文书
运动会广播稿100字
2015/08/19 职场文书
JVM入门之类加载与字节码技术(类加载与类的加载器)
2021/06/15 Java/Android
Java日常练习题,每天进步一点点(38)
2021/07/26 Java/Android
SQL 聚合、分组和排序
2021/11/11 MySQL