Python 类型与对象的区别有多大?
Python 类型与对象的区别有多大?,python,metaclass,Python,Metaclass,type.\uuuu setattr\uuuuu用于类,基本上是元类的实例对象。另一方面,用于类的实例。这是完全理解的 我看不出这两种方法之间有什么显著的区别,至少在Python级别,我注意到这两种方法使用相同的属性赋值过程,如果我错了,请纠正我: 假设a是一个用户定义类的实例,只是一个普通类: class A: pass a = A() a.x = ... 然后,a.x=…调用type(a)。\uuuuu setattr\uuuuuuu(…)执行以下步骤: 注意:类型(a)。\uu
type.\uuuu setattr\uuuuu
用于类,基本上是元类的实例<代码>对象。另一方面,用于类的实例。这是完全理解的
我看不出这两种方法之间有什么显著的区别,至少在Python级别,我注意到这两种方法使用相同的属性赋值过程,如果我错了,请纠正我:
假设a
是一个用户定义类的实例,只是一个普通类:
class A:
pass
a = A()
a.x = ...
然后,a.x=…
调用type(a)。\uuuuu setattr\uuuuuuu(…)
执行以下步骤:
注意:类型(a)。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
1) 在类型(a)中查找数据描述符
2) 如果找到一个数据描述符,调用它的\uuuu set\uu
方法并退出
3) 如果在类型(a)中找不到数据描述符,则将属性添加到a.。a.。\uuuuuu dict\uuuu['x']=…
对于类——元类的实例,过程类似:
class A(metaclass=type):
pass
然后:A.x=…
被转换为类型(A)。\uuuu setattr\uuuu(…)
,执行以下步骤:
注:类型(A)。\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu
1) 在类型(a)中查找数据描述符
2) 如果找到一个数据描述符,调用它的\uuuu set\uu
方法并退出
3) 如果在类型(A)中找不到数据描述符,则将属性添加到A.。A.。\uuuuuu dict\uuuu['x']=…
但是object.\uuuu setattr\uuuu
不适用于类:
>>> object.__setattr__(A, 'x', ...)
TypeError: can't apply this __setattr__ to type object
反之亦然,type.\uuuuu setattr\uuuuu
不适用于A
的实例:
>>> type.__setattr__(A(), 'x', ...)
TypeError: descriptor '__setattr__' requires a 'type' object but received a 'A'
嗯!!这两种方法之间肯定有些不同。这是微妙的,但确实如此
假设这两种方法在\uuuuuu setattr\uuuuuu
中执行相同的步骤,type.\uuuuu setattr\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu,它还进行了一系列不可见的清理,这对于普通对象来说是不必要的
让我们看看引擎盖下面!这是:
static int
类型_setattro(PyTypeObject*类型、PyObject*名称、PyObject*值)
{
if(!(类型->tp_标志和Py_TPFLAGS_HEAPTYPE)){
Pyrr_格式(
PyExc_类型错误,
“无法设置内置/扩展类型“%s”的属性,
类型->tp_名称);
返回-1;
}
if(PyObject_genericsettr((PyObject*)类型、名称、值)<0)
返回-1;
返回更新槽(类型、名称);
}
如果我们检查,我们会看到它使用PyObject\u GenericSetAttr
作为其\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu setattr
的调用,在type\u setattro
的中间出现了相同的调用
因此,type.\uuuuSetAttr\uuuuuuuu
类似于对象。\uuuuuSetAttr\uuuuuuuuu
,但有一些附加的处理
首先,if(!(type->tp_flags&Py_TPFLAGS_HEAPTYPE))
检查禁止对用C编写的类型进行属性分配,如int
或numpy.array
,因为在这些类型上分配属性可能会以不熟悉C-API的人可能无法预料的方式严重破坏Python内部结构
其次,在PyObject\u GenericSetAttr
调用更新类型的dict或从元类调用适当的描述符之后,update\u slot
修复受属性分配影响的所有插槽。这些插槽是C级函数指针,实现诸如实例分配、检查中的、+
、解除分配等功能。它们中的大多数都有相应的Python级方法,如\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu包含
或或\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu添加(或插槽)也必须更新。update\u slot
也会更新类的所有子体上的slot,并且它会使用于类型对象属性的内部属性缓存中的条目无效。关于您提到的第二步的一个问题。假设Klass
最初没有\u contains\uu
和__contains
是在类创建后分配的。如果我分配给像:Klass这样的类。PyObject\u GenericSettR
将更新Klass。dict
和update\u slot
将更新\uU contains\uCODE>的插槽。这也意味着\uU CONTAINSTAINS\uC>的插槽将更新ode>在赋值之前最初是Null
?@direprobs:update\u slot
将设置与\uuuu contains\uuuu
相对应的插槽。该插槽是->tp\u as\u sequence->sq sq\u contains
,并且不仅仅是sq\u contains
为Null,它甚至可能还不存在,因为tp\u as\u sequence
本身可能存在已经为空。(除非您需要使用C API,否则这些对您来说都不重要。)
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);
}