对比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检测主机存活端口及检查存活主机
Oct 12 Python
Python中文分词实现方法(安装pymmseg)
Jun 14 Python
利用Anaconda完美解决Python 2与python 3的共存问题
May 25 Python
python 读写文件,按行修改文件的方法
Jul 12 Python
使用PM2+nginx部署python项目的方法示例
Nov 07 Python
python调用staf自动化框架的方法
Dec 26 Python
解决python super()调用多重继承函数的问题
Jun 26 Python
Python字符串对象实现原理详解
Jul 01 Python
浅谈pycharm使用及设置方法
Sep 09 Python
python GUI库图形界面开发之PyQt5开发环境配置与基础使用
Feb 25 Python
详解基于Jupyter notebooks采用sklearn库实现多元回归方程编程
Mar 25 Python
matplotlib画混淆矩阵与正确率曲线的实例代码
Jun 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中的函数嵌套层数限制分析
2011/06/13 PHP
php shell超强免杀、减少体积工具实现代码
2012/10/16 PHP
yii操作cookie实例简介
2014/07/09 PHP
PHP改进计算字符串相似度的函数similar_text()、levenshtein()
2014/10/27 PHP
PHP中error_reporting()用法详解
2015/08/31 PHP
[原创]ThinkPHP中SHOW_RUN_TIME不能正常显示运行时间的解决方法
2015/10/10 PHP
调试WordPress中定时任务的相关PHP脚本示例
2015/12/10 PHP
JavaScript中的其他对象
2008/01/16 Javascript
Jsonp 跨域的原理以及Jquery的解决方案
2010/05/18 Javascript
JS Map 和 List 的简单实现代码
2013/07/08 Javascript
输入自动提示搜索提示功能的javascript:sugggestion.js
2013/09/02 Javascript
JS.elementGetStyle(element, style)应用示例
2013/09/24 Javascript
js中一个函数获取另一个函数返回值问题探讨
2013/11/21 Javascript
JavaScript中判断变量是数组、函数或是对象类型的方法
2015/02/25 Javascript
JS搜狐面试题分析
2016/12/16 Javascript
JS将网址url转化为JSON格式的方法
2018/07/02 Javascript
vue项目前端知识点整理【收藏】
2019/05/13 Javascript
解决Vue @submit 提交后不刷新页面问题
2020/07/18 Javascript
Vue插槽_特殊特性slot,slot-scope与指令v-slot说明
2020/09/04 Javascript
[04:21]狐狸妈带你到现场 DOTA2 TI中国区预选赛线下赛路线指引
2014/05/22 DOTA
python基础教程之缩进介绍
2014/08/29 Python
Python 内置函数进制转换的用法(十进制转二进制、八进制、十六进制)
2018/04/30 Python
django xadmin中form_layout添加字段显示方式
2020/03/30 Python
基于python requests selenium爬取excel vba过程解析
2020/08/12 Python
喜诗官方在线巧克力店:See’s Candies
2017/01/01 全球购物
STAY JAPAN台湾:预订日本民宿
2018/07/22 全球购物
加拿大国民体育购物网站:National Sports
2018/11/04 全球购物
澳大利亚领先的内衣店:Bendon Lingerie澳大利亚
2020/05/15 全球购物
机械设计专业应届生求职信
2013/11/21 职场文书
应付会计岗位职责
2013/12/12 职场文书
医院门卫岗位职责
2013/12/30 职场文书
生物学学生自我评价
2014/01/17 职场文书
秋季红领巾广播稿
2014/01/27 职场文书
市政管理求职信范文
2014/05/07 职场文书
刚学完怎么用Python实现定时任务,转头就跑去撩妹!
2021/06/05 Python
PyCharm 配置SSH和SFTP连接远程服务器
2022/05/11 Python