• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

Python-中几种属性访问的区别

python 搞java代码 3年前 (2022-06-26) 40次浏览 已收录 0个评论

起步
python的提供一系列和属性拜访无关的非凡办法:__get__, __getattr__, __getattribute__, __getitem__。本文论述它们的区别和用法。

属性的拜访机制
个别状况下,属性拜访的默认行为是从对象的字典中获取,并当获取不到时会沿着肯定的查找链进行查找。例如 a.x 的查找链就是,从 a.__dict__[‘x’] ,而后是 type(a).__dict__[‘x’] ,再通过 type(a) 的基类开始查找。

若查找链都获取不到属性,则抛出 AttributeError 异样。

一、__getattr__ 办法
这个办法是当对象的属性不存在是调用。如果通过失常的机制能找到对象属性的话,不会调用 getattr 办法。

class A:
    a = 1
    def __getattr__(self, item):
        print('__getattr__ call')
        return item

t = A()
print(t.a)
print(t.b)
# output
1
__getattr__ call
b

二、__getattribute__ 办法
这个办法会被无条件调用。不论属性存不存在。如果类中还定义了 getattr ,则不会调用 getattr__()办法,除非在 __getattribute 办法中显示调用__getattr__() 或者抛出了 AttributeError 。

class A:
    a = 1
    def __getattribute__(self, item):
        print('__getattribute__ call')
        raise AttributeError

    def __getattr__(self, item):
        print('__getattr__ call')
        return item

t = A()
print(t.a)
print(t.b)

所以个别状况下,为了保留 getattr 的作用,__getattribute__() 办法中个别返回父类的同名办法:

def __getattribute__(self, item):
    return object.__getattribute__(self, item)

应用基类的办法来获取属性能防止在办法中呈现有限递归的状况。

三、__get__ 办法
这个办法比较简单阐明,它与后面的关系不大。

如果一个类中定义了 __get__(), __set__() 或 __delete__() 中的任何办法。则这个类的对象称为描述符。

class Descri(object):
    def __get__(self, obj, type=None):
        print("call get")

    def __set__(self, obj, value):
        print("call set")

class A(object):
    x = Descri()

a = A()
a.__dict__['x'] = 1  # 不会调用 __get__
a.x                  # 调用 __get__

如果查找的属性是在描述符对象中,则这个描述符会笼罩上文说的属性拜访机制,体现在查找链的不同,而这个行文也会因为调用的不同而稍有不一样:

  • 如果调用是对象实例(题目中的调用形式),a.x 则转换为调用:。type(a).__dict__[‘x’].__get__(a, type(a))
  • 如果调用的是类属性, A.x 则转换为:A.__dict__[‘x’].__get__(None, A)
  • 其余状况见文末参考资料的文档

四、__getitem__ 办法

这个调用也属于无条件调用,这点与 getattribute 统一。区别在于 getitem 让类实例容许 [] 运算,能够这样了解:

  • __getattribute__实用于所有.运算符;
  • __getitem__实用于所有 [] 运算符。
class A(object):
    a = 1

    def __getitem__(self, item):
        print('__getitem__ call')
        return item

t = A()
print(t['a'])
print(t['b'])

如果仅仅想要对象可能通过 [] 获取对象属性能够简略的:

def __getitem(self, item):
    return object.__getattribute__(self, item)

总结
当这几个办法同时呈现可能就会扰乱你了。我在网上看到一份示例还不错,略微改了下:

class C(object):
    a = 'abc'

    def __getattribute__(self, *args, **kwargs):
        print("__getattribute__() is called")
        return object.__getattribute__(self, *args, **kwargs)

    #        return "haha"
    def __getattr__(self, name):
        print("__getattr__() is called ")
        return name + " from getattr"

    def __get__(self, instance, owner):
        print("__get__() is called", instance, owner)
        return self

    def __getitem__(self, item):
        print('__getitem__ call')
        return object.__getattribute__(self, item)

    def foo(self, x):
        print(x)

class C2(object):
    d = C()

if __name__ == '__main__':
    c = C()
    c2 = C2()
    print(c.a)
    print(c.zzzzzzzz)
    c2.d
    print(c2.d.a)
    print(c['a'])

能够联合输入缓缓了解,这里还没波及继承关系呢。总之,每个以 __get 为前缀的办法都是获取对象外部数据的钩子,名称不一样,用处也存在较大的差别,只有在实践中了解它们,能力真正把握它们的用法。

以上就是本次分享的所有内容,想要理解更多 python 常识欢送返回公众号:Python 编程学习圈 ,发送 “J” 即可收费获取,每日干货分享


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:Python-中几种属性访问的区别

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址