分配给属性引用期间出现 TypeError?

TypeError during assignment to attribute reference?

在 Python 的文档中阅读有关 Assignment statements 的内容,我发现了这个:

If the target is an attribute reference: The primary expression in the reference is evaluated. It should yield an object with assignable attributes; if this is not the case, TypeError is raised. That object is then asked to assign the assigned object to the given attribute; if it cannot perform the assignment, it raises an exception (usually but not necessarily AttributeError).

我想知道如何获得这个TypeError

什么Python类型没有设置属性的套路?

如果您想在代码中引发 TypeError:

raise TypeError

我建议您阅读 Python 中的异常和异常处理以获取更多信息。 https://docs.python.org/3/tutorial/errors.html

这个文档行真的已经过时了。它至少可以追溯到 Python 1.4,远早于 type/class 统一。我相信那时,尝试做一些像

x = 1
x.foo = 3

会产生 TypeError,但我当时并没有写 Python,而且我没有足够古老的解释器版本来测试它。

如果您查看 source code 属性分配分派,您可以看到记录的检查仍然存在:

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 会引发错误,根据该类型是否有获取属性的例程来抱怨 "no attributes" 或 "only read-only attributes"。我相信在早期,像 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 而言,这部分文档可能只是遗留物。