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

Другие вопросы по тегам