python类的属性有哪几种?如何访问它们?

 我来答
沉稳又淡泊丶小猫v
2020-01-10 · TA获得超过3564个赞
知道小有建树答主
回答量:1367
采纳率:80%
帮助的人:124万
展开全部

属性的访问机制

一般情况下,属性访问的默认行为是从对象的字典中获取,并当获取不到时会沿着一定的查找链进行查找。例如 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 为前缀的方法都是获取对象内部数据的钩子,名称不一样,用途也存在较大的差异,只有在实践中理解它们,才能真正掌握它们的用法。
星座有味道
2020-01-10 · 星座,揭示性格与命运的神秘之钥。
星座有味道
采纳数:136 获赞数:4229

向TA提问 私信TA
展开全部
解,这里还没涉及继承关系呢。总之,每个以 __ get 为前缀的方法都是获取对象内部数据的钩子,名称不一样,用途也存在较大的差异,只有在实践中理解它们,才能真正掌握它们的用法。
已赞过 已踩过<
你对这个回答的评价是?
评论 收起
推荐律师服务: 若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询

为你推荐:

下载百度知道APP,抢鲜体验
使用百度知道APP,立即抢鲜体验。你的手机镜头里或许有别人想知道的答案。
扫描二维码下载
×

类别

我们会通过消息、邮箱等方式尽快将举报结果通知您。

说明

0/200

提交
取消

辅 助

模 式