网站首页 > 技术文章 正文
1 python委托定制超类getattr和getattribute管理属性
将一个类的实例属性通过self.attr=另一个类名(),赋值为另一个类对象,并且通过getattr和getattribute拦截属性来访问另一个类的属性,称为委托定制超类。
在_getattr__()中,通过getattr()返回超类实例对象的属性,从而实现超类实例属性的访问。
在__getattribute__()中,如果是本类属性通过object.__getattribute__()返回属性,避免循环;
在__getattribute__()中,如果是非本类属性,通过getattr()返回超类实例对象的属性,从而实现超类实例属性的访问。
1.1 通过getattr访问超类属性
用法
class MyClass:
def __init__(self):
# 将超类对象赋值给实例属性attr,通过委托定制超类
self.instance=超类名()
def __getattr__(self,attr):
# 拦截未定义属性的点号运算
# 返回被委托对象属性
print('MyClass 拦截未定义属性',attr)
return getattr(self.instance,attr)
描述
(1) 本类实例属性赋值为超类实例对象;
(2) 本类定义__getattr__()拦截未定义属性的点号运算;
(3) 在__getattr__()通过getattr()返回超类实例对象的属性,从而实现超类实例属性的访问。
示例
managerstaff.py
本例中,self.staff=Staff(),来实现定制超类。
# encoding=utf-8
import sys
class Staff:
def __init__(self,name,job=None,pay=0):
self.name=name
self.job=job
self.pay=pay
def surName(self):
if sys.version.split()[0].startswith('2'):
sn=self.name[:3]
else:
sn=self.name[0]
return '姓:'+sn
def giveRaise(self,rate):
self.pay=int(self.pay*(1+rate))
def __str__(self):
return '员工信息:姓名={0.name},职位={0.job},薪水={0.pay}'.format(self)
class Manager:
def __init__(self,name,pay):
# 将Staff对象赋值给Manager的实例属性,通过委托定制超类
self.staff=Staff(name,'经理',pay)
def giveRaise(self,rate,bonus=.10):
self.staff.giveRaise(rate+bonus)
def __getattr__(self,attr):
# 拦截未定义属性的点号运算
# 返回被委托对象属性
print('Manager 拦截未定义属性:'+attr)
return getattr(self.staff,attr)
def __str__(self):
# __str__ 必须返回 string , 需要用 str() 转换
return str(self.staff)
if __name__=='__main__':
import sys
print(sys.version.split()[0])
s1=Staff('张三',job='开发',pay=100000)
print(s1.surName())
s1.giveRaise(.10)
print(s1)
# Manager.__init__()
m1=Manager('李四',50000)
# 拦截未定义属性 surName,触发 Manager.__getattr__()
# 触发 Staff.surName
print(m1.surName())
# Manager.giveRaise -> Staff.giveRaise
m1.giveRaise(.10)
# Manager.__str__ -> Staff.__str__
print(m1)
python3.x 执行结果
C:\Users\Administrator>D:\python3\python.exe E:\documents\F盘\managerstaff.py
3.7.8
姓:张
员工信息:姓名=张三,职位=开发,薪水=110000
Manager 拦截未定义属性 surName
姓:李
员工信息:姓名=李四,职位=经理,薪水=60000
python2.x 执行结果
C:\Users\Administrator>chcp 65001
Active code page: 65001
C:\Users\Administrator>D:\Python27\python.exe E:\documents\F盘\managerstaff.py
2.7.18
姓:张
员工信息:姓名=张三,职位=开发,薪水=110000
Manager 拦截未定义属性:surName
姓:李
员工信息:姓名=李四,职位=经理,薪水=60000
1.2 getattr拦截print()情况
描述
getattr()拦截未定义属性,内置函数print()对应__str__()方法,当未定义__str__()时,print(实例名),python2.x会被拦截,python3.x不拦截。
NO | 调用方式 | 是否被__getattr__()拦截 |
1 | print(实例名) | python2.x被拦截 |
2 | print(实例名) | python3.x不拦截 |
示例
注释Manager的__str__()方法。
managerstaff.py
# encoding=utf-8
import sys
class Staff:
def __init__(self,name,job=None,pay=0):
self.name=name
self.job=job
self.pay=pay
def surName(self):
if sys.version.split()[0].startswith('2'):
sn=self.name[:3]
else:
sn=self.name[0]
return '姓:'+sn
def giveRaise(self,rate):
self.pay=int(self.pay*(1+rate))
def __str__(self):
return '员工信息:姓名={0.name},职位={0.job},薪水={0.pay}'.format(self)
class Manager:
def __init__(self,name,pay):
# 将Staff对象赋值给Manager的实例属性,通过委托定制超类
self.staff=Staff(name,'经理',pay)
def giveRaise(self,rate,bonus=.10):
self.staff.giveRaise(rate+bonus)
def __getattr__(self,attr):
# 拦截未定义属性的点号运算
# 返回被委托对象属性
print('Manager 拦截未定义属性:'+attr)
return getattr(self.staff,attr)
#def __str__(self):
# __str__ 必须返回 string , 需要用 str() 转换
#return str(self.staff)
if __name__=='__main__':
import sys
print(sys.version.split()[0])
s1=Staff('张三',job='开发',pay=100000)
print(s1.surName())
s1.giveRaise(.10)
print(s1)
# Manager.__init__()
m1=Manager('李四',50000)
# 拦截未定义属性 surName,触发 Manager.__getattr__()
# 触发 Staff.surName
print(m1.surName())
# Manager.giveRaise -> Staff.giveRaise
m1.giveRaise(.10)
# python2.x Manager.__getattr__()
# python3.x object.__str__()
print(m1)
python2.x执行结果
C:\Users\Administrator>chcp 65001
Active code page: 65001
C:\Users\Administrator>D:\Python27\python.exe E:\documents\F盘\managerstaff.py
2.7.18
姓:张
员工信息:姓名=张三,职位=开发,薪水=110000
Manager 拦截未定义属性:surName
姓:李
员工信息:姓名=李四,职位=经理,薪水=60000
python3.x执行结果
C:\Users\Administrator>D:\Python3\python.exe E:\documents\F盘\managerstaff.py
3.7.8
姓:张
员工信息:姓名=张三,职位=开发,薪水=110000
Manager 拦截未定义属性:surName
姓:李
<__main__.Manager object at 0x01AA8F30>
1.3 通过getattribute访问超类属性
python的__getattribute__()拦截实例的全部属性的点号运算。
python2.x必须为新式类,getattribute方法才生效。
用法
# python2.x 的 __getattribute__ 对新式类生效,所以要(object)
class MyClass(object):
def __init__(self):
# 将其它类对象赋值给实例属性instance,通过委托定制超类
self.instance=其它类名()
def __getattribute__(self,attr):
# 拦截全部属性的点号运算
print('MyClass.__getattribute__ 拦截属性:'+attr)
if attr in ('attr1','attr2'):
# 本类属性通过 object.__getattribute__ 返回,避免循环
return object.__getattribute__(self,attr)
else:
# 非本类属性通过 getattr(其它类对象,属性) 返回,实现访问超类属性
return getattr(self.instance,attr)
描述
(1) python2.x本类显式声明为新式类(object);
(2) 本类实例属性赋值为其它类实例对象,实现委托定制超类;
(3) 本类定义__getattribute__()拦截属性的点号运算;
(4) 在__getattribute__()中,如果是本类属性通过object.__getattribute__()返回属性,避免循环;
(5) 在__getattribute__()中,如果是非本类属性,通过getattr()返回超类实例对象的属性,从而实现超类实例属性的访问。
(6) 在__str__()中,通过object.__getattribute__(self,超类对象的属性名),获取超类对象的字符串显示,实现访问超类的str()方法。
示例
managerstaff.py
# encoding=utf-8
import sys
class Staff:
def __init__(self,name,job=None,pay=0):
self.name=name
self.job=job
self.pay=pay
def surName(self):
if sys.version.split()[0].startswith('2'):
sn=self.name[:3]
else:
sn=self.name[0]
return '姓:'+sn
def giveRaise(self,rate):
self.pay=int(self.pay*(1+rate))
def __str__(self):
return '员工信息:姓名={0.name},职位={0.job},薪水={0.pay}'.format(self)
# python2.x 的 __getattribute__ 对新式类生效,所以要(object)
class Manager(object):
def __init__(self,name,pay):
# 将Staff对象赋值给Manager的实例属性,通过委托定制超类
self.staff=Staff(name,'经理',pay)
def giveRaise(self,rate,bonus=.10):
self.staff.giveRaise(rate+bonus)
def __getattribute__(self,attr):
# 拦截属性的点号运算
print('Manager.__getattribute__ 拦截属性:'+attr)
if attr in ('staff','giveRaise'):
# 本类属性通过 object.__getattribute__ 返回,避免循环
return object.__getattribute__(self,attr)
else:
# 非本类属性通过 getattr(其它类对象,属性) 返回,实现访问超类属性
return getattr(self.staff,attr)
def __str__(self):
# __str__ 必须返回 string , 需要用 str() 转换
staff=object.__getattribute__(self,'staff')
return str(staff)
if __name__=='__main__':
import sys
print(sys.version.split()[0])
s1=Staff('张三',job='开发',pay=100000)
print(s1.surName())
s1.giveRaise(.10)
print(s1)
# Manager.__init__()
m1=Manager('李四',50000)
# 拦截未定义属性 surName,触发 Manager.__getattr__()
# 触发 Staff.surName
print(hasattr(m1.staff,'surName'))
print(m1.surName())
# Manager.giveRaise -> Staff.giveRaise
m1.giveRaise(.10)
# Manager.__str__ -> Staff.__str__
print(m1)
python2.x执行结果
C:\Users\Administrator>chcp 65001
Active code page: 65001
C:\Users\Administrator>D:\Python27\python.exe E:\documents\F盘\managerstaff.py
2.7.18
姓:张
员工信息:姓名=张三,职位=开发,薪水=110000
Manager.__getattribute__ 拦截属性:staff
True
Manager.__getattribute__ 拦截属性:surName
Manager.__getattribute__ 拦截属性:staff
姓:李
Manager.__getattribute__ 拦截属性:giveRaise
Manager.__getattribute__ 拦截属性:staff
员工信息:姓名=李四,职位=经理,薪水=60000
python3.x执行结果
C:\Users\Administrator>D:\Python3\python.exe E:\documents\F盘\managerstaff.py
3.7.8
姓:张
员工信息:姓名=张三,职位=开发,薪水=110000
Manager.__getattribute__ 拦截属性:staff
True
Manager.__getattribute__ 拦截属性:surName
Manager.__getattribute__ 拦截属性:staff
姓:李
Manager.__getattribute__ 拦截属性:giveRaise
Manager.__getattribute__ 拦截属性:staff
员工信息:姓名=李四,职位=经理,薪水=60000
1.4 getattribute不拦截print()
描述
__getattribute__()拦截全部属性,内置函数print()对应__str__()方法,当print(实例名)时,python2.x和python3.x都不拦截。
NO | 调用方式 | 是否被__getattribute__()拦截 |
1 | print(实例名) | python2.x不拦截 |
2 | print(实例名) | python3.x不拦截 |
示例
注释Manager的str()方法。
managerstaff.py
# encoding=utf-8
import sys
class Staff:
def __init__(self,name,job=None,pay=0):
self.name=name
self.job=job
self.pay=pay
def surName(self):
if sys.version.split()[0].startswith('2'):
sn=self.name[:3]
else:
sn=self.name[0]
return '姓:'+sn
def giveRaise(self,rate):
self.pay=int(self.pay*(1+rate))
def __str__(self):
return '员工信息:姓名={0.name},职位={0.job},薪水={0.pay}'.format(self)
# python2.x 的 __getattribute__ 对新式类生效,所以要(object)
class Manager(object):
def __init__(self,name,pay):
# 将Staff对象赋值给Manager的实例属性,通过委托定制超类
self.staff=Staff(name,'经理',pay)
def giveRaise(self,rate,bonus=.10):
self.staff.giveRaise(rate+bonus)
def __getattribute__(self,attr):
# 拦截属性的点号运算
print('Manager.__getattribute__ 拦截属性:'+attr)
if attr in ('staff','giveRaise'):
# 本类属性通过 object.__getattribute__ 返回,避免循环
return object.__getattribute__(self,attr)
else:
# 非本类属性通过 getattr(其它类对象,属性) 返回,实现访问超类属性
return getattr(self.staff,attr)
#def __str__(self):
# __str__ 必须返回 string , 需要用 str() 转换
#staff=object.__getattribute__(self,'staff')
#return str(staff)
if __name__=='__main__':
import sys
print(sys.version.split()[0])
s1=Staff('张三',job='开发',pay=100000)
print(s1.surName())
s1.giveRaise(.10)
print(s1)
# Manager.__init__()
m1=Manager('李四',50000)
# 拦截未定义属性 surName,触发 Manager.__getattr__()
# 触发 Staff.surName
print(hasattr(m1.staff,'surName'))
print(m1.surName())
# Manager.giveRaise -> Staff.giveRaise
m1.giveRaise(.10)
# Manager.__str__ -> Staff.__str__
print(m1)
python2.x执行结果
C:\Users\Administrator>chcp 65001
Active code page: 65001
C:\Users\Administrator>D:\Python27\python.exe E:\documents\F盘\managerstaff.py
2.7.18
姓:张
员工信息:姓名=张三,职位=开发,薪水=110000
Manager.__getattribute__ 拦截属性:staff
True
Manager.__getattribute__ 拦截属性:surName
Manager.__getattribute__ 拦截属性:staff
姓:李
Manager.__getattribute__ 拦截属性:giveRaise
Manager.__getattribute__ 拦截属性:staff
<__main__.Manager object at 0x0000000002F97508>
python3.x执行结果
C:\Users\Administrator>D:\Python3\python.exe E:\documents\F盘\managerstaff.py
3.7.8
姓:张
员工信息:姓名=张三,职位=开发,薪水=110000
Manager.__getattribute__ 拦截属性:staff
True
Manager.__getattribute__ 拦截属性:surName
Manager.__getattribute__ 拦截属性:staff
姓:李
Manager.__getattribute__ 拦截属性:giveRaise
Manager.__getattribute__ 拦截属性:staff
<__main__.Manager object at 0x01888F70>
2 END
本文首发微信公众号:梯阅线条,
更多内容参考python知识分享或软件测试开发目录。
猜你喜欢
- 2025-07-27 pycharm下module 'requests' has no attribute 'get'问题的解决
- 2025-07-27 「按键精灵安卓版」界面多选框实现10选3(选中不超过3个)
- 2025-07-27 Attribute Changer 11.30b属性更改器增强版
- 2025-07-27 关于Spring,必须要掌握的这25个常用注解,你知道几个?
- 2025-07-27 _attribute__((weak))关键字如何使用?
- 2025-07-27 Qt setAttribute设置窗口属性(qt设置窗口名)
- 2025-07-27 JSP request.setAttribute()详解及实例
- 2025-07-27 刘心向学(33):Python中的__getattr__与__getattribute__
- 2025-07-27 GNU __attribute详解(gnutls)
- 2025-07-27 从零开始使用特性(Attribute)在C#中实现AOP功能
- 07-27据说这是1000年以后的课本(一千年后的教科书)
- 07-27穿得好,你也可以很丁真!黑黄皮男生夏日色彩搭配指南
- 07-27进口大众贰则 丨 Volkswagen Multivan T5与CrossGolf
- 07-27《病娇模拟器》制作人让玩家投票决定游戏的发展之路
- 07-27《呻吟》内容过于真实,请谨慎阅读(四)
- 07-27汇编指令学习(ADD,SUB,MUL,DIV,XADD,INC,DEC,NEG)
- 07-27汇编语言mul乘法指令和模块化程序设计
- 07-27pycharm下module 'requests' has no attribute 'get'问题的解决
- 最近发表
-
- 据说这是1000年以后的课本(一千年后的教科书)
- 穿得好,你也可以很丁真!黑黄皮男生夏日色彩搭配指南
- 进口大众贰则 丨 Volkswagen Multivan T5与CrossGolf
- 《病娇模拟器》制作人让玩家投票决定游戏的发展之路
- 《呻吟》内容过于真实,请谨慎阅读(四)
- 汇编指令学习(ADD,SUB,MUL,DIV,XADD,INC,DEC,NEG)
- 汇编语言mul乘法指令和模块化程序设计
- pycharm下module 'requests' has no attribute 'get'问题的解决
- python委托定制超类getattr和getattribute管理属性
- 「按键精灵安卓版」界面多选框实现10选3(选中不超过3个)
- 标签列表
-
- axure 注册码 (25)
- exploit db (21)
- mutex_lock (30)
- oracleclient (27)
- nfs (25)
- springbatch (28)
- oracle数据库备份 (25)
- dir (26)
- connectionstring属性尚未初始化 (23)
- output (32)
- panel滚动条 (28)
- centos 5 4 (23)
- sql学习 (33)
- c 数组 (33)
- pascal语言教程 (23)
- ppt 教程 (35)
- java7 (24)
- 自适应网站制作 (32)
- server服务自动停止 (25)
- 超链接去掉下划线 (34)
- 什么是堆栈 (22)
- map entry (25)
- ubuntu装qq (25)
- outputstreamwriter (26)
- fill_parent (22)