图 | 《借东西的小人阿莉埃蒂》剧照

起步

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 为前缀的方法都是获取对象内部数据的钩子,名称不一样,用途也存在较大的差异,只有在实践中理解它们,才能真正掌握它们的用法。

参考

https://docs.python.org/3/reference/datamodel.html#object.__getattribute__

python访问属性的格式_Python 中几种属性访问的区别相关推荐

  1. python属性和方法的区别_Python中几种属性访问的区别与用法详解

    起步 在Python中,对于一个对象的属性访问,我们一般采用的是点(.)属性运算符进行操作.例如,有一个类实例对象foo,它有一个name属性,那便可以使用foo.name对此属性进行访问.一般而言, ...

  2. python中属于私有属性的是_Python中的实例属性和私有属性

    相关知识点 实例属性 实例属性和类属性的区别在于实例属性定义在类的__init__()魔法方法中,而类属性定义在类下: 1 classC:2 b = 1 #类属性 3 4 def __init__(s ...

  3. python私有属性怎么定义_Python中定义私有属性的方法是()。

    [判断题]请假条带有请求的性质,所以一般来说篇幅要尽量长一些,以示郑重;更多要用煽情性语句,以打动对方.( ) [单选题]关于类和对象的关系,下列描述正确的是(). [选择]Трудоспособны ...

  4. python属性和方法的区别_Python中几种属性访问的区别

    起步 python的提供一系列和属性访问有关的特殊方法:__get__, __getattr__, __getattribute__, __getitem__ .本文阐述它们的区别和用法. 属性的访问 ...

  5. python检查输入字符串格式_Python中的字符串格式检查

    在准备AS级计算机科学考试时,我在预发布材料中遇到了一个问题: 提示用户输入用户ID,并检查ID的格式是否与预定义的格式规则对应,并相应地输出. 格式(按顺序):一个大写字母 两个小写字母 三个数字字 ...

  6. python if else 嵌套格式_python中if嵌套命令实例讲解

    一.嵌套命令计算机执行的顺序 缩进相同的命令处于同一个等级,第一步,计算机就要按顺序一条一条地执行命令. 1.先给score赋值: 2.因为if和else是只能留一个的互斥关系,if和else下的代码 ...

  7. [转载] python不允许使用关键字_Python中关键字global与nonlocal的区别

    参考链接: Python全局关键字 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/xCyansun/article/details/79672634 ...

  8. python sys模块详解_python中os和sys模块的区别与常用方法总结

    {"moduleinfo":{"card_count":[{"count_phone":1,"count":1}],&q ...

  9. python新式类c3算法_python中的MRO和C3算法

    一. 经典类和新式类 1.python多继承 在继承关系中,python子类自动用友父类中除了私有属性外的其他所有内容.python支持多继承.一个类可以拥有多个父类 2.python2和python ...

最新文章

  1. 2018-2020年Gartner战略科技发展趋势一览!
  2. 11月21日spring mvc的表单校验培训日记
  3. 将excel的数据导入到mysql数据表
  4. 可变分区存储管理实验报告总结_操作系统第5次实验报告:内存管理
  5. PHP之Session与Cookie:存放 安全 应用场景 过期设定 依赖关系
  6. 神探tcpdump第三招
  7. (SPFA+最短路变形+回路对起点的影响)Arbitrage
  8. latex 插图解释_仅使用一些插图和视频即可解释Big O符号
  9. 合并有序数组java
  10. 杭电1411 校庆神秘建筑
  11. Nacos 配置中心原理分Nacos 配置中心原理分析析
  12. 小米wifi驱动 linux驱动,Centos7-驱动小米WIFI做AP
  13. 2019最新好听DJ舞曲精选(51-70)【WAV/百度】
  14. 安装mysql staring server 失败 已经成功决解。
  15. 流放者柯南自建服务器 linux,流放者柯南自建服务器教程一览服务器搭建方法介绍...
  16. 布尔代数中表达式的展开及因式分解的技巧
  17. B2B商业模式以及交易模式
  18. UWB_安信可NodeMCU-BU01的使用
  19. 【x86架构】x86平台CPU的历史
  20. 相机标定与矫正(总结)

热门文章

  1. JAVA:实现Graphs图表算法(附完整源码)
  2. 利用魔兽世界战网API收集数据,从而起底同账号角色的新方法
  3. Bankless丨浅析 NFT 游戏设计中的挑战和机会
  4. 用canvas画飞机大战(一步步详解附带源代码,源码和素材上传到csdn,可以免费下载)
  5. 网页制作——学成在线(P129-P146)
  6. (附源码)springboot螺丝加工厂订单管理 毕业设计 010346
  7. JAVA葵 花 宝 典(面试题)
  8. DataGuard之DG 故障切换(switchover和failover)以及利用flashback 进行恢复
  9. Windows10为Oracle开防火墙
  10. class7-字幕提取