如何防止内置类型被覆盖(分配给)它们的方法?
How are built-in types protected from overwriting (assigning to) their methods?
我注意到
int.__str__ = lambda x: pass
产生错误。
我明白了,为什么这是被禁止的。但是怎么办?我可以在 "normal" 代码中使用它吗?
对于直接在 int
本身和其他内置类型(而不是它们的实例)上设置属性,这种保护发生在 type.__setattr__
中,它特别禁止在内置类型上设置属性:
static int
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
int res;
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;
}
...
Py_TPFLAGS_HEAPTYPE
是指示类型是否在 Python 而不是 C 中定义的标志。
你不能用你自己的 类 做同样的事情,除非你用 C 实现它们。你可以通过编写一个带有自定义 __setattr__
的元类来假装这样做,但是使使用其他有用的 meta类 变得更加复杂,但它仍然不能阻止有人直接在你的 类 上调用 type.__setattr__
。 (用 object.__setattr__(int, ...)
尝试类似的技巧是行不通的,因为有一个 specific check 可以捕捉到它。)
您没有询问内置类型的实例,但它们也很有趣。大多数内置类型的实例不能在其上设置属性,仅仅是因为没有地方可以放置这些属性 - 没有 __dict__
。与其拥有特殊的 "no setting allowed" __setattr__
,或缺少 __setattr__
,他们通常从 object
继承 __setattr__
,knows how to handle 对象没有 __dict__
:
descr = _PyType_Lookup(tp, name);
if (descr != NULL) {
Py_INCREF(descr);
f = descr->ob_type->tp_descr_set;
if (f != NULL) {
res = f(descr, obj, value);
goto done;
}
}
if (dict == NULL) {
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
if (descr == NULL) {
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%U'",
tp->tp_name, name);
}
else {
PyErr_Format(PyExc_AttributeError,
"'%.50s' object attribute '%U' is read-only",
tp->tp_name, name);
}
goto done;
}
...
我注意到
int.__str__ = lambda x: pass
产生错误。
我明白了,为什么这是被禁止的。但是怎么办?我可以在 "normal" 代码中使用它吗?
对于直接在 int
本身和其他内置类型(而不是它们的实例)上设置属性,这种保护发生在 type.__setattr__
中,它特别禁止在内置类型上设置属性:
static int
type_setattro(PyTypeObject *type, PyObject *name, PyObject *value)
{
int res;
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;
}
...
Py_TPFLAGS_HEAPTYPE
是指示类型是否在 Python 而不是 C 中定义的标志。
你不能用你自己的 类 做同样的事情,除非你用 C 实现它们。你可以通过编写一个带有自定义 __setattr__
的元类来假装这样做,但是使使用其他有用的 meta类 变得更加复杂,但它仍然不能阻止有人直接在你的 类 上调用 type.__setattr__
。 (用 object.__setattr__(int, ...)
尝试类似的技巧是行不通的,因为有一个 specific check 可以捕捉到它。)
您没有询问内置类型的实例,但它们也很有趣。大多数内置类型的实例不能在其上设置属性,仅仅是因为没有地方可以放置这些属性 - 没有 __dict__
。与其拥有特殊的 "no setting allowed" __setattr__
,或缺少 __setattr__
,他们通常从 object
继承 __setattr__
,knows how to handle 对象没有 __dict__
:
descr = _PyType_Lookup(tp, name);
if (descr != NULL) {
Py_INCREF(descr);
f = descr->ob_type->tp_descr_set;
if (f != NULL) {
res = f(descr, obj, value);
goto done;
}
}
if (dict == NULL) {
dictptr = _PyObject_GetDictPtr(obj);
if (dictptr == NULL) {
if (descr == NULL) {
PyErr_Format(PyExc_AttributeError,
"'%.100s' object has no attribute '%U'",
tp->tp_name, name);
}
else {
PyErr_Format(PyExc_AttributeError,
"'%.50s' object attribute '%U' is read-only",
tp->tp_name, name);
}
goto done;
}
...