对比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统计列表中的重复项出现的次数的方法
Aug 18 Python
Python多线程爬虫简单示例
Mar 04 Python
python实现简单聊天应用 python群聊和点对点均实现
Sep 14 Python
python合并同类型excel表格的方法
Apr 01 Python
Python字符串逆序输出的实例讲解
Feb 16 Python
Python自定义函数计算给定日期是该年第几天的方法示例
May 30 Python
django框架基于queryset和双下划线的跨表查询操作详解
Dec 11 Python
Python3读取和写入excel表格数据的示例代码
Jun 09 Python
Python StringIO及BytesIO包使用方法解析
Jun 15 Python
解析Tensorflow之MNIST的使用
Jun 30 Python
FP-growth算法发现频繁项集——构建FP树
Jun 24 Python
Python使用plt.boxplot()函数绘制箱图、常用方法以及含义详解
Aug 14 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 用sock技术发送邮件的函数
2007/07/21 PHP
Yii实现单用户博客系统文章详情页插入评论表单的方法
2015/12/28 PHP
Laravel 集成微信用户登录和绑定的实现
2019/12/27 PHP
关于PHP中interface的用处详解
2020/07/26 PHP
RR vs IO BO3 第一场2.13
2021/03/10 DOTA
如何在标题栏显示框架内页面的标题
2007/02/03 Javascript
js实现GridView单选效果自动设置交替行、选中行、鼠标移动行背景色
2010/05/27 Javascript
JS 获取select(多选下拉)中所选值的示例代码
2013/08/02 Javascript
jquery网页元素拖拽插件效果及实现
2013/08/05 Javascript
js中各种类型的变量在if条件中是true还是false
2014/07/16 Javascript
JavaScript中的object转换成number或string规则介绍
2014/12/31 Javascript
用JavaScript显示浏览器客户端信息的超相近教程
2015/06/18 Javascript
深入理解bootstrap框架之第二章整体架构
2016/10/09 Javascript
JavaScript中 this 指向问题深度解析
2017/02/21 Javascript
Node.js创建Web、TCP服务器
2017/12/05 Javascript
Element UI 自定义正则表达式验证方法
2018/09/04 Javascript
Vue2 添加数据可视化支持的方法步骤
2019/01/02 Javascript
layui.tree组件的使用以及搜索节点功能的实现
2019/09/26 Javascript
JS动态图片的实现方法完整示例
2020/01/13 Javascript
vue插件--仿微信小程序showModel实现模态提示窗功能
2020/08/19 Javascript
原生js实现自定义滚动条
2021/01/20 Javascript
Python中单、双下划线的区别总结
2017/12/01 Python
django使用django-apscheduler 实现定时任务的例子
2019/07/20 Python
pytorch 改变tensor尺寸的实现
2020/01/03 Python
Python脚本调试工具安装过程
2021/01/11 Python
纯css3实现鼠标经过图片显示描述的动画效果
2014/09/01 HTML / CSS
快速实现一个简单的canvas迷宫游戏的示例
2018/07/04 HTML / CSS
校园安全演讲稿
2014/05/09 职场文书
任命书格式
2014/06/05 职场文书
党的群众路线教育实践活动宣传标语口号
2014/06/06 职场文书
工作服管理制度范本
2015/08/06 职场文书
给校长的建议书作文400字
2015/09/14 职场文书
2016教师校本培训心得体会
2016/01/08 职场文书
golang 实现Location跳转方式
2021/05/02 Golang
MySQL大小写敏感的注意事项
2021/05/24 MySQL
一次项目中Thinkphp绕过禁用函数的实战记录
2021/11/17 PHP