python 类属性的访问

首先我们来看这段代码

class CLS(object):
    func = 'name'
    def __init__(self, out=None):
        self._out = out
        self.func = '23333'
    def func(self):
        return ('asdasd')
    def __getattr__(self, arg):
        print ('~!@#$访问失败',arg,arg)

a = CLS()
print ('##',a.__dict__)
a.ff = '111111'
print ('@@',a.__dict__)
print ('!!',a.func,CLS.func)
print ('_+_+',a.adsasdasd)

run一下后的结果是这样的

## {'_out': None, 'func': '23333'}
@@ {'_out': None, 'func': '23333', 'ff': '111111'}
!! 23333 0x000002350DD82378>
~!@#$访问失败 adsasdasd adsasdasd
_+_+ None
[Finished in 0.4s]

这里访问到的是 init 中的属性而不是 func 为什么会这样呢?我们来看文档如何说

一个类实例是通过调用一个类对象来创建的(参见上文)。一个类实例有一个实现为字典的命名空间,它是第一个在其中搜索属性引用的地方。如果在那里找不到属性,并且实例的类具有该名称的属性,则继续搜索类属性。如果找到的是一个用户定义的函数对象的类属性,它将被转换为self属性为实例的实例方法对象。静态方法和类方法对象也被转换; 见上面的“类”。有关通过实例获取的类的属性可能与实际存储在类中的对象有所不同的另一种方式,请参见实现描述符一节dict。如果没有找到类属性,并且该对象的类有一个getattr()方法,那么将调用该方法来满足查找。

很清晰了,类的属性都放在这个 __dict__ 这个dict里,当一个类的实例的实例访问属性的时候先搜索这个 dict 因为搜索到了,所以不会在去搜索类属性。也能看到 类定义的 func 并不在这个 dict 中。


做一个备忘

object.getattr(self, name)¶
Called when the default attribute access fails with an AttributeError (either getattribute() raises an AttributeError because name is not an instance attribute or an attribute in the class tree for self; or get() of a name property raises AttributeError). This method should either return the (computed) attribute value or raise an AttributeError exception.

当访问attr失败的时候 raise attr error 的时候调用,inst 没有这个 attr 或 cls tree 没有 这个attr ,根据上面的我们知道,是先搜索cls tree 然后再看 inst 的attr的。
使用访问不存在的变量是,不会经过getattr函数。而descriptor不存在此问题,只是把instance标识为none而已。


object.getattribute(self, name)
Called unconditionally to implement attribute accesses for instances of the class. If the class also defines getattr(), the latter will not be called unless getattribute() either calls it explicitly or raises an AttributeError. This method should return the (computed) attribute value or raise an AttributeError exception. In order to avoid infinite recursion in this method, its implementation should always call the base class method with the same name to access any attributes it needs, for example, object.getattribute(self, name).

# 通过 inst 访问 attr?拿 cls 的attr如何访问?在cls定义下面 init 前面定义也不行,待续。
能看出通过 dot 的 attr 访问实际是通过这个func来做的,latter 是后者 –> __getattr__ ,后者是不会调用的除非 getattribute显示调用它或引发一个error。就是说无论怎么样只要通过dot的都会调用一边getattribute func。


class C(object):
    a = 'abc'
    def __getattribute__(self, *args, **kwargs):
        print("__getattribute__() is called")
        if args[0] == 'a':
            return object.__getattribute__(self, *args, **kwargs)
        else:
            print ('调用函数foo()')
            return object.__getattribute__(self,'foo')()
    def foo(self):
        return "hello"
c = C()
print (c.foo)
print (c.a)

https://blog.csdn.net/l363244944/article/details/51509575 引用自这里,非常nb的代码简洁明了,可以配合上面的描述看。

https://www.cnblogs.com/saolv/p/6890645.html 这个有关于 get() 的方面,待看~


a.x时发生了什么?属性的lookup顺序如下:

  • 如果重载了getattribute,则调用.
  • a.dict, 实例中是不允许有descriptor的,所以不会遇到descriptor
  • A.dict, 也即a.class.dict .如果遇到了descriptor,优先调用descriptor.
  • 沿着继承链搜索父类.搜索a.class.bases中的所有dict. 如果有多重继承且是菱形继承的情况,按MRO(Method Resolution Order)顺序搜索.

如果以上都搜不到,则抛AttributeError异常.
上面这段不确定,因为非文档上的东西,待续。


Finis.

你可能感兴趣的:(python)