type.__setattr__用于类,基本上是元类的实例。另一方面,object.__setattr__用于类的实例。这是完全可以理解的。
我看不出这两个方法之间有什么明显的区别,至少在Python级别上,我注意到这两个方法使用相同的过程进行属性分配,如果我错了,请纠正我:
假设a是用户定义类的实例,只是一个普通类:
class A:
pass
a = A()
a.x = ...然后a.x = ..调用type(a).__setattr__(...),它执行以下步骤:
注意:type(a).__setattr__将在object内置类中找到__setattr__
1)在type(a).__mro__中查找数据描述符。
2)如果找到数据描述符,调用其__set__方法并退出。
3)如果在type(a).__mro__中未找到数据描述符,则向a.__dict__、a.__dict__['x'] = ...添加属性
对于类--元类的实例,该过程类似:
class A(metaclass=type):
pass然后:A.x = ...被转换为type(A).__setattr__(...),执行以下步骤:
注意:type(A).__setattr__将在type内置类中找到__setattr__
1)在type(A).__mro__中查找数据描述符
2)如果找到数据描述符,调用其__set__方法并退出。
3)如果在type(A).__mro__中未找到数据描述符,则向A.__dict__、a.__dict__['x'] = ...添加属性
但是object.__setattr__不适用于类:
>>> object.__setattr__(A, 'x', ...)
TypeError: can't apply this __setattr__ to type object反之亦然,type.__setattr__不适用于A实例:
>>> type.__setattr__(A(), 'x', ...)
TypeError: descriptor '__setattr__' requires a 'type' object but received a 'A'嗯!这两种方法之间肯定有些不同。这是微妙的,但还是正确的!
假设这两种方法在__setattr__中执行相同的步骤,那么type.__setattr__和object.__setattr__之间有什么区别,以便type.__setattr__仅限于类,而object.__setattr__仅限于类的实例?
发布于 2017-05-02 18:45:23
type.__setattr__有一个检查,以防止设置像int这样的类型的属性,并且它做了一堆普通对象不需要的不可见清理。
让我们看看引擎盖下面!这是type.__setattr__
static int
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
PyErr_Format(
PyExc_TypeError,
"can't set attributes of built-in/extension type '%s'",
type->tp_name);
return -1;
}
if (PyObject_GenericSetAttr((PyObject *)type, name, value) < 0)
return -1;
return update_slot(type, name);
}如果我们检查PyBaseObject_Type,我们可以看到它使用PyObject_GenericSetAttr作为它的__setattr__,这个调用出现在type_setattro的中途。
因此,type.__setattr__就像object.__setattr__,但是有一些附加的处理围绕着它。
首先,if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE))检查禁止对用C编写的类型(如int或numpy.array )分配属性,因为在这些类型上分配属性可能会严重破坏Python的内部结构,这是一些不熟悉can的人可能不会想到的。
其次,在PyObject_GenericSetAttr调用更新类型的dict或从元类调用适当的描述符之后,update_slot修复了受属性赋值影响的任何插槽。这些插槽是实现诸如实例分配、in检查、+、去分配等功能的C级函数指针。它们中的大多数都有相应的Python级方法,如__contains__或__add__,如果重新分配了这些Python级别的方法之一,则相应的槽(或插槽)也必须更新。update_slot还更新类的所有子类上的插槽,并使用于类型对象属性的内部属性缓存中的条目无效。
https://stackoverflow.com/questions/43739608
复制相似问题