美文网首页
32.2-反射的魔术方法和实例属性搜索顺序

32.2-反射的魔术方法和实例属性搜索顺序

作者: BeautifulSoulpy | 来源:发表于2019-12-31 08:42 被阅读0次

征服畏惧建立自信的最快最确实的方法,就是去做你害怕的事,直到你获得成功的经验!

反射的魔术方法

魔术方法 意义
_getattr_() 当通过搜索实例、实例的类及祖先类查不到属性,就会调用此方法
_setattr_() 通过.访问实例属性,进行增加、修改都要调用它
_delattr_() 当通过实例来删除属性时调用此方法
_getattribute_ (少用) 实例所有的属性调用都从这个方法开始

属性查找顺序:
实例调用_getattribute() --> instance._dict --> instance._class._dict --> 继承的祖先类(直到
object)的_dict_ --> 调用_getattr_()

1. getattr
一个类的属性会按照继承关系找,如果找不到,就会执行 getattr() 方法,如果没有这个方法,就会抛出
AttributeError异常表示找不到属性。

查找属性顺序为:
instance.dict --> instance.class.dict --> 继承的祖先类(直到object)的dict ---找不到--> 调
getattr()

_getattr_跟类无关,只跟实例调用有关
属性不存在的情况下,参数作为item送入 getattr

class B:
    a = 200
    
class A(B):
    z = 100
    def __init__(self,x,y):
        self.x = x
        self.y = y
        
    def __getattr__(self,item):
        print('__getattr',item)  # 
        return 'abc'
        
print(A.z)
A.z = 1000
print('-'*30)

a = A(1,2)
print(a.x)
print(a.y)
print(a.z)

print(getattr(a,'x'))
print('-'*30)
print(a.b)
print('-'*30)
print(getattr(a,'c'))  # 等价于 a.c
#---------------------------------------------------------
100
------------------------------
1
2
1000
1
------------------------------
__getattr b
abc
------------------------------
__getattr c
abc

2. setattr

如果没有setattr方法,属性初始化init的赋值是成功的;
只要属性是赋值的方式,setattr它就参与;属性必须添加进setattr

实例通过.点号设置属性,例如self.x = x,就会调用 setattr() ,属性要加到实例的 dict 中,就需要自己
完成。

class B:
    b = 200
    
class A(B):
    z = 100
    def __init__(self,x,y):
        self.x = x
        setattr(self,'y',y)
        self.__dict__['a'] = 5
        
    def __getattr__(self,item):        # 缺省属性;
        print('__getattr~~~~~~~~',item)  # 
        return self.d[item]
    
    def __setattr__(self,key,value):   # 添加属性; 只要实例是赋值的方式,它就参与;
        print(key)
        print(value)
        self.__dict__[key] = value
a = A(4,5)
print(a.__dict__)
print(A.__dict__)

print(a.x)
print(a.a)
# -------------------------------------------------------------------
x                      
4
y
5
{'x': 4, 'y': 5, 'a': 5}       # setattr 方法;
{'__module__': '__main__', 'z': 100, '__init__': <function A.__init__ at 0x000001C624D82950>, '__getattr__': <function A.__getattr__ at 0x000001C624D82AE8>, '__setattr__': <function A.__setattr__ at 0x000001C624D82A60>, '__doc__': None}
4
5

3. delattr
class A(B):
    z = 100
    def __init__(self,x,y):
        self.x = x
        setattr(self,'y',y)
        self.__dict__['a'] = 5
        
    def __getattr__(self,item):        # 缺省属性;
        print('__getattr~~~~~~~~',item)  # 
        return self.d[item]
    
    def __setattr__(self,key,value):   # 添加属性; 只要实例是赋值的方式,它就参与;
        print(key)
        print(value)
        self.__dict__[key] = value
        
    def __delattr__(self,item):
        print('can not del {}'.format(item))
a = A(4,5)
print(a.__dict__)
print(A.__dict__)
print(a.x)
print(a.a)

#del a.__dict__['a']
del a.a
print(a.__dict__)
#-------------------------------------------------------------------------
x
4
y
5
{'x': 4, 'y': 5, 'a': 5}
{'__module__': '__main__', 'z': 100, '__init__': <function A.__init__ at 0x000001C624F6BB70>, '__getattr__': <function A.__getattr__ at 0x000001C624F6BD08>, '__setattr__': <function A.__setattr__ at 0x000001C623D96BF8>, '__delattr__': <function A.__delattr__ at 0x000001C625216048>, '__doc__': None}
4
5
can not del a
{'x': 4, 'y': 5, 'a': 5}
4. getattribute 第一关 拦截属性的搜索

实例的所有的属性访问,第一个都会调用 _getattribute_ 方法,它阻止了属性的查找,该方法应该返回(计算后的)值或者抛出一个AttributeError异常。

  1. 它的return值将作为属性查找的结果。
  2. 如果抛出AttributeError异常,则会直接调用 _getattr_ 方法,因为表示属性没有找到
class B:
    b = 200

class A(B):
    z = 100
    def __init__(self,x,y):
        self.x = x
        self.y = y
        
    def __getattribute__(self,item):
        print(item,'----------------------------')
        return object.__getattribute__(self,item)

a = A(4,5)

print(a.__dict__)
print('-'*30)
print(a.x)
#--------------------------------------------------------
__dict__ ----------------------------
{'x': 4, 'y': 5}
------------------------------
x ----------------------------
4

_getattribute_ 方法中为了避免在该方法中无限的递归,它的实现应该永远调用基类的同名方法以访问需要的
任何属性,例如 object._getattribute(self, name) 。
注意,除非你明确地知道 _getattribute
方法用来做什么,否则不要使用它。

相关文章

  • 32.2-反射的魔术方法和实例属性搜索顺序

    征服畏惧建立自信的最快最确实的方法,就是去做你害怕的事,直到你获得成功的经验! 反射的魔术方法 魔术方法意义_ge...

  • python 理解类变量与实例变量

    实例的属性存储在实例的dict中。 类属性和方法存储在类的dict中。 查找属性的顺序:特性->实例的dict->...

  • JavaScript中原型的简单语法

    简单的原型写法 原型中的方法是可以互相访问的 实例对象使用的属性和方法层层的搜索 实例对象使用的属性或者方法,先在...

  • Python高级知识点学习(三)

    mro算法 类属性和实例属性的查找顺序 何为类属性:定义在类内部的的一些变量或者方法,都统称为类属性 何为实例属性...

  • 反射

    实体类 反射获取实例 反射获取方法 反射获取属性 补充 testBean.getClasses()返回调用类的所有...

  • 反射泛型容器

    一、 反射 1.1> 什么是反射 Class是反射的核心。在运行期进行实例的生成。 Class文件 属性 方法 (...

  • 26、反射(二)

    反射除了获取属性,也可以获取方法,调用方法。 获取实例方法:Method method = clazz.getMe...

  • 属性动画与补间动画的性能差异

    属性动画操作的是对象的实例属性,例如translationX,然后反射调用set,get方法,多个属性动画同时执行...

  • 原型继承

    一、原型判断方法*术语解释:成员=属性+方法实例成员:实例属性和实例方法原型成员:原型对象属性和原型对象方法1、原...

  • 类属性和实例属性的查找顺序

    类属性:定义在类内部的变量和方法,统称为属性。 查找顺序 - MRO 查找 Python 的属性搜索算法,在 Py...

网友评论

      本文标题:32.2-反射的魔术方法和实例属性搜索顺序

      本文链接:https://www.haomeiwen.com/subject/pzqmoctx.html