重载__getattr__方法对类及其实例未定义的属性有效。如果访问的属性存在,就不会调用__getattr__方法。这个属性的存在,包括类属性和实例属性

classClassA:

x= 'a'

def __init__(self):

self.y= 'b'

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

if __name__ == '__main__':

a=ClassA()print(a.x)#输出结果 a

#使用实例直接访问实例存在的属性时,不会调用__getattr__方法

print(a.y) #输出结果 b

#使用实例直接访问实例不存在的属性时,会调用__getattr__方法

print(a.z) #输出结果 __getattr__

__getattribute__仅在新式类中可用,重载__getattrbute__方法对类实例的每个属性访问都有效,无论属性存不存在都会先调用__getattribute__方法

classClassA:

x= 'a'

def __init__(self):

self.y= 'b'

def __getattribute__(self, item):return '__getattribute__'

if __name__ == '__main__':

a=ClassA()#使用实例直接访问存在的类属性时,会调用__getattribute__方法

print(a.x) #输出结果 __getattribute__

#使用实例直接访问实例存在的实例属性时,会调用__getattribute__方法

print(a.y) #输出结果 __getattribute__

#使用实例直接访问实例不存在的实例属性时,也会调用__getattribute__方法

print(a.z) #输出结果 __getattribute__

当同时定义__getattribute__和__getattr__时,__getattr__方法不会再被调用,除非显示调用__getattr__方法或引发AttributeError异常。

classClassA:def __getattr__(self, item):print('__getattr__')def __getattribute__(self, item):print('__getatttribute__')if __name__ == '__main__':

a=ClassA()

a.x

运行结果__getatttribute__

由于__getattr__只针对未定义属性的调用,所以它可以在自己的代码中自由地获取其他属性,

而__getattribute__针对所有的属性运行,因此要十分注意避免在访问其他属性时,再次调用自身的递归循环。死循环!!

当在__getattribute__代码块中,再次执行属性的获取操作时,会再次触发__getattribute__方法的调用,代码将会陷入无限递归,直到Python递归深度限制(重载__setter__  __setattr__方法也会有这个问题)。

示例代码(无限递归):

classClassA:

x= 'a'

def __getattribute__(self, item):print('__getattribute__')return self.item #再次出现属性的获取操作,会再次触发__getattribute__的调用

#相当于return self.__getattribute__(item)

if __name__ == '__main__':

a=ClassA()

a.x

运行结果,达到最大递归深度

ecursionError: maximum recursion depth exceeded

也没办法通过从__dict__取值的方式来避免无限递归(重写__setattr__可以通过__dict__取值的方式来避免无限递归)

classClassA:

x= 'a'

def __getattribute__(self, name):return self.__dict__[name] #__dict__魔法方法可以查看对象的属性,返回一个字典,键代表属性名 ,这样再次出现属性获取的操作,会再次触发__getattribute__if __name__ == '__main__':

a=ClassA()

a.x#无限递归

为了避免无限递归,应该把获取属性的方法 __getattribute__指向一个更高的超类,例如object(因为__getattribute__只在新式类中可用,而新式类所有的类都显式或隐式地继承自object,所以对于新式类来说,object是所有新式类的超类)。利用super()方法

classClassA:

x= 'a'   #类属性

def __getattribute__(self, item):print('__getattribute__')return super().__getattribute__(self, item)if __name__ == '__main__':

a=ClassA()print(a.x) #输出__getattribute__

a

调用__getattr__详细过程如下:

obj.attribute

首先会在对象的实例属性中寻找,找不到执行第二步

来到对象所在的类中查找类属性,如果还找不到执行第三步

来到对象的继承链上寻找,如果还找不到执行第四步

调用obj.__getattr__方法,如果用户没有定义或者还是找不到,抛出AttributeError异常,属性查找失败

classMyClass:def __init__(self, x):

self.x=x>>> obj = MyClass(1)>>>obj.y

AttributeError:'MyClass' object has no attribute 'a'

如上代码,没有定义__getattr__魔法方法,又找不到属性,就会抛出异常

调用__getattrIbute__方法

当我们调用对象的属性时,首先会调用__getattribute__魔法方法。无论对象存不存在;当__getattribute__查找失败,就会去调用__getattr__方法。

obj.x

obj.__getattribute__(x)

这两个代码其实是等价的

使用__getattribute__魔法方法时,要返回父类的方法,(super函数)不然很难写对!!会导致无限递归!

另外,内置的bif   getattr和hasattr也会触发这个魔法方法__getattribute__!!

其他细节需要注意

1.  _getattribute__的查找顺序

classMyClass:

x= 999         #类属性x

def __init__(self, x):   #形参x

self.x=x       #实例属性xdef __getattribute__(self, item):print('正在获取属性{}'.format(item))return super(MyClass, self).__getattribute__(item)

>>> obj = MyClass(2)

>>> print(obj.x)

正在获取属性x

2

>>> del obj.x     #删除了实例属性x

>>> print(obj.x)   #此时访问的是类属性

正在获取属性

999

上面代码中,定义了一个类属性x和一个实例属性x,这两个属性同名,根据Python语法规则,当对象获取属性x的时候,首先会在实例属性中寻找,如果找不到才回去类属性中查找

这便是__getattribute__的查找顺序。通常该方法在框架中可能会用到,一般情况下无需使用

2.  super 对象没有 __getattr__魔法方法!!

>>> classC:def __getattr__(self, name):print(1)return super().__getattr__(name)def __getattribute__(self, name):print(2)return super().__getattribute__(name)def __setattr__(self, name, value):print(3)

super().__setattr__(name, value)def __delattr__(self, name):print(4)

super().__delattr__(name)>>> c =C()>>>c.x

运行结果:>>> c =C()>>>c.x2

1Traceback (most recent call last):

File"", line 1, in c.x

File"", line 4, in __getattr__

return super().__getattr__(name)

AttributeError:'super' object has no attribute '__getattr__'

分析一下:首先 c.x 会先调用 __getattribute__() 魔法方法,打印 2;然后调用 super().__getattribute__(),找不到属性名 x,因此会紧接着调用 __getattr__() ,于是打印 1;你希望最后以 super().__getattr__() 终了的时候,Python 竟然告诉你 AttributeError,super 对象木有 __getattr__ !

证明:

>>>dir(super)

['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__get__', '__getattribute__',

'__gt__', '__hash__', '__init__', '__le__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',

'__self__', '__self_class__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', '__thisclass__']

(dir() 函数不带参数时,返回当前范围内的变量、方法和定义的类型列表;带参数时,返回参数的属性、方法列表。如果参数包含方法__dir__(),该方法将被调用。如果参数不包含__dir__(),该方法将最大限度地收集参数信息)

3.  初学常犯错误没有“观前顾后”!

例如:编写一个 Counter 类,用于实时检测对象有多少个属性。

classCounter:def __init__(self):

self.counter=0    # 属性赋值,这里会触发 __setattr__ 调用def __setattr__(self, name, value): #self是绑定的对象,name是属性名(name必须是字符串),value是为对象属性赋的值

self.counter+= 1super().__setattr__(name, value) #这时候 self.counter 还没有定义,所以没法 += 1,错误的根源。def __delattr__(self, name):

self.counter-= 1super().__delattr__(name)

>>>c =Counter()

运行结果:

AttributeError: 'Counter' object has no attribute 'counter'

正确代码:

classCounter:def __init__(self):

super().__setattr__('counter', 0)         #调用基类的赋值魔法方法__setattr__(name,value) name必须是字符串!def __setattr__(self, name, value):

super().__setattr__('counter', self.counter + 1)

super().__setattr__(name, value)def __delattr__(self, name):

super().__setattr__('counter', self.counter - 1)

super().__delattr__(name)

另外的

__setattr__(self, name, value)

定义当一个属性被设置时的行为

__delattr__(self, name)

定义当一个属性被删除时的行为

python getattr和getattribute_python中__getattr__和__getattribute__区别相关推荐

  1. python getattr和getattribute_Python的__getattr__和__getattribute__

    __getattr__ __getattr__在当前主流的Python版本中都可用,重载__getattr__方法对类及其实例未定义的属性有效.也就属性是说,如果访问的属性存在,就不会调用__geta ...

  2. python getattr和getattribute_python中__get__、__getattr__、__getattribute__详解

    __get__,__getattr__和__getattribute__(只存在于新式类)都是访问属性的方法,但有一定的区别. object.__getattr__(self, name) 通过实例访 ...

  3. python getattr函数_Python中的getattr()函数详解

    在计算机编程中,自省是指这种能力:检查某些事物以确定它是什么.它知道什么以及它能做什么.自省向程序员提供了极大的灵活性和控制力. 自省(introspection),在计算机编程领域里,是指在运行时来 ...

  4. python getattr函数_python中getattr函数 hasattr函数

    hasattr(object, name) 作用:判断对象object是否包含名为name的特性(hasattr是通过调用getattr(ojbect, name)是否抛出异常来实现的). 示例: & ...

  5. Python教程:json中encode与decode区别

    在Python3中,将对象序列化为JSON对象,即对对象进行json encode编码,使用函数 json.dumps(obj, *, skipkeys=False, ensure_ascii=Tru ...

  6. python大括号用法_Python中各种括号的区别、用途及使用方法

    python语言最常见的括号有三种,分别是:小括号( ).中括号[ ]和大括号也叫做花括号{ }.其作用也各不相同,分别用来代表不同的python基本内置数据类型. 小括号( ):代表tuple元组数 ...

  7. python eval函数_Python中eval与exec区别 | 萧小寒

    摘要 学过JavaScript的人都知道,在JS中有一个函数叫内置函数叫eval.eval函数可计算某个字符串,并执行其中的的JavaScript代码.正是因为这个特性,所以现在很多教材都不推荐使用这 ...

  8. 【7.2】__getattr__、__getattribute__魔法函数

    1 #!/user/bin/env python 2 # -*- coding:utf-8 -*- 3 # __getattr__.__getattribute__ 4 # __getattr__ 就 ...

  9. python getattr和getattribute_getattr与getattribute的区别__

    让我们看看__getattr__和__getattribute__魔术方法的一些简单示例. __getattr__ 每当您请求尚未定义的属性时,Python将调用__getattr__方法.在下面的示 ...

最新文章

  1. 开放一些3D视觉相关职位!
  2. mysql函数快速查找
  3. Xamarin Essentials教程安全存储SecureStorage
  4. 并发队列-无界阻塞优先级队列
  5. RandomForest:随机森林
  6. 【杂谈】从学生到讲师,我如何20天里在有三AI赚3万
  7. 应对程序员面试,你必须知道的8大数据结构
  8. VMware linux 虚拟机(ubuntu18.04) 安装TL-WDN5200H 2.0网卡驱动 完美使用(适用于vmware无法桥接网络使用此方法)
  9. 用Flask开发Web版日历应用
  10. 每日三道前端面试题--vue 第一弹
  11. bt种子文件变成html,bt种子文件是什么?bt种子文件怎么用?
  12. python代码扫描工具_Python脚本实现Web漏洞扫描工具
  13. Myeclipse 10破解run.bat和cracker.jar打不开的问题
  14. 2021秋软工实践第二次结对编程作业
  15. 世界道路协会(PIARC)道路安全手册(RSM)
  16. 如何利用数据挖掘让RTB广告效果倍增?
  17. mac SnailSVN如何拉取多个svn副本
  18. Grandmaster 楼教主回忆录
  19. Oracle中rowid的用法(全面)
  20. 蓝桥杯真题:天干地支

热门文章

  1. SAP Spartacus 自定义 theme 实现思路
  2. 在服务器端渲染完毕的 Angular Component,在客户端还会重新渲染一次吗?
  3. 谈谈 SAP 产品 UI 开发中的组件概念
  4. SAP Fiori OData gateway 和后台 ABAP 系统的双缓存表(cache table)设计
  5. Flex布局里的align-self属性
  6. SAP Spartacus和Table相关的配置结构ResponsiveTableConfiguration
  7. SAP Spartacus cx-table加了cxFocus指令后的测试效果
  8. SAP Spartacus里的登录token处理
  9. github 2FA里的recovery code,一定要好好保存
  10. 关于fixture.debugElement.query(By.css)这个方法的一个疑问