一、 引言

前面几节分别介绍了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. php之4个坐标点判断是否为矩形和正方形

    代码 <?php $a=[0,0]; $b=[0,1]; $c=[1,1]; $d=[1,0]; $ar=array($a,$b,$c,$d); $a1=[]; // 0 1 2 3 forea ...

  2. leetcode95:jump game

    题目描述 给出一个非负整数数组,你最初在数组第一个元素的位置 数组中的元素代表你在这个位置可以跳跃的最大长度 判断你是否能到达数组最后一个元素的位置 例如 A =[2,3,1,1,4], 返回 tru ...

  3. python_面向对象_组合

    组合: 一个类的对象是另外一个类对象的属性 # 组合 # 一个类的对象是另一个类对象的属性 # 什么时候使用组合:当两个类之间的关系是 :什么有什么的关系 : 班级有学生 学生有班级 班级有课程 图书 ...

  4. notepad++覆盖了eclipse的快捷键

    好长时间发现eclipse快捷键alt+/无法使用,今天决定解决一下 1.Windows Hotkey Explorer 用此工具找到是notepad++占用了快捷键 2.C:\Program Fil ...

  5. TypeScript注意

    中文文档中,元组目前已经不能越界访问

  6. NO.A.0001——day01——Java概述/进制间的转换

    一.什么是JAVA语言:        JAVA语言是美国sun公司(Stanford University Network)在1995年推出的高级编程语言.所谓编程语言,是计算机的语言,人们可以使用 ...

  7. linux的别名(alias/unalias)

    linux中有别名时先找的别名后找命令文件 临时创建是直接用alias. [root@localhost ~]# alias ls=pwd [root@localhost ~]# ls /root 其 ...

  8. NOIP前一些题目的理解

    ZYB和售货机(图论,环) 题目链接 个人感觉这道题与基环树没有任何关系,你会发现,每个点最多只有一个入度和出度,所以只能是链或环. 还有就是本题的突破点就在于正确建图,题目的限制保证每个点的入度不大 ...

  9. vue+node+mysql

    准备工作 安装node,这是必须的 新版node自带npm,安装Node.js时会一起安装,npm的作用就是对Node.js依赖的包进行管理,也可以理解为用来安装/卸载Node.js需要装的东西.验证 ...

  10. python3 多线程批量验证POC模板

    #coding:utf-8 import threading,Queue,sys,os class RedisUN(threading.Thread): def __init__(self,queue ...