python类的属性包括类属性、实例属性,
类属性:直接在类顶层赋值,或通过类名.属性名=值赋值;
实例属性:通过self赋值,或通过实例名.属性名=值赋值;
类实例可以访问类属性和实例属性;
python的特性和描述符都用于管理属性。
一个特性或描述符管理一个单个的、特定的属性。
getattr、getattribute、setattr、delattr 可以管理多个属性。
重载__getattr__()和__getattribute__()方法,在获取类实例属性值时会被自动调用。
(1)__getattr__(),针对实例属性,获取属性值时,会被自动调用;
(2)__getattribute__(),针对类和实例属性,获取属性值时,会被自动调用。
用于基于委托的场景,比如,包装对象,管理嵌套对象的全部属性访问。
用法
class C:
def __getattr__(self,name):pass
def __getattribute__(self,name):pass
def __setattr__(self,name,value):pass
def __delattr__(self,name):pass
c=C()
描述
类实例c,
未定义属性attr,c.attr自动调用__getattr__(),
未定义或已定义属性attr,c.attr自动调用__getattribute__(),
设置实例属性值时,c.attr=value,自动调用__setattr__(),
删除实例属性时,del c.attr,自动调用__delattr__()。
__getattr__()和__getattribute__()需返回一个值。
未定义属性attr,同时存在__getattr__()和__getattribute__(),c.attr自动调用getattribute,不调用getattr。
都是通过实例名操作属性时自动调用对应方法,通过类名操作属性不触发对应方法的调用。
描述
python的__getattr__()方法,针对未定义的属性,拦截属性点号运算,即未定义的属性进行点号运算(.属性名)时自动调用getattr方法。已定义的属性进行点号运算不调用getattr方法。
类名不可访问实例属性,所以,通过类名操作实例属性报错。
未定义属性attr,实例名.attr,自动调用getattr。
NO | 点号运算 | 是否调用getattr |
---|---|---|
1 | 未定义属性attr,实例名.attr | 自动调用 |
2 | 未定义属性attr,类名.attr | 不调用,报错 AttributeError |
3 | 已定义类属性attr,实例名.attr | 不调用 |
4 | 已定义实例属性attr,实例名.attr | 不调用 |
5 | 已定义类属性attr,类名.attr | 不调用 |
6 | 已定义实例属性attr,类名.attr | 不调用,报错 AttributeError |
示例
>>> class MyGet:
day=30
def __init__(self):
self.url='www.tyxt.work'
# 未定义的属性进行点号运算,自动调用 __getattr__
def __getattr__(self,attr):
print('__getattr__拦截点号运算')
if attr=='name':
return '梯阅线条'
else:
raise AttributeError(attr)
>>> mg=MyGet()
# 已定义的类属性和实例属性,实例名.属性,不调用 __getattr__
>>> mg.day,mg.url
(30, 'www.tyxt.work')
>>> mg.addr='深圳'
>>> mg.addr
'深圳'
# 未定义的属性,实例名.属性,自动调用 __getattr__
>>> mg.name
__getattr__拦截点号运算
'梯阅线条'
>>> mg.age
__getattr__拦截点号运算
Traceback (most recent call last):
File "<pyshell#20>", line 1, in <module>
mg.age
File "<pyshell#16>", line 11, in __getattr__
raise AttributeError(attr)
AttributeError: age
# 已定义的类属性,类名.属性,不调用 __getattr__
>>> MyGet.day
30
# 未定义的属性,类名.属性,不调用 __getattr__ ,报错
>>> MyGet.month
Traceback (most recent call last):
File "<pyshell#85>", line 1, in <module>
MyGet.month
AttributeError: type object 'MyGet' has no attribute 'month'
# 已定义的实例属性,类名.实例属性,不调用 __getattr__ ,报错
>>> MyGet.url
Traceback (most recent call last):
File "<pyshell#94>", line 1, in <module>
MyGet.url
AttributeError: type object 'MyGet' has no attribute 'url'
描述
python的__getattribute__()方法,针对全部属性,拦截属性点号运算,即全部属性的点号运算(.属性名),自动调用getattribute方法,包括已定义和未定义的属性。
实例可访问类属性和实例属性,所以,包括类属性和实例属性的点号运算。
类名不可访问实例属性,所以,通过类名操作实例属性报错。
未定义属性或已定义类属性或已定义实例属性为attr,实例名.attr,自动调用getattribute。
NO | 点号运算 | 是否调用getattribute |
---|---|---|
1 | 未定义属性attr,实例名.attr | 自动调用 |
2 | 未定义属性attr,类名.attr | 不调用,报错 AttributeError |
3 | 已定义类属性attr,实例名.attr | 自动调用 |
4 | 已定义实例属性attr,实例名.attr | 自动调用 |
5 | 已定义类属性attr,类名.attr | 不调用 |
6 | 已定义实例属性attr,类名.attr | 不调用,报错 AttributeError |
示例
>>> class MyGet:
day=30
def __init__(self):
self.url='www.tyxt.work'
# 全部属性的点号运算,自动调用 __getattribute__
def __getattribute__(self,attr):
print('__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性',attr)
>>> mg=MyGet()
# 已定义的类属性和实例属性,实例名.属性,自动调用 __getattribute__
>>> mg.day,mg.url
__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性 day
__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性 url
(None, None)
>>> mg.addr='深圳'
>>> mg.addr
__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性 addr
# 已定义的类属性,类名.类属性,不调用 __getattribute__
>>> MyGet.day
30
# 已定义的实例属性,类名.实例属性,不调用 __getattribute__ ,报错
>>> MyGet.url
Traceback (most recent call last):
File "<pyshell#91>", line 1, in <module>
MyGet.url
AttributeError: type object 'MyGet' has no attribute 'url'
# 未定义的属性,实例名.属性,自动调用 __getattribute__
>>> mg.name
__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性 name
# 未定义的属性,类名.属性,不调用 __getattribute__ , 报错
>>> MyGet.name
Traceback (most recent call last):
File "<pyshell#89>", line 1, in <module>
MyGet.name
AttributeError: type object 'MyGet' has no attribute 'name'
描述
python的__setattr_\_()方法,超类和本类的self.attr=value赋值运算、实例名.attr=value赋值运算、原属性修改和新属性设置的赋值运算,都会自动调用 setattr方法。
类名.attr=value赋值运算,不调用settattr方法。
实例可访问类属性和实例属性,所以,包括类属性和实例属性的赋值运算。
未定义属性或已定义类属性或已定义实例属性为attr,实例名.attr=value,自动调用setattr。
NO | 赋值运算 | 是否调用setattr |
---|---|---|
1 | 超类self.attr=value | 自动调用 |
2 | 本类self.attr=value | 自动调用 |
3 | 已定义实例属性attr,实例名.attr=value,超类和本类 | 自动调用 |
4 | 已定义类属性attr,实例名.attr=value,超类和本类 | 自动调用 |
5 | 未定义属性attr,实例名.attr=value | 自动调用 |
6 | 已定义实例属性attr,类名.attr=value,超类和本类 | 不调用 |
7 | 已定义类属性attr,类名.attr=value,超类和本类 | 不调用 |
8 | 未定义属性attr,类名.attr=value,超类和本类 | 不调用 |
示例
>>> class MySuper:
x=1
def __init__(self,addr):
self.addr=addr
self.tel=110
>>> class MySet(MySuper):
day=30
def __init__(self):
self.url='www.tyxt.work'
super().__init__('深圳')
# 全部实例属性的赋值运算,自动调用 __setattr__
# 包括超类属性的赋值运算
# 包括原属性修改和新属性设置的赋值运算
# 不包括类属性的赋值运算
# 实例属性赋值形式:self.attr=value,实例名.attr=value
def __setattr__(self,attr,value):
print('__setattr__ 拦截实例属性的赋值运算,包括超类实例属性',attr)
# 超类和本类的self.attr=value赋值运算,自动调用 __setattr__
# 类原属性赋值(x=1和day=30)运算,不调用 __setattr__
>>> ms=MySet()
__setattr__ 拦截实例属性的赋值运算,包括超类实例属性 url
__setattr__ 拦截实例属性的赋值运算,包括超类实例属性 addr
__setattr__ 拦截实例属性的赋值运算,包括超类实例属性 tel
# 实例名.attr=value,原实例属性赋值运算,自动调用 __setattr__
>>> ms.tel=120
__setattr__ 拦截实例属性的赋值运算,包括超类实例属性 tel
>>> ms.url='tyxt.work'
__setattr__ 拦截实例属性的赋值运算,包括超类实例属性 url
# 实例名.attr=value,新属性赋值运算,自动调用 __setattr__
>>> ms.age=9555
__setattr__ 拦截实例属性的赋值运算,包括超类实例属性 age
# 实例名.attr=value,原类属性赋值运算,自动调用 __setattr__
>>> ms.x=2;ms.day=31
__setattr__ 拦截实例属性的赋值运算,包括超类实例属性 x
__setattr__ 拦截实例属性的赋值运算,包括超类实例属性 day
# 类新属性赋值运算,不调用 __setattr__
>>> MySuper.y=2
>>> MySet.month=12
描述
python的__delattr__()方法,del 实例名.属性,删除类属性和实例属性、未定义的属性,都会自动调用 delattr方法。
实例可访问类属性和实例属性,所以,包括类属性和实例属性的删除操作。
类名不可访问实例属性,所以,通过类名操作实例属性报错。
未定义属性或已定义类属性或已定义实例属性为attr,del 实例名.attr,自动调用delattr。
NO | 删除操作 | 是否调用delattr |
---|---|---|
1 | 已定义实例属性attr,del 实例名.attr | 自动调用 |
2 | 已定义类属性attr,del 实例名.attr | 自动调用 |
3 | 未定义属性attr,del 实例名.attr | 自动调用 |
4 | 已定义实例属性attr,del 类名.attr | 不调用,报错 AttributeError |
5 | 已定义类属性attr,del 类名.attr | 不调用 |
6 | 未定义属性attr,del 类名.attr | 不调用,报错 AttributeError |
示例
>>> class MyDel:
day=30
def __init__(self):
self.url='www.tyxt.work'
# del 实例名.属性,自动调用 __delattr__
def __delattr__(self,attr):
print('__delattr__ 拦截 del 实例名.属性 运算',attr)
>>> md=MyDel()
# del 实例名.类属性,自动调用 __delattr__
>>> del md.day
__delattr__ 拦截 del 实例名.属性 运算 day
# del 实例名.实例属性,自动调用 __delattr__
>>> del md.url
__delattr__ 拦截 del 实例名.属性 运算 url
# del 类名.类属性,不调用 __delattr__
>>> del MyDel.day
# del 类名.实例属性,不调用 __delattr__ , 报错
>>> del MyDel.url
Traceback (most recent call last):
File "<pyshell#105>", line 1, in <module>
del MyDel.url
AttributeError: url
# del 实例名.attr ,attr 为不存在的属性 , 自动调用 __delattr__
>>> del md.x
__delattr__ 拦截 del 实例名.属性 运算 x
描述
同时定义__getattr__()和__getattribute__()两个方法,未定义属性attr,实例名.attr,只调用getattribute方法,不调用getattr方法。
示例
>>> class MyGet:
day=30
def __init__(self):
self.url='www.tyxt.work'
# 未定义的属性进行点号运算,自动调用 __getattr__
def __getattr__(self,attr):
print('__getattr__拦截点号运算')
# 全部属性的点号运算,自动调用 __getattribute__
def __getattribute__(self,attr):
print('__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性',attr)
>>> mg=MyGet()
# 已定义类属性 day , 实例名.day , 自动调用 __getattribute__
>>> mg.day
__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性 day
# 已定义实例属性 url , 实例名.url , 自动调用 __getattribute__
>>> mg.url
__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性 url
# 未定义属性 x , 实例名.x , 自动调用 __getattribute__
>>> mg.x
__getattribute__ 拦截全部属性的点号运算,包括已定义和未定义的属性 x