python类中默认有一些特殊方法,这篇文章记录一下特殊方法的功能及用法。
一、__getattribute__()
顾名思义,当访问object的属性会调用该方法,可以测试:
class A(object):
def __init__(self, name,age):
self.name = name
self.age = age
def __getattribute__(self, attr):
print("__getattribute__ is called")
try:
return super().__getattribute__(attr)
except AttributeError:
print(f'have no attr of {
attr}')
if __name__ == '__main__':
a = A('jyz',200)
print(a.name)
print(a.age)
print(a.gender)
输出:
__getattribute__ is called
jyz
__getattribute__ is called
200
__getattribute__ is called
have no attr of gender
None
可以看出,当我们通过object.attrname
的形式访问实例属性时,实际上我们是通过__getattribute__
得到了该属性,是不是联想到了OOP中封装的思想?别急,下面会看到更多的oop设计思想。值得一提的是,在重写__getattribute__()
方法时,一定要知道你在做什么,否则可能导致无法正确访问实例对象。另外,官方文档建议始终使用基类方法来设置属性,否则会陷入无限递归,最终栈溢出:
比如可以尝试:
class A(object):
def __init__(self, name,age):
self.name = name
self.age = age
def __getattribute__(self, attr):
return self.name
if __name__ == '__main__':
a = A('jyz',200)
print(a.name)
输出:
[Previous line repeated 996 more times]
RecursionError: maximum recursion depth exceeded
究其原因,是因为当使用self.name
访问属性时会调用__getattribute__
,而__getattribute__
又要访问self.name
,因此会无限递归下去。正确的做法是使用基类方法,对于该例子由于继承的是基类,因此使用super().__getattribute__(attr)
或object.__getattribute__(self,attr)
均可。
二、__setattr__()
实例初始化过程中,为实例属性赋值时会调用该方法。
class A(object):
def __init__(self, name,age):
self.name = name
self.age = age
def __getattribute__(self, attr):
print("__getattribute__ is called")
try:
return super().__getattribute__(attr)
except AttributeError:
print(f'have no attr of {
attr}')
def __setattr__(self, key, value):
print(f"__setattr__() is called, key is {
key}")
object.__setattr__(self, key, value)
输出:
__setattr__() is called, key is name
__setattr__() is called, key is age
与__getattribute__
同理,在__setattr__
中也尽量使用基类的该方法来设置一些属性,否则可能发生无限递归。
三、__getattr__()
从字面意思理解跟__getattribute__
差不多,事实上,该方法是__getattribute__
的补充,当访问某些属性不存在,或**__getattribute__
显示地抛出AttributeError
**,会自动转到该方法做进一步处理。
可以测试:
class A(object):
def __init__(self, name,age):
self.name = name
self.age = age
def __getattr__(self, attr):
print(f"__getattr__() is called,but {
attr} is not exist!")
if __name__ == '__main__':
a = A('jyz',200)
print(a.gender)
输出:
__getattr__() is called,but gender is not exist!
None
测试通过主动抛出异常的方式触发__getattr__()
:
class A(object):
def __init__(self, name,age):
self.name = name
self.age = age
def __getattribute__(self, attr):
if attr not in ['name','age']:
raise AttributeError
else:
return object.__getattribute__(self, attr)
def __getattr__(self, attr):
print(f"__getattr__() is called,but {
attr} is not exist!")
if __name__ == '__main__':
a = A('jyz',200)
print(a.name)
print(a.gender)
输出:
jyz
__getattr__() is called,but gender is not exist!
None
可以看到,上面两种方式都可以触发,__getattr__()
。
今天的文章python getattribute 、getattr、setattr 详解分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/28782.html