Для установки атрибутов непосредственно на самом 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, ...)
не работает, потому что есть специальная проверка , чтобы поймать это.)
Вы не спрашивали об экземплярах встроенных типов, но они также интересны. Экземпляры большинства встроенных типов не могут иметь атрибуты, установленные на них просто потому, что такие атрибуты некуда поместить - нет __dict__
. Вместо того, чтобы иметь специальную «не разрешенную настройку» __setattr__
или не иметь __setattr__
, они обычно наследуют __setattr__
от object
, который знает, как обрабатывать объекты без __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;
}
...