一、 引言

《第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. Java线程状态及切换

    Java线程状态及切换 一.什么是Java线程状态 在Java程序中,用于描述Java线程的六种状态: 新建(NEW):当前线程,刚刚新建出来,尚未启动. 运行(RUNNABLE):当前线程,处于竞争 ...

  2. 面试题:你有没有搞混查询缓存和Buffer Pool

    一. 关注送书!<Netty实战> 文章公号号首发!连载中!关注微信公号回复:"抽奖" 可参加抽活动 首发地址:点击跳转阅读原文,有更好的阅读体验 使用推荐阅读,有更好 ...

  3. Socket 套接字的系统调用

    socket 结构 /** * struct socket - general BSD socket * @state: socket state (%SS_CONNECTED, etc) * @ty ...

  4. Exactly Once 语义

    将服务器的 ACK 级别设置为-1,可以保证 Producer 到 Server 之间不会丢失数据,即 At Least Once 语义. 相对的,将服务器 ACK 级别设置为 0,可以保证生产者每条 ...

  5. Linux (操作二)

    1.U盘的装载与卸载(设备都保存在/dev中  /dev存放设备的文件) 1.卸载u盘 umount /media/xxx/xxx  (xxx为具体路径) 2.查看设备 sudo fdisk -l ( ...

  6. putty连接Linux(NAT)

    1.系统装好后第一次连的时候需要打开ssh服务 sudo apt-get install openssh-server 当在机器不能通过ping ip相通的话那么就要解决ip不同的问题,当ip相通还是 ...

  7. HotSpot源码分析之C++对象的内存布局

    HotSpot采用了OOP-Klass模型来描述Java类和对象.OOP(Ordinary Object Pointer)指的是普通对象指针,而Klass用来描述对象的具体类型.为了更好理解这个模型, ...

  8. 快速增加osdmap的epoch

    最近因为一个实验需要用到一个功能,需要快速的增加 ceph 的 osdmap 的 epoch 编号 查询osd的epoch编号 root@lab8107:~# ceph osd stat osdmap ...

  9. 文本多行省略号(CSS最优方案)

    Float定位溢出隐藏 优点: 纯CSS实现,性能好,不用js调优 兼容性高 多行省略,自动显示 缺点: 单词截断 代码如下: <div class="ellipses-div&quo ...

  10. Flink处理函数实战之三:KeyedProcessFunction类

    欢迎访问我的GitHub https://github.com/zq2599/blog_demos 内容:所有原创文章分类汇总及配套源码,涉及Java.Docker.Kubernetes.DevOPS ...