python __getattr__ & __setattr__

python中属性查找流程

  1. 对于my_obj.x表达式,首先检查my_obj实例中有没有名为x的实例属性
  2. 如果上一步没找到,检查对应的类中有没有名为x的类属性,因为类属性可以作为实例属性的默认值
  3. 如果上一步没找到,沿着继承树继续查找......
  4. 如果仍找不到,则会调用__getattr__方法。

__getattr__方法

  • __getattr__简单实现
    • self._components是实例属性,现在假设其是一个列表 [0, 1, 2, 3]
    • 如果我们用my_obj.x来调用,在python属性查找流程中,前三步找不到属性x,那么调用__getattr__方法,根据方法中的逻辑,可以返回列表中的第一个元素 0
    • __getattr__方法有两个参数,第一个是self,即实例本身的引用,第二个是属性名的字符串表示形式。
      shortcut_names = 'xyzt'
    
      def __getattr__(self, name):
        cls = type(self) # 获取当前类名Vector
     
        if len(name) == 1: # 属性名只有一个字符,可能是'xyzt'中的某一个
            pos = cls.shortcut_names.find(name) # 查找是否是'xyzt'中的某一个
            if 0 <= pos < len(self._components): # 定位位置
                return self._components[pos]
        msg = '{.__name__!r} object has no attribute {!r}' # 失败则抛出属性错误
        raise AttributeError(msg.format(cls, name))
    
    

__setattr__方法

  • 只使用__getattr__会出现问题,如下:

    1. 通过__getattr__,属性x可以引用到0.0
    2. 更改v.x的值,此时并没有更改原列表中的值,而是创建了一个新的实例属性x
  • 为了在更改__getattr__设置的属性名的时候更改原数据,需要在__setattr__方法里设置具体的行为。

posted @ 2022-03-14 11:48  肖肖凯  阅读(82)  评论(0)    收藏  举报