python的getattr和getattribute调用

1 python的getattr和getattribute调用

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。

都是通过实例名操作属性时自动调用对应方法,通过类名操作属性不触发对应方法的调用。

1.1 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 "", line 1, in <module>
    mg.age
  File "", line 11, in __getattr__
    raise AttributeError(attr)
AttributeError: age
# 已定义的类属性,类名.属性,不调用 __getattr__
>>> MyGet.day
30
# 未定义的属性,类名.属性,不调用 __getattr__ ,报错
>>> MyGet.month
Traceback (most recent call last):
  File "", line 1, in <module>
    MyGet.month
AttributeError: type object 'MyGet' has no attribute 'month'
# 已定义的实例属性,类名.实例属性,不调用 __getattr__ ,报错
>>> MyGet.url
Traceback (most recent call last):
  File "", line 1, in <module>
    MyGet.url
AttributeError: type object 'MyGet' has no attribute 'url'

1.2 getattribute

描述

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 "", 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 "", line 1, in <module>
    MyGet.name
AttributeError: type object 'MyGet' has no attribute 'name'

1.3 setattr

描述

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

1.4 delattr

描述

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 "", line 1, in <module>
    del MyDel.url
AttributeError: url
# del 实例名.attr ,attr 为不存在的属性 , 自动调用 __delattr__
>>> del md.x
__delattr__ 拦截 del 实例名.属性 运算 x

1.5 getattr和getattribute同时存在

描述

同时定义__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

你可能感兴趣的:(python,python)