微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决在这种情况下,为什么 __setattr__ 和 __delattr__ 会引发 AttributeError ?

在 Python 中,如果类型具有 update 属性,那么 object.__setattr__type.__setattr__属性 update 期间引发 AttributeError 的基本原理是什么?没有 __set__ 方法的 em>data 描述符?同样,如果该类型具有一个 data 没有 object.__delattr__ 方法的描述符?

我之所以这么问是因为我注意到 type.__delattr__AttributeError not属性 lookup 期间引发了 __delete__,如果该类型有一个属性,它是一个 data 描述符,没有 object.__getattribute__ 方法

这是一个简单的程序,说明一方面通过 type.__getattribute__ 查找属性(未引发 AttributeError)与通过 __get__ 更新属性和通过 {{ 删除属性间的区别1}} 另一方面(object.__getattribute__ 被提升):

AttributeError

这是另一个简单的程序,说明一方面通过 object.__setattr__ 查找属性(未引发 object.__delattr__)与通过 AttributeError 更新属性和通过 {{ 删除属性间的区别1}} 另一方面(class DataDescriptor1: # missing __get__ def __set__(self,instance,value): pass def __delete__(self,instance): pass class DataDescriptor2: # missing __set__ def __get__(self,owner=None): pass def __delete__(self,instance): pass class DataDescriptor3: # missing __delete__ def __get__(self,owner=None): pass def __set__(self,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 以进行属性更新和属性删除属性查找从实例字典返回一个值,所以我想知道为什么属性更新和属性删除不使用实例字典(就像如果类型没有作为数据描述符的属性时那样)。>

解决方法

我认为这只是 C 级设计的结果,没有人真正考虑或关心。

在C级,__set____delete__对应相同的C级slottp_descr_set,通过向set传递空值来指定删除。 (这类似于用于 __setattr____delattr__ 的设计,它们也对应于 a single slot,也通过 NULL 进行删除。)

如果你实现了 __set____delete__,C 级槽被设置为一个 wrapper function,它寻找 __set____delete__ 并调用它:

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__,3);
    }
    if (res == NULL)
        return -1;
    Py_DECREF(res);
    return 0;
}

槽没有办法说“哎呀,没有找到方法,回到正常处理”,它没有尝试。它也不会尝试模拟正常处理——这很容易出错,因为“正常处理”是类型相关的,并且它不知道要为所有类型模拟什么。如果槽包装器没有找到该方法,它只会引发异常。

如果 __set____delete__ 获得了两个插槽,这种效果就不会发生,但是有人在设计 API 时必须关心,我怀疑有人这样做了。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?