实例的基础上记忆考虑到我有几百万的对象有3 __slots__
待办事项属性名消耗蟒蛇
它是更多的内存高效能有像x
与长的很像would_you_like_fries_with_that_cheeseburger
短插槽名称?
或者每类分配一次的名称(相对于每一次实例?)
实例的基础上记忆考虑到我有几百万的对象有3 __slots__
待办事项属性名消耗蟒蛇
它是更多的内存高效能有像x
与长的很像would_you_like_fries_with_that_cheeseburger
短插槽名称?
或者每类分配一次的名称(相对于每一次实例?)
名称为插槽只需要存储每类,而不是每个实例。
插槽使用descriptors直接映射到为实例保留的内存中,属性名称映射到类中的这些描述符。
因此,名称的长度不会影响每个实例对插槽使用多少内存;这些名称只占用类的__dict__
属性(映射名称到描述符)以及描述符对象本身(提供对象的字符串表示形式)中的空间;该字符串甚至被拦截。
您可以检查如何自定义描述符中给出的C source code for type.__new__()
他们的状态:
if (slots != NULL) {
for (i = 0; i < nslots; i++, mp++) {
mp->name = PyString_AS_STRING(
PyTuple_GET_ITEM(slots, i));
mp->type = T_OBJECT_EX;
mp->offset = slotoffset;
/* __dict__ and __weakref__ are already filtered out */
assert(strcmp(mp->name, "__dict__") != 0);
assert(strcmp(mp->name, "__weakref__") != 0);
slotoffset += sizeof(PyObject *);
}
}
其中mp->offset
是该指数为实例的内存。
使用的描述符是PyMemberDescr_Type
object,其member_get
函数使用(非常通用)PyMember_GetOne()
function;与偏移指针从实例检索到:
PyMember_GetOne(const char *addr, PyMemberDef *l)
{
PyObject *v;
if ((l->flags & READ_RESTRICTED) &&
PyEval_GetRestricted()) {
PyErr_SetString(PyExc_RuntimeError, "restricted attribute");
return NULL;
}
addr += l->offset;
addr
是实例的存储器地址。其余的功能涉及各种类型的成员;插槽成员始终设置为T_OBJECT
:
case T_OBJECT:
v = *(PyObject **)addr;
if (v == NULL)
v = Py_None;
Py_INCREF(v);
break;
函数然后返回。