一、 引言

《第8.26节 重写Python类中的__getattribute__方法实现实例属性访问捕获》章节介绍了__getattribute__方法,可以通过重写该方法,截获所有通过“实例名.属性名”访问实例变量、类变量、实例方法的所有操作,这是一个非常符合Python风格的方法。类似的,Python提供了__setattr__方法截获所有给属性赋值的能操作,在本节的前2节介绍了调用__setattr__方法进行属性设置的方法,本节将介绍重写__setattr__方法并以此验证所有属性值的修改Python都会隐式地调用__setattr__方法。

二、 重写__setattr__方法

虽然可以动态重写__setattr__方法,但老猿并不建议这样做,我们还是建议在类中直接通过定义重写__setattr__()方法你,这样最高效也最符合编程者的思维。

  1. 语法:setattr(self, name, value)
  2. 语法释义:

    1)self,就是对象自身,如果有不理解的,请参考老猿前面的博文《第7.5节 揭开Python类中self的面纱》

    2)name:需要定义的属性名字,为字符串类型。注意属性不仅是实例变量,也可能是实例方法,但不会是类变量,因为触发该方法只能通过“对象.属性”触发,而在使用该方式给类变量赋值时,并不是赋值给类变量,而是定义了一个与类变量同名的实例变量。具体请参考老猿前面的博文《第7.12节 可共享的Python类变量》

    3)value:属性需要设置的值;
  3. 重写一个类的实例方法__setattr__后,在该类的任何个属性被尝试赋值时将调用重写的方法,这个调用会取代正常机制(即将值保存到实例字典)。因此在自定义类中重写__setattr__方法后,如果需要继续执行赋值给一个实例属性的任务,它应该调用同名的父类方法,例如 object.__setattr__方法, 或执行“实例.dict[属性名]=值”,如果调用自身的__setattr__方法执行赋值语句,会导致__setattr__方法的嵌套递归调用。

三、 案例

  1. 案例说明

    1)定义类Car,类中除了构造方法,还有实例方法drive1和重写的__setattr__;

    2)重写的__setattr__方法就是在调用时输出相关属性及其要设置的值,并为了保障属性值正常设置,调用了父类的__setattr__方法去设置属性的值;

    3)在类体外定义了实例car;

    4)在类体外定义一个函数fdrive,在定义实例后,将该函数动态赋值给类的实例变量drive2,并通过MethodType实现实例与该函数的绑定;

    5)执行相关方法查看重写的__setattr__方法的执行情况以及对__dict__的影响。

  2. 案例代码

>>> from types import MethodType #导入MethodType方法
>>> def fdrive(self,distance):
print(f"In function fdrive:distance={distance}")
self.totaldistance += distance #定义一个函数,准备用于赋值给类的实例方法属性 >>> class Car():
def __init__(self, power):
self.power = power
self.totaldistance=0 def drive1(self,distance):
print(f"In method drive:distance={distance}")
self.totaldistance+=distance def __setattr__(self,name,value):
print(f"execute __setattr__:name={name},value={value}")
self.__dict__[name]= value >>> car = Car('汽油发动机')
execute __setattr__:name=power,value=汽油发动机
execute __setattr__:name=totaldistance,value=0
>>> car.drive1(100)
In method drive:distance=100
execute __setattr__:name=totaldistance,value=100
>>> car.__setattr__('drive2',MethodType(fdrive,car)) #用函数定义实例方法drive2
execute __setattr__:name=drive2,value=<bound method fdrive of <__main__.Car object at 0x00000000045E5A90>>
>>> car.drive2(100)
In function fdrive:distance=100
execute __setattr__:name=totaldistance,value=200
>>> car.__dict__ #查看自定义实例变量
{'power': '汽油发动机', 'totaldistance': 200, 'drive2': <bound method fdrive of <__main__.Car object at 0x00000000045E5A90>>}
>>>
  1. 执行截图



5. 案例总结

1)通过上述执行情况可以确认,无论是类体内的实例方法(含构造方法)执行还是类体外的实例变量赋值,都会触发__setattr__方法的执行。因此该自定义方法可以完全捕获所有对属性的设置,如果需要加控制逻辑可以在该自定义方法中增加;

2)动态绑定的实例方法,与类体内定义的实体方法不同,动态定义的在__dict__中有一个实例变量,而类体内预定义的则没有。这是因为动态定义本身就是一个赋值语句,肯定会触发实例变量的增加。

本节结合案例介绍了重写__setattr__方法的实现以及相关注意事项,通过重写类的实该方法__setattr__,可以捕获对该类的所有属性定义和赋值。

老猿Python,跟老猿学Python!

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


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

第8.30节 重写Python __setattr__方法实现属性修改捕获的更多相关文章

  1. 第8.26节 重写Python类中的__getattribute__方法实现实例属性访问捕获

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

  2. Python魔法方法之属性访问 ( __getattr__, __getattribute__, __setattr__, __delattr__ )

    通常情况下,我们在访问类或者实例对象的时候,会牵扯到一些属性访问的魔法方法,主要包括: ① __getattr__(self, name): 访问不存在的属性时调用 ② __getattribute_ ...

  3. python魔法方法大全

    1.python魔法方法详解: python魔法方法是可以修改重载的,如果你的对象实现(重载)了这些方法中的某一个,那么这个方法就会在特殊的情况下被 Python 所调用,你可以定义自己想要的行为,而 ...

  4. 第8.22节 Python案例详解:重写 “富比较”方法控制比较逻辑

    一. 案例说明 本节定义一个小汽车的类Car,类中包括车名carname.百公里油耗oilcostper100km.价格price三个属性.然后实现__lt__.__gt__.__le__.__ge_ ...

  5. python魔法方法:__getattr__,__setattr__,__getattribute__

    python魔法方法:__getattr__,__setattr__,__getattribute__ 难得有时间看看书....静下心来好好的看了看Python..其实他真的没有自己最开始想的那么简单 ...

  6. 第8.17节 Python __repr__方法和__str__方法、内置函数repr和str的异同点对比剖析

    一. 引言 记得刚开始学习Python学习字符串相关内容的时候,查了很多资料,也做了些测试,对repr和str这两个函数的返回值老猿一直没有真正理解,因为测试发现这两个函数基本上输出时一样的.到现在老 ...

  7. 第8.29节 使用MethodType将Python __setattr__定义的实例方法与实例绑定

    一. 引言 在<第7.14节Python类中的实例方法解析>介绍了使用"实例对象名.方法名 = MethodType(函数, 对象)"将动态定义的方法与实例进行绑定 在 ...

  8. python 魔法方法补充(__setattr__,__getattr__,__getattribute__)

    python 魔法方法补充 1 getattribute (print(ob.name) -- obj.func())当访问对象的属性或者是方法的时候触发 class F(object): def _ ...

  9. Python中自定义类如果重写了__repr__方法为什么会影响到str的输出?

    这是因为Python3中,str的输出是调用类的实例方法__str__来输出,如果__str__方法没有重写,则自动继承object类的__str__方法,而object类的__str__方法是调用_ ...

随机推荐

  1. Thinkphp3.2 cms之权限管理

    五.权限管理 <?php namespace Admin\Controller; use Think\Controller; class CommonController extends Con ...

  2. leetcode97:maximum -subarray

    题目描述 请计算给出的数组(至少含有一个数字)中具有最大和的子数组(子数组要求在原数组中连续) 例如:给出的数组为[−2,1,−3,4,−1,2,1,−5,4], 子数组[−2,1,−3,4,−1,2 ...

  3. WPF应用中一种比较完美的权限控制设计方式

    如题近段时间 需要在wpf应用中设计一个权限控制 , 简而言之的说 你懂的 对于IT人员来说都知道的 常见的软件功能 首先要有用户 用户,然后用户属于哪个角色 ,然后各个角色都有自己的可供操作的一堆功 ...

  4. 解决IE9弹出json下载提示框

    <!-- 开启注解 --> <mvc:annotation-driven> <mvc:message-converters> <bean class=&quo ...

  5. 基于tensorflow的bilstm_crf的命名实体识别(数据集是msra命名实体识别数据集)

    github地址:https://github.com/taishan1994/tensorflow-bilstm-crf 1.熟悉数据 msra数据集总共有三个文件: train.txt:部分数据 ...

  6. XML fragments parsed from previous mappers already contains value for

    1. ssm项目报错: WARN  [main]  DefaultListableBeanFactory:1479-- Bean creation exception on FactoryBean t ...

  7. 硬盘LBA 和CHS的关系(转)

    磁头数 × 磁道(柱面)数 × 每道扇区数 × 每扇区字节数 l         磁头(head)数:每个盘片一般有上下两面,分别对应1个磁头,共2个磁头:l         磁道(track)数:磁 ...

  8. 解决calamari无法获取节点信息的bug

    前言 一直在做calamari的相关的一些打包和安装的工作,都是业余弄的东西,所以并没有仔细的进行功能点的验证测试,正好ceph社区群里面有人问了个问题 calamari上是不是能看到ceph的ver ...

  9. Java解释单链表中的头插法以及尾插法

    单链表属于数据结构中的一种基本结构,是一种线性结构,在此使用Java对其中的头插法以及尾插法进行解释. 首先定义好链表中的节点类: 其中,data代表节点所存放的数据,next代表指向下一节点 对于单 ...

  10. Springboot 框架整理,建议做开发的都看看,整理的比较详细!

    什么是 Spring Boot? SpringBoot是Spring项目中的一个子工程,与我们所熟知的Spring-framework 同属于spring的产品,是用来简化 spring 初始搭建和开 ...