内置类型如何防止覆盖(分配)其方法?

时间:2018-05-01 14:38:58

标签: python built-in-types

我注意到了

int.__str__ = lambda x: pass

产生错误。

我可以看到,为什么这是被禁止的。但是怎么样?我可以在“普通”代码中使用它吗?

1 个答案:

答案 0 :(得分:4)

为了直接在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__的元类来假装这样做,但这会使得使用其他有用的元类更多很复杂,它仍然不会阻止有人直接在你的课堂上调用type.__setattr__。 (使用object.__setattr__(int, ...)尝试类似的技巧并不起作用,因为有specific check可以捕获它。)

您没有询问内置类型的实例,但它们也很有趣。大多数内置类型的实例都不能设置属性,因为没有地方可以放置这些属性 - 没有__dict__。而不是有一个特殊的"没有设置允许" __setattr__,或缺少__setattr__,他们通常会从__setattr__继承object,其中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;
    }
    ...