Loading [MathJax]/jax/input/TeX/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >问答首页 >在这种情况下,为什么__setattr__和__delattr__会引发AttributeError?

在这种情况下,为什么__setattr__和__delattr__会引发AttributeError?
EN

Stack Overflow用户
提问于 2021-03-22 13:27:07
回答 1查看 565关注 0票数 3

在Python中,如果类型的属性是没有object.__setattr__方法的数据描述符,那么type.__setattr__AttributeError在属性更新期间引发AttributeError的理由是什么?同样,如果类型的属性是一个没有object.__delattr__方法的数据描述符,那么在删除属性期间,type.__delattr__AttributeError的理由是什么?

我之所以问这个问题,是因为我注意到,如果类型有一个属性(即没有__get__方法的数据描述符),则在属性查找期间,type.__getattribute__AttributeError不会引发AttributeError

下面是一个简单的程序,说明了object.__getattribute__查找属性(不引发AttributeError)与object.__setattr__更新属性和object.__delattr__删除属性(提出AttributeError)之间的区别:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class DataDescriptor1:  # missing __get__
    def __set__(self, instance, value): pass
    def __delete__(self, instance): pass

class DataDescriptor2:  # missing __set__
    def __get__(self, instance, owner=None): pass
    def __delete__(self, instance): pass

class DataDescriptor3:  # missing __delete__
    def __get__(self, instance, owner=None): pass
    def __set__(self, instance, value): pass

class A:
    x = DataDescriptor1()
    y = DataDescriptor2()
    z = DataDescriptor3()

a = A()
vars(a).update({'x': 'foo', 'y': 'bar', 'z': 'baz'})

a.x
# actual: returns 'foo'
# expected: returns 'foo'

a.y = 'qux'
# actual: raises AttributeError: __set__
# expected: vars(a)['y'] == 'qux'

del a.z
# actual: raises AttributeError: __delete__
# expected: 'z' not in vars(a)

下面是另一个简单的程序,说明了type.__getattribute__查找属性(不引发AttributeError)与type.__setattr__更新属性和type.__delattr__删除属性(引发AttributeError)之间的区别:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
class DataDescriptor1:  # missing __get__
    def __set__(self, instance, value): pass
    def __delete__(self, instance): pass

class DataDescriptor2:  # missing __set__
    def __get__(self, instance, owner=None): pass
    def __delete__(self, instance): pass

class DataDescriptor3:  # missing __delete__
    def __get__(self, instance, owner=None): pass
    def __set__(self, instance, value): pass

class M(type):
    x = DataDescriptor1()
    y = DataDescriptor2()
    z = DataDescriptor3()

class A(metaclass=M):
    x = 'foo'
    y = 'bar'
    z = 'baz'

A.x
# actual: returns 'foo'
# expected: returns 'foo'

A.y = 'qux'
# actual: raises AttributeError: __set__
# expected: vars(A)['y'] == 'qux'

del A.z
# actual: raises AttributeError: __delete__
# expected: 'z' not in vars(A)

我希望实例字典会发生变异,而不是获得用于属性更新和属性删除的AttributeError。属性查找返回实例字典中的值,因此我想知道为什么属性更新和属性删除也不使用实例字典(就像如果类型没有数据描述符的属性一样)。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2021-03-22 15:47:20

我认为这只是C级设计的一个结果,没有人真正想到或关心它。

在C级别,__set____delete__对应于相同的C级插槽tp_descr_set,而删除是通过传递一个空值来指定的。(这与__setattr____delattr__使用的设计类似,它们也对应于一个插槽,后者也通过NULL进行删除。)

如果您实现了__set____delete__,则C级插槽被设置为查找__set____delete__并调用它的包装函数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
static int
slot_tp_descr_set(PyObject *self, PyObject *target, PyObject *value)
{
    PyObject* stack[3];
    PyObject *res;
    _Py_IDENTIFIER(__delete__);
    _Py_IDENTIFIER(__set__);

    stack[0] = self;
    stack[1] = target;
    if (value == NULL) {
        res = vectorcall_method(&PyId___delete__, stack, 2);
    }
    else {
        stack[2] = value;
        res = vectorcall_method(&PyId___set__, stack, 3);
    }
    if (res == NULL)
        return -1;
    Py_DECREF(res);
    return 0;
}

插槽没有办法说"oops,没有找到方法,回到正常的处理“,也没有尝试。它也不试图模仿正常的处理--这很容易出错,因为“正常处理”是依赖于类型的,而且它也不知道对所有类型都要模仿什么。如果槽包装器找不到该方法,它只会引发异常。

如果__set____delete__有两个插槽,这种效果就不会发生,但是当他们设计API时,会有人关心这个问题,我怀疑有人会这么做。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66754075

复制
相关文章
Python指南:高级程序设计之面向对象程序设计进阶
本节中,我们将更深入地学习 Python 对面向对象的支持,学习很多可以减少必须编写的代码的总量、拓展程序的威力与功能的技术。下面以一个简单的类开始:
王强
2018/08/09
8870
Python自学成才之路 魔术方法之属性访问控制
其中__getattr__只有在属性不存在时会被调用,__getattribute__无论属性是否存在都会被调用,item参数就是要访问的属性。
我是李超人
2020/08/20
5470
Python中反射和描述器总结
在Python中,能够通过一个对象,找出type、class、attribute或者method的能力,成为反射。
py3study
2020/01/14
9310
python 魔术方法(一) 自定义容器类与类属性控制
此前的文章中,我们介绍了 Python 面向对象编程及对象的继承和派生。 接下来的几篇文章,我们将详细介绍 Python 解释器提供的一系列特殊方法 -- 魔术方法。
用户3147702
2022/06/27
6300
python 魔术方法(一) 自定义容器类与类属性控制
定制类和黑魔法
定制类 反射     反射又称为自省,指的是程序可以访问、检测和修改它本身状态和行为的一种能力。python中提供了以下四个自检功能的函数。     hasattr(object, name):用来检测object(适用于类、文件、模块或对象,一切皆对象)中有没有一个name字符串对应的方法或属性。
py3study
2020/02/10
4750
Python进阶——如何正确使用魔法方法?(上)
在做 Python 开发时,我们经常会遇到以双下划线开头和结尾的方法,例如 __init__、__new__、__getattr__、__setitem__ 等等,这些方法我们通常称之为「魔法方法」,而使用这些「魔法方法」,我们可以非常方便地给类添加特殊的功能。
_Kaito
2021/03/23
7170
python 中__setattr__, __getattr__,__getattribute__, __call__使用方法
object._getattr_(self, name) 拦截点号运算。当对未定义的属性名称和实例进行点号运算时,就会用属性名作为字符串调用这个方法。如果继承树可以找到该属性,则不调用此方法 实例instance通过instance.name访问属性name,只有当属性name没有在实例的__dict__或它构造类的__dict__或基类的__dict__中没有找到,才会调用__getattr__。当属性name可以通过正常机制追溯到时,__getattr__是不会被调用的。如果在__getattr__(s
用户1214487
2018/01/24
1.3K0
python面向对象的多态-类相关内置函数-类内置魔法函数-迭代器协议-上下文管理-04
首先强调,多态不是一种特殊的语法,而是一种状态,特性(多个不同对象可以相应同一个方法,长身不同的结果)
suwanbin
2019/09/26
6860
python面向对象的多态-类相关内置函数-类内置魔法函数-迭代器协议-上下文管理-04
【Python大神秘籍Top10】这些窍门99%的人都不知道
【新智元导读】Python神奇方法是指一些允许在自定义类中增加“神奇”功能的方法。而在Python官方文档中,有关这些方法的介绍或描述不仅内容分散,而且组织结构也相对松散。本文便对Python神奇方法做了系统的梳理。对于初学者亦或Python行家,都或多或少的会有些帮助。
新智元
2018/08/16
7130
【Python大神秘籍Top10】这些窍门99%的人都不知道
Spring事物(@transactional注解)在什么情况下会失效,为什么?
2、加了此注解后每个业务方法执行时,都会开启一个事务,不过都是按照相同的管理机制。
凯哥Java
2022/12/16
7030
每天一道 python 面试题 - Python反射与自省
自省:自省就是能够获得自身的结构和方法,给开发者可以灵活的调用,给定一个对象,返回该对象的所有属性和函数列表,或给定对象和该对象的函数或者属性的名字,返回对象的函数或者属性实例
公众号---人生代码
2020/05/18
7450
Python中dir,hasattr,getattr,setattr,vars的使用
Python一切皆对象,对象都有很多属性和方法,使用时我们怎么知道对象有哪些属性,以及如何获取对象的属性和设置对象的属性呢?
Python碎片公众号
2021/02/26
1.4K0
Python中dir,hasattr,getattr,setattr,vars的使用
魔法方法(2)
在学习面向对象程序设计时,我们通常会学到存取方法,它们是名称类似于getHeight和setHeight的方法,用于获取和设置属性(这些属性可能是私有的)。如果访问给定的时必须采取特定的措施,那么像这样封装状态变量(属性)很重要。例如,请看下面的Rectangle类:
不可言诉的深渊
2019/07/26
7260
我终于把Python中下划线的含义弄清楚了(憋了很久了)
Python中有关单个和双下划线(“ dunder”)的各种含义和命名约定,名称修饰的工作方式以及它如何影响Python类。
Python知识大全
2020/02/13
11K0
我终于把Python中下划线的含义弄清楚了(憋了很久了)
五个与Python属性相关的魔术方法
今天要给大家介绍五个魔术方法,他们都与Python属性相关,涉及获取、删除和修改属性,我们一起来看看吧。
罗罗攀
2021/12/06
3270
Python中 5 种不同的下划线含义你都知道吗?
本文将介绍Python中单下划线和双下划线("dunder")的各种含义和命名约定,名称修饰(name mangling)的工作原理,以及它如何影响你自己的Python类。
Python数据科学
2020/09/24
8920
Python中 5 种不同的下划线含义你都知道吗?
点击加载更多

相似问题

为什么在这种情况下会引发ClassLoader异常?

20

超载__setattr__导致AttributeError

22

为什么从实例中获取类属性会引发AttributeError?

25

为什么超级().__dict__会引发一个AttributeError?

23

AttributeError: Preferences实例没有属性“__setattr__”

20
添加站长 进交流群

领取专属 10元无门槛券

AI混元助手 在线答疑

扫码加入开发者社群
关注 腾讯云开发者公众号

洞察 腾讯核心技术

剖析业界实践案例

扫码关注腾讯云开发者公众号
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文