2014-05-09 73 views
2

实例的基础上记忆考虑到我有几百万的对象有3 __slots__待办事项属性名消耗蟒蛇

它是更多的内存高效能有像x与长的很像would_you_like_fries_with_that_cheeseburger短插槽名称?

或者每类分配一次的名称(相对于每一次实例?)

回答

4

名称为插槽只需要存储每类,而不是每个实例。

插槽使用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; 

函数然后返回。