我的编程空间,编程开发者的网络收藏夹
学习永远不晚

python-__getattr__ 和

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

python-__getattr__ 和

python3完全使用了新式类,废弃了旧式类,getattribute作为新式类的一个特性有非常奇妙的作用。查看一些博客和文章后,发现想要彻底理解getattr和getattribute的区别,实际上需要理解python中属性的查找顺序、描述器(descriptor)、__get__、__set__、__dict__等知识。

首先需要指出,如果一个类只定义了__get__方法则称之为non-data descriptor(非资料描述器),如果这个类将__get__和 __set__都定义了,则称之为data descriptor(资料描述器),具体可见我的另一篇博客,方便理解。下面介绍实例属性的查找顺序。假设 t = T(),t.at的查找顺序如下:

1、如果是python自动产生的属性,返回,否则进行第2步

2、如果‘at’出现在了T或者其父类和祖先类__dict__中(即‘at’是一个类属性,并非只属于t的实例属性),并且at是一个data descriptor,则优先调用其__get__方法。不是data descriptor或者没有该属性则进行第2步。

3、查找实例t的__dict__中是否有at属性,有则返回,没有则到第3步。

4、查找t的父类和祖先类的__dict__中是否有at属性,如果没有则执行第4步,如果有则执行如下步骤:

​ 4.1 at是一个non-data descriptor,调用其__get__方法,不是则执行3.2

​ 4.2 返回__dict__['at']

5、如果实例t的父类中有__getattr__方法,则调用该方法,没有则抛出AttributeError。

注意每次类或实例调用属性时getattribute会被无条件首先调用。下方代码略长,耐心查看。

class Descriptor:  # 定义描述器的类
    def __get__(self, instance, owner):  # get方法用于返回实例的a属性
        print('3 get called,', 'instance is', instance, ',owner is', owner)
        return instance.a

    def __set__(self, instance, value):  # set方法用于修改实例的a属性
        print('4 set called,', 'instance is', instance, ',value is', value)
        instance.a = value**2

    def __getattribute__(self, item): 
        print('5 Des getattribute called, item is %s' % item)

class NotDescriptor: # 定义non-data descriptor
    def __get__(self, instance, owner):
        print('6 get called,', 'instance is', instance, ',owner is', owner)
        return instance.a - 100

class T:
    desc = Descriptor()  # 类属性,一个资料描述器 data descriptor
    Not_Desc = NotDescriptor()  # 类属性,一个非资料描述器 non-data descriptor    
    def __init__(self):
        self.a = 123
        self.not_desc = 'instance not_desc'
        
    def func(self):
        return 'T func'

    def __getattribute__(self, item):
        print('1 getattribute called, item is ', item)
        return object.__getattribute__(self, item)

    def __getattr__(self, item):
        print('2 getattr called, item is', item)
        raise AttributeError('NO such attr %s' % item)

以下的测试均使用上方的代码,每次的输出操作都重置过,以避免混淆。

1 getattribute called, item is  func
T func  # 实例的函数
1 getattribute called, item is  a
123  # 实例的属性
==================================================
4 set called, instance is <__main__.T object at 0x000001E55B630240> ,value is 2
# set方法前不调用getattribute。instance是拥有该描述器类的一个实例。value是要设置的值。
==================================================
1 getattribute called, item is  desc
3 get called, instance is <__main__.T object at 0x000001E55B630240> ,owner is <class '__main__.T'>
# get方法前还是优先调用getattribute,instance是拥有该描述器对象的一个实例。owner是拥有者本身
1 getattribute called, item is  a
t.a = 4 # 2**2 = 4

可见调用实例的属性和方法时都会无条件首先调用getattrtibute方法,而set方法则不会调用。另外代码利用描述器的get和set方法,实际上已经实现了类似于@property的使用(当然,property装饰器其实就是基于描述器实现的,对property装饰器不了解的话可以查看我的另一篇博客)。

下面继续使用上方代码验证__getattr__、非描述器的执行顺序。

t = T()
print(t.not_desc)
--------结果如下------
1 getattribute called, item is not_desc
instance not_desc

回想前面提到的属性查找顺序,‘not_desc’在类的__dict__被找到了,但不是descriptor,所以执行第2步,在实例的__dict__中发现该属性,返回。

t = T()
print(t.Not_Desc)
--------结果如下------
1 getattribute called, item is  Not_Desc
6 get called, instance is <__main__.T object at 0x0000017F70A006A0> ,owner is <class '__main__.T'>
# 这里是NonDataDescriptor中的get方法
1 getattribute called, item is  a
23  # a的初始值为123 由get方法返回的是123-100=23

根据我们之前提到的顺序,‘Not_Desc’属性在类的__dict__中找到但不是data descriptor,又没有在实例的dict中找到,所以进行到了4.1步骤,发现它是一个non-data descriptor,然后就执行了其中的get方法。

t = T()
print(t.bbbbbb)  # T类中没有定义该属性
------结果如下----------
1 getattribute called, item is bbbbbb
2 getattr called, item is bbbbbb
Traceback (most recent call last):
  File "C:/省略/.py", line 40, in <module>
    print(t.bbbbbb)
  File "C:C:/省略/.py.py", line 36, in __getattr__
    raise AttributeError('NO such attr %s' % item)
AttributeError: NO such attr bbbbbb

可见,当我们访问一个没有被定义的属性时,仍然会首先调用getattribute,根据属性查找原则,在实例和类中都没有找到这个属性,于是执行getattr。到这里我们也就了解到了python中属性的查找顺序、getattribute和getattr的执行顺序。

回过头来,getattribute会在调用类和实例的属性时无条件调用,所以可以用于权限鉴别、日志记录等操作;而getattr会在属性没有被找到的时候执行,因此可以用来做一些兜底的操作,可见这篇博客

另外注意重写getattribute时的循环陷阱,返回语句要写成return object.__getattribute__(),不要使用return self.xxx,否则self相当于又指向了自己,而getattribute会无条件调用,从而进入无限循环。


最后的我们查看类和实例的__dict__属性,看看又什么不同

t = T()
print(t.__dict__)
print(T.__dict__)
------结果如下--------
1 getattribute called, item is __dict__
{'a': 123, 'not_desc': 'instance not_desc'}
{'__module__': '__main__', 'desc': <__main__.Descriptor object at 0x0000021FD20C0128>, 'Not_Desc': <__main__.NotDescriptor object at 0x0000021FD20C0160>, '__init__': <function T.__init__ at 0x0000021FD20B59D8>, 'func': <function T.func at 0x0000021FD20B5A60>, '__getattribute__': <function T.__getattribute__ at 0x0000021FD20B5AE8>, '__getattr__': <function T.__getattr__ at 0x0000021FD20B5B70>, '__dict__': <attribute '__dict__' of 'T' objects>, '__weakref__': <attribute '__weakref__' of 'T' objects>, '__doc__': None}

可见实例t只有init中定义的属性,而类T中才有描述器和非描述器等属性。

参考:

https://blog.csdn.net/yitiaodashu/article/details/78974596

https://www.cnblogs.com/Vito2008/p/5280216.html

https://www.cnblogs.com/pyxiaomangshe/p/7927540.html

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

python-__getattr__ 和

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

python-__getattr__ 和

python3完全使用了新式类,废弃了旧式类,getattribute作为新式类的一个特性有非常奇妙的作用。查看一些博客和文章后,发现想要彻底理解getattr和getattribute的区别,实际上需要理解python中属性的查找顺序、描
2023-01-30

详解Python中 __get__和__getattr__和__getattribute__的区别

引子 假设我们有个类A,其中a是A的实例 a.x时发生了什么属性的lookup顺序如下:如果重载了__getattribute__,则调用.a.__dict__, 实例中是不允许有descriptor的,所以不会遇到descriptorA.
2022-06-04

__getattr__

正常情况下,当调用类的方法或属性时,如果不存在,就会报错要避免这个错误,除了可以加上那个要调用但不存在的属性外,Python还有另一个机制,那就是写一个__getattr__()方法,动态返回一个属性只有在没有找到属性的情况下,才调用__g
2023-01-31

Python中的getattr,__getattr__,__getattribute__和__get__怎么用

这篇文章将为大家详细讲解有关Python中的getattr,__getattr__,__getattribute__和__get__怎么用,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。getattrget
2023-06-22

对比Python中__getattr__和 __getattribute__获取属性的用法

相信大家觉得大多数时候我们并不太需要关注getattribute和getattr的一些细节(至少我自己吧:)), 一般情况下消费我们自定义的类的时候,我们对类的结构都了解,不会刻意偏离,造成一些属性访问的错误。 不过作为一个有好奇心有追求有
2022-06-04

Kivy 屏幕管理器 kivy\properties.pyx KeyError 和 AttributeError:“super”对象没有属性“__getattr__”。您的意思是:“__setattr

问题内容我在尝试使用 kivy 实现屏幕管理器时遇到了问题。正如您所看到的“聊天”id 是在 main.kv 中定义的,所以我无法理解为什么会发生错误。我是 kivy 的新手,以前从未使用过屏幕管理器..请帮忙!app_cleaned.
Kivy 屏幕管理器 kivy\properties.pyx KeyError 和 AttributeError:“super”对象没有属性“__getattr__”。您的意思是:“__setattr
2024-02-09

Python 2.7 和 Python

Python 2 发布于 2000 年年底,意味着较之先前版本,这是一种更加清晰和更具包容性的语言开发过程。而先前版本的 Python 应用的是 PEP (Python 增强协议),这种技术规范能向 Python 社区成员提供信息或描述这种
2023-01-31

Python 2 和 Python 3

Guido(Python之父,仁慈的独裁者)在设计 Python3 的过程中,受一篇文章 “Python warts” 的影响,决定不向后兼容,否则无法修复大多数缺陷。---摘录自《流畅的Python》  你可能从来没有听说过学 Java
2023-01-31

关于python和sudo python

之前在搞ssd的时候没出问题,后来重装啦一下系统,把它拷回来,发现出了点问题,在训练或者测试的时候,需要输入:python examples/ssd/ssd_pascal.py 或者python examples/ssd/score_ssd
2023-01-31

python classmethod和

这两个装饰器是Python自带的,虽然一直都知道装饰器是怎么用的,但是确实不知道何时去使用它们,今天看到某人用到了,又看了一遍,才有所收货.   其实我们几乎可以不用这两个装饰器,总有办法解决问题,所以让我定义装饰起的用途,那么就一点,让代
2023-01-31

vim支持+python和+python

vim(33) zz:http://jingyan.baidu.com/article/c1a3101e41c0b4de656debcb.htmlubuntu 中的 vim 从 16.04 开始支持 python3 取代了之前对 Pytho
2023-01-31

Python实战(5)Python和Sh

Shell使用系统tarPython使用tarfile模块,Python不开多线程的情况两者做文件打包压缩对比。Shell代码 #!/bin/sh - # Bak_rsync_Shell.sh version  shell_dir=`pwd
2023-01-31

python datetime和cale

一,datetime模块datetime模块定义了下面这几个类:datetime.date:表示日期的类。常用的属性有year, month, day;datetime.time:表示时间的类。常用的属性有hour, minute, sec
2023-01-31

python sorted 和 lamb

dict = [{'id':'4','name':'b'},{'id':'6','name':'c'},{'id':'3','name':'a'},{'id':'1','name':'g'},{'id':'8','name':'f'}]di
2023-01-31

python isinstance和is

一.isinstance和issubclass1.isinstanceclass Animal: def eat(self): print('刚睡醒吃点儿东西')class Cat(Animal): def pla
2023-01-30

Python encode和decode

今天在写一个StringIO.write(int)示例时思维那么一发散就拐到了字符集的问题上,顺手搜索一发,除了极少数以外,绝大多数中文博客都解释的惨不忍睹,再鉴于被此问题在oracle的字符集体系中蹂躏过,因此在过往笔记的基础上增删了几个
2023-01-30

python之permutations和

>>> import itertools>>> list(itertools.combinations('abc', 2))[('a', 'b'), ('a', 'c'), ('b', 'c')]>>> list(itertools.per
2023-01-31

Python-JSON和pickle

笔记:一:简介 (1)JSON (JavaScript Object Notation) 是一种轻量级(XML重量级)的数据交换格式。 是为了数据交换而定制的一种规则,它基于ECMAScript的一个子集。 (2)JSON
2023-01-30

python write和writeli

file.write(str)的参数是一个字符串,就是你要写入文件的内容.file.writelines(sequence)的参数是序列,比如列表,它会迭代帮你写入文件。
2023-01-31

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录