如何创建只读插槽?
How to create read-only slots?
插槽默认为 可写:
>>> class A: __slots__ = ('x',)
...
>>> list(vars(A))
['__module__', '__slots__', 'x', '__doc__']
>>> vars(A)['x']
<member 'x' of 'A' objects>
>>> a = A()
>>> a.x = 'foo'
>>> del a.x
如何创建 只读 插槽,例如 [=24= 的插槽 '__thisclass__'
、'__self__'
和 '__self_class__'
] super
?
>>> list(vars(super))
['__repr__', '__getattribute__', '__get__', '__init__', '__new__',
'__thisclass__', '__self__', '__self_class__', '__doc__']
>>> vars(super)['__thisclass__']
<member '__thisclass__' of 'super' objects>
>>> s = super(int, 123)
>>> s.__thisclass__ = float
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
>>> del s.__thisclass__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
你不能,Python 代码没有选项来创建只读描述符,例如用于 __thisclass__
等的描述符
在 C API 中,插槽都使用相同的描述符对象类型,对于 PyMemberDef
arrays 中 flags
设置为 READONLY
的条目,它变成只读的.
例如您确定的 super
描述符在 super_members
array:
中定义
static PyMemberDef super_members[] = {
{"__thisclass__", T_OBJECT, offsetof(superobject, type), READONLY,
"the class invoking super()"},
{"__self__", T_OBJECT, offsetof(superobject, obj), READONLY,
"the instance invoking super(); may be None"},
{"__self_class__", T_OBJECT, offsetof(superobject, obj_type), READONLY,
"the type of the instance invoking super(); may be None"},
{0}
};
当__slots__
正在处理时,没有可以设置此标志的路径; code in type.__new__
just sets the first three values,分别是name
、type
和offset
:
mp = PyHeapType_GET_MEMBERS(et);
slotoffset = base->tp_basicsize;
if (et->ht_slots != NULL) {
for (i = 0; i < nslots; i++, mp++) {
mp->name = PyUnicode_AsUTF8(
PyTuple_GET_ITEM(et->ht_slots, i));
if (mp->name == NULL)
goto error;
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 *);
}
}
供参考:
PyHeapType_GET_MEMBERS
访问正在创建的新类型对象的 PyMemberDef
数组。它已经分配了正确数量的插槽。
et->ht_slots
是插槽名称的元组。
slotoffset
是存储槽内容到实例对象内存区的相对偏移量
-
type
字段的 T_OBJECT_EX
值意味着插槽存储指向 Python 对象的指针,如果指针设置为 NULL
则 AttributeError
当您尝试获取值时会引发。
请注意,如果 可以将这些插槽设置为只读,您还需要一种机制来在 [=58] 之前提供它们的值=] 创建一个新实例!毕竟,如果所有 Python 代码都被阻止在实例上设置只读属性,那么您的 Python class 将如何设置初始值?
插槽默认为 可写:
>>> class A: __slots__ = ('x',)
...
>>> list(vars(A))
['__module__', '__slots__', 'x', '__doc__']
>>> vars(A)['x']
<member 'x' of 'A' objects>
>>> a = A()
>>> a.x = 'foo'
>>> del a.x
如何创建 只读 插槽,例如 [=24= 的插槽 '__thisclass__'
、'__self__'
和 '__self_class__'
] super
?
>>> list(vars(super))
['__repr__', '__getattribute__', '__get__', '__init__', '__new__',
'__thisclass__', '__self__', '__self_class__', '__doc__']
>>> vars(super)['__thisclass__']
<member '__thisclass__' of 'super' objects>
>>> s = super(int, 123)
>>> s.__thisclass__ = float
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
>>> del s.__thisclass__
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
你不能,Python 代码没有选项来创建只读描述符,例如用于 __thisclass__
等的描述符
在 C API 中,插槽都使用相同的描述符对象类型,对于 PyMemberDef
arrays 中 flags
设置为 READONLY
的条目,它变成只读的.
例如您确定的 super
描述符在 super_members
array:
static PyMemberDef super_members[] = {
{"__thisclass__", T_OBJECT, offsetof(superobject, type), READONLY,
"the class invoking super()"},
{"__self__", T_OBJECT, offsetof(superobject, obj), READONLY,
"the instance invoking super(); may be None"},
{"__self_class__", T_OBJECT, offsetof(superobject, obj_type), READONLY,
"the type of the instance invoking super(); may be None"},
{0}
};
当__slots__
正在处理时,没有可以设置此标志的路径; code in type.__new__
just sets the first three values,分别是name
、type
和offset
:
mp = PyHeapType_GET_MEMBERS(et);
slotoffset = base->tp_basicsize;
if (et->ht_slots != NULL) {
for (i = 0; i < nslots; i++, mp++) {
mp->name = PyUnicode_AsUTF8(
PyTuple_GET_ITEM(et->ht_slots, i));
if (mp->name == NULL)
goto error;
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 *);
}
}
供参考:
PyHeapType_GET_MEMBERS
访问正在创建的新类型对象的PyMemberDef
数组。它已经分配了正确数量的插槽。et->ht_slots
是插槽名称的元组。slotoffset
是存储槽内容到实例对象内存区的相对偏移量-
type
字段的T_OBJECT_EX
值意味着插槽存储指向 Python 对象的指针,如果指针设置为NULL
则AttributeError
当您尝试获取值时会引发。
请注意,如果 可以将这些插槽设置为只读,您还需要一种机制来在 [=58] 之前提供它们的值=] 创建一个新实例!毕竟,如果所有 Python 代码都被阻止在实例上设置只读属性,那么您的 Python class 将如何设置初始值?