问题描述
根据Python language documentation:
__slots__
允许我们显式声明数据成员(如属性)并拒绝创建 __dict__
和 __weakref__
(除非在 __slots__
中显式声明或在父级中可用.)
所以我想知道这个类是否
>>> class A: __slots__ = ('__dict__','__weakref__')
...
>>> del A.__slots__
>>> vars(A)
mappingproxy({
'__module__': '__main__','__dict__': <attribute '__dict__' of 'A' objects>,'__weakref__': <attribute '__weakref__' of 'A' objects>,'__doc__': None
})
相当于这个:
>>> class A: pass
...
>>> vars(A)
mappingproxy({
'__module__': '__main__','__doc__': None
})
解决方法
如果您未设置 __slots__
属性,则默认情况下会在特定条件下创建 __weakref__
和 __dict__
插槽。
这发生在type.__new__()
;一个类被赋予描述符来访问每个实例的内存插槽:
-
首先,通过测试
tp_dictoffset
、tp_weaklistoffset
和tp_itemsize
在类型对象结构。- 如果基类尚未定义一个
__dict__
槽(base->tp_dictoffset
为 0),则您只能有一个__weakref__
槽。 - 如果基类型未定义一个(
base->tp_weaklistoffset
为 0)并且基具有固定长度的实例(base->tp_itemsize
为 0),则您只能有一个__slots__
槽。
- 如果基类尚未定义一个
-
然后,如果没有
slots = _PyDict_GetItemIdWithError(dict,&PyId___slots__); nslots = 0; add_dict = 0; add_weak = 0; may_add_dict = base->tp_dictoffset == 0; may_add_weak = base->tp_weaklistoffset == 0 && base->tp_itemsize == 0; if (slots == NULL) { if (PyErr_Occurred()) { goto error; } if (may_add_dict) { add_dict++; } if (may_add_weak) { add_weak++; } } else { /* Have slots */ ... }
,则设置标志变量以实际启用要添加的插槽。
type.__new__()
implementation 很长,但相关部分如下所示:
if (add_dict) {
if (base->tp_itemsize)
type->tp_dictoffset = -(long)sizeof(PyObject *);
else
type->tp_dictoffset = slotoffset;
slotoffset += sizeof(PyObject *);
}
if (add_weak) {
assert(!base->tp_itemsize);
type->tp_weaklistoffset = slotoffset;
slotoffset += sizeof(PyObject *);
}
然后,再往下大约 400 行,您会找到实际创建插槽的代码:
int
当扩展某些原生类型(例如 bytes
或 __weakref__
)时,您不会获得 tp_itemsize
槽,因为它们具有可变长度的实例(由 class Job {
int jobID;
List<Task> task_list;
String imageURL;
String jobName;
Job({
this.jobId,this.task_list,this.imageURL,this.jobName,});
}
class Task{
int taskID;
String imageURL;
String name;
String type;
int taskTime;
Task({
this.taskID,this.name,this.type,this.taskTime,})
}
final int myId = 1234;
final List<Task> all_tasks= [_task1,_task2,_task3];
final String myUrl = 'www.stackoverflow.com';
final String myJobName = 'developer';
final Job myJob = Job(myId,all_tasks,myUrl,myJobName);
处理) ).