一、 引言

前面几节分别介绍了Python中属性操作捕获的三剑客:__ getattribute__方法、__setattr__方法、__delattr__方法,为什么__ getattribute__方法与后两者的命名规则会不同呢?为什么属性读取的方法不是__ getattr__方法呢?这是因为Python中__ getattr__方法别有用途。

二、 __getattr__与__getattribute__关系

__getattr__是Python中的内置函数,该函数可以在实例的属性查看时出现异常时执行,object类的__getattr__直接抛出异常。

__getattr__与__getattribute__都是内置方法,都是与属性查看相关的方法,当Python每次调用一个实例的属性查看时,Python会无条件进入__getattribute__中,而当对应属性不存在时,Python就会调用__getattr__来进行处理。

  1. 当默认属性访问因引发 AttributeError 而失败时__getattr__被调用,这种调用:

    1)可能是调用 __getattribute__() 时由于 name 不是一个实例属性或 self 的类关系树中的属性而引发了 AttributeError

    2)可能是对 name 特性属性调用 __get__() 时引发了 AttributeError
  2. 此方法应当返回(找到的)属性值或是引发一个 AttributeError 异常。如果属性是通过正常机制找到的,__getattr__() 就不会被调用;
  3. 重写__getattr__()时,如果重写的自定义方法不能在自定义代码中返回对应值或抛出异常,则可以调用父类的__getattr__()方法。

三、 为什么有__getattribute__还需要__getattr__

通过前面的介绍,我们知道__getattr__执行时,__getattribute__肯定会执行,__getattribute__执行时,不一定会执行__getattr__。那为什么还需要__getattr__呢?

这是Python在 __getattr__() 和 __setattr__() 之间故意设置的不对称性:

  1. 这是为了提高处理效率,__getattribute__不论什么情况查看属性都会执行,而 __getattr__只在属性错误的情况下执行,如果业务逻辑只要求错误情况下才进行捕获处理,则__getattribute__重写会导致访问效率降低;
  2. 如果出错情况下调用__getattribute__,而在处理逻辑中为了支持这种异常情况的处理可能会需要访问实例的其他属性,这会导致再次触发__getattribute__,从而可能导致嵌套调用甚至无穷尽的调用,而使用__getattr__则可以避免这种情况

四、 案例

  1. 案例说明

    案例中定义了类Car,类中有构造方法、__getattribute__和__getattr__方法,用该类定义实例对象car,通过实例访问正常的实例变量和不存在的方法、不存在的实例变量,看__getattribute__和__getattr__方法的执行情况。
  2. 源代码
>>> car = Car('汽油发动机')
>>> car.power #存在的属性查看只调用了__getattribute__
execute __getattribute__power
>>> car.drive() #一个不存在的方法drive调用了__getattribute__,同时还调用了__getattr__,最后抛出AttributeError异常
execute __getattribute__drive
execute __getattr__:name=drive
Traceback (most recent call last):
File "<pyshell#50>", line 1, in <module>
car.drive() #一个不存在的方法drive调用了__getattribute__,同时还调用了__getattr__,最后抛出AttributeError异常
File "<pyshell#47>", line 12, in __getattr__
super().__getattr__(name)
AttributeError: 'super' object has no attribute '__getattr__'
>>> car.Power #一个不存在的实例变量Power调用了__getattribute__,同时还调用了__getattr__,最后抛出AttributeError异常
execute __getattribute__Power
execute __getattr__:name=Power
Traceback (most recent call last):
File "<pyshell#51>", line 1, in <module>
car.Power #一个不存在的实例变量Power调用了__getattribute__,同时还调用了__getattr__,最后抛出AttributeError异常
File "<pyshell#47>", line 12, in __getattr__
super().__getattr__(name)
AttributeError: 'super' object has no attribute '__getattr__'
>>>
  1. 执行截图

本节介绍了__getattr__方法触发的场景,并与__getattribute__方法进行了比对,开发者可以在特定情况下重写该方法对抛出异常进行截获,如特定条件下网络访问URL的重定向。

老猿Python,跟老猿学Python!

博客地址:https://blog.csdn.net/LaoYuanPython


请大家多多支持,点赞、评论和加关注!谢谢!

第8.33节 Python中__getattr__以及__getattr__与__ getattribute__的关系深入剖析的更多相关文章

  1. 第7.19节 Python中的抽象类详解:abstractmethod、abc与真实子类

    第7.19节 Python中的抽象类详解:abstractmethod.abc与真实子类 一.    引言 前面相关的章节已经介绍过,Python中定义某种类型是以实现了该类型对应的协议为标准的,而不 ...

  2. 第7.15节 Python中classmethod定义的类方法详解

    第7.15节  Python中classmethod定义的类方法详解 类中的方法,除了实例方法外,还有两种方法,分别是类方法和静态方法.本节介绍类方法的定义和使用. 一.    类方法的定义 在类中定 ...

  3. 第7.26节 Python中的@property装饰器定义属性访问方法getter、setter、deleter 详解

    第7.26节 Python中的@property装饰器定义属性访问方法getter.setter.deleter 详解 一.    引言 Python中的装饰器在前面接触过,老猿还没有深入展开介绍装饰 ...

  4. 第7.22节 Python中使用super调用父类的方法

    第7.22节 Python中使用super调用父类的方法 前面章节很多地方都引入了super方法,这个方法就是访问超类这个类对象的.由于super方法的特殊性,本节单独谈一谈super方法. 一.su ...

  5. 第8.23节 Python中使用sort/sorted排序与“富比较”方法的关系分析

    一. 引言 <第8.21节 Python中__lt__.gt__等 "富比较"("rich comparison")方法用途探究>和<第8.2 ...

  6. 第8.27节 Python中__getattribute__与property的fget、@property装饰器getter关系深入解析

    一. 引言 在<第7.23节 Python使用property函数定义属性简化属性访问的代码实现>和<第7.26节 Python中的@property装饰器定义属性访问方法gette ...

  7. 第11.20节 Python 中正则表达式的扩展功能:后视断言、后视取反

    一. 引言 在<第11.19节 Python 中正则表达式的扩展功能:前视断言和前视取反>中老猿介绍了前视断言和前视取反,与二者对应的还有后视断言和后视取反. 二. (?<=-)后视 ...

  8. 第14.12节 Python中使用BeautifulSoup解析http报文:使用select方法快速定位内容

    一. 引言 在<第14.10节 Python中使用BeautifulSoup解析http报文:html标签相关属性的访问>和<第14.11节 Python中使用BeautifulSo ...

  9. 第14.11节 Python中使用BeautifulSoup解析http报文:使用查找方法快速定位内容

    一. 引言 在<第14.10节 Python中使用BeautifulSoup解析http报文:html标签相关属性的访问>介绍了BeautifulSoup对象的主要属性,通过这些属性可以访 ...

随机推荐

  1. 微信小程序开发实战(云开发)--资产管理工具

    添加首页 menu页面 截图展示 menu.js源码 // pages/menu/menu.js Page({ /** * 页面的初始数据 */ data: { }, /** * 生命周期函数--监听 ...

  2. GraphX 在图数据库 Nebula Graph 的图计算实践

    不同来源的异构数据间存在着千丝万缕的关联,这种数据之间隐藏的关联关系和网络结构特性对于数据分析至关重要,图计算就是以图作为数据模型来表达问题并予以解决的过程. 一.背景 随着网络信息技术的飞速发展,数 ...

  3. Spring源码解析之BeanFactoryPostProcessor(一)

    BeanFactoryPostProcessor 在前面几个章节,笔者有介绍过BeanFactoryPostProcessor,在spring在解析BeanDefinition之后,正式初始化bean ...

  4. Java8 新特性 —— Stream 流式编程

    本文部分摘自 On Java 8 流概述 集合优化了对象的存储,大多数情况下,我们将对象存储在集合是为了处理他们.使用流可以帮助我们处理对象,无需迭代集合中的元素,即可直接提取和操作元素,并添加了很多 ...

  5. python_super()及继承顺序

    class A(object): def func(self): print('A') class B(A): def func(self): super().func() print('B') cl ...

  6. Docker(32)- 如何修改 docker 容器的启动参数

    如果你还想从头学起 Docker,可以看看这个系列的文章哦! https://www.cnblogs.com/poloyy/category/1870863.html 前言 有时候创建容器时忘了添加  ...

  7. 基于 Nebula Operator 的 K8s 自动化部署运维

    摘要:Nebula Operator 是 Nebula Graph 在 Kubernetes 系统上的自动化部署运维插件.在本文,你将了解到 Nebula Operator 的特性及它的工作原理. 从 ...

  8. mysql语句的书写顺序和执行顺序

    mysql语句的书写顺序和执行顺序有很大差异. 书写顺序,mysql的一般书写顺写为: select <要返回的数据列> from <表名> <join, left jo ...

  9. 分布式 task_master / task_worker

    17:08:0317:08:04 在Thread(线程)和Process(进程)中,应当优选Process,因为Process更稳定,而且,Process可以分布到多台机器上,而Thread最多只能分 ...

  10. SQL Server 数据库bak备份文件还原操作和mdf文件附加操作

    前言:现在任何软件都离不开数据的支持,数据的价值是无价的,因此数据目前显得尤为重要,日常软件生产库的数据定时或实时备份必不可少,备份出的文件也需要进行验证,下边我将介绍SQL Server数据的的备份 ...