TypeError при назначении ссылки на атрибут?
Читая об утверждениях Назначения в документах Python, я нашел это:
Если целью является ссылка на атрибут: вычисляется основное выражение в ссылке. Это должно привести к объекту с присваиваемыми атрибутами; если это не так,
TypeError
Поднялся. Затем этому объекту предлагается назначить назначенный объект данному атрибуту; если он не может выполнить назначение, он вызывает исключение (обычно, но не обязательноAttributeError
).
Мне интересно как это получить TypeError
?
Какие типы Python не имеют процедуры для установки атрибутов?
3 ответа
Эта строка документации просто действительно устарела. Он восходит по крайней мере к Python 1.4, задолго до объединения типа / класса. Я верю тогда, пытаясь сделать что-то вроде
x = 1
x.foo = 3
Я бы написал TypeError, но я тогда не писал Python, и у меня нет достаточно древней версии интерпретатора для его проверки.
Если вы посмотрите на исходный код для отправки атрибутов, вы увидите, что задокументированная проверка все еще существует:
if (tp->tp_setattro != NULL) {
...
return ...;
}
if (tp->tp_setattr != NULL) {
...
return ...;
}
Py_DECREF(name);
assert(name->ob_refcnt >= 1);
if (tp->tp_getattr == NULL && tp->tp_getattro == NULL)
PyErr_Format(PyExc_TypeError,
"'%.100s' object has no attributes "
"(%s .%U)",
tp->tp_name,
value==NULL ? "del" : "assign to",
name);
else
PyErr_Format(PyExc_TypeError,
"'%.100s' object has only read-only attributes "
"(%s .%U)",
tp->tp_name,
value==NULL ? "del" : "assign to",
name);
return -1;
Если у типа объекта нет подпрограммы для установки атрибутов, Python вызывает ошибку, жалуясь на "нет атрибутов" или "только атрибуты только для чтения", в зависимости от того, имеет ли тип подпрограмму для получения атрибутов. Я считаю, в первые дни, такие как int
пошел бы по этому пути кода. Тем не менее, все типы теперь наследуют такие процедуры от object
, поэтому я не думаю, что этот путь к коду когда-либо взят.
Есть связанный путь кода в type.__setattr__
что поднимает TypeError
для установки атрибутов для типов, написанных на C. Этот путь к коду все еще используется, но он не такой общий, как описано в документации:
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;
}
Этот код производит TypeError
и кажется, что это то, что описывает документация:
>>> def f(): pass
...
>>> f.func_globals = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: readonly attribute
Но это TypeError
действительно поднял потому что в документации это сказано? Я искренне сомневаюсь в этом. Похоже func_globals
реализация просто повышает TypeError
если вы попытаетесь назначить что-то на это.
КСТАТИ...
Я бы на самом деле ожидал того же в следующем примере, но это AttributeError
вместо:
>>> class A(object):
... __slots__ = 'a',
...
>>> A().b = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'A' object has no attribute 'b'
Обновление (Python 3)
Выше было в Python 2.7. В Python 3 нет func_globals
, так что это не применимо (вы можете назначить все, что угодно).
Какие атрибуты функции в Python 3, кажется, вызывают AttributeError
когда это только для чтения.
>>> f.__globals__ = 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: readonly attribute
Это имеет смысл для меня. Возможно, эта часть документации является просто реликвией в том, что касается Python 3.
Если вы хотите поднять TypeError в своем коде:
raise TypeError
Я предлагаю вам прочитать об исключениях и обработке исключений в Python для получения дополнительной информации. https://docs.python.org/3/tutorial/errors.html