所以问题很简单: 如果我们有一个随机类,让我们说一个int,我们尝试访问一个未定义的属性:
my_int = 5
my_int.this_is_a_test
我们会收到此错误:
AttributeError: 'int' object has no attribute 'this_is_a_test'
但是如果我们尝试访问它的索引(在这种情况下Python会查找__getitem__
属性):
my_int = 5
my_int[0]
我们得到:
TypeError: 'int' object has no attribute '__getitem__'
异常类型更改背后的逻辑是什么?对我来说,TypeError
被引发似乎很奇怪,抱怨缺少属性(AttributeError
似乎是一个更好的候选者)
答案 0 :(得分:3)
这取决于你的意图。
In [1]: my_int = 5
In [2]: my_int.__getitem__(0) # -> AttributeError
In [3]: my_int[0] # -> TypeError
当您使用.
时,您隐式调用getattr
函数,如果该属性不存在,则自然会引发AttributeError
。
更新2 。让我们看一下字节码。
In [11]: import dis
In [12]: def via_operator():
my_int = 5
my_int[0]
In [13]: def via_getattr():
my_int = 5
my_int.__getitem__(0)
In [14]: dis.dis(via_operator)
2 0 LOAD_CONST 1 (5)
3 STORE_FAST 0 (my_int)
3 6 LOAD_FAST 0 (my_int)
9 LOAD_CONST 2 (0)
12 BINARY_SUBSCR
13 POP_TOP
14 LOAD_CONST 0 (None)
17 RETURN_VALUE
In [15]: dis.dis(via_getattr)
2 0 LOAD_CONST 1 (5)
3 STORE_FAST 0 (my_int)
3 6 LOAD_FAST 0 (my_int)
9 LOAD_ATTR 0 (__getitem__)
12 LOAD_CONST 2 (0)
15 CALL_FUNCTION 1
18 POP_TOP
19 LOAD_CONST 0 (None)
22 RETURN_VALUE
如您所见,[]
有一个特殊的虚拟机指令。来自docs
BINARY_SUBSCR:实现TOS = TOS1 [TOS]。
因此,当您执行指令失败时,提出TypeError
是很自然的。
更新1 :查看getattr
来源,很清楚此功能永远不会引发TypeError
,因此[]
操作员并没有在引擎盖下调用它(至少对于内置类型,尽管找到源代码来澄清这一点比较好)。
static PyObject *
builtin_getattr(PyObject *self, PyObject *args)
{
PyObject *v, *result, *dflt = NULL;
PyObject *name;
if (!PyArg_UnpackTuple(args, "getattr", 2, 3, &v, &name, &dflt))
return NULL;
#ifdef Py_USING_UNICODE
if (PyUnicode_Check(name)) {
name = _PyUnicode_AsDefaultEncodedString(name, NULL);
if (name == NULL)
return NULL;
}
#endif
if (!PyString_Check(name)) {
PyErr_SetString(PyExc_TypeError,
"getattr(): attribute name must be string");
return NULL;
}
result = PyObject_GetAttr(v, name);
if (result == NULL && dflt != NULL &&
PyErr_ExceptionMatches(PyExc_AttributeError))
{
PyErr_Clear();
Py_INCREF(dflt);
result = dflt;
}
return result;
}
答案 1 :(得分:1)
AttributeError
的{{1}}可能会产生误导,因为您没有尝试访问my_int[0]
的属性,而您正试图访问项目。引发my_int
是因为TypeError
不支持下标,并且此异常消息已在Python 3.X中更新。
话虽如此,但int
没有AttributeError
是不合适的。我怀疑这可能是__getitem__
,因为数字(TypeError
,int
,float
)是唯一不支持下标的内置数据类型。
当出现此错误时,您会认为long
包含不同类型的对象,因此my_int
。