for i in foo:
print i
这是失败的代码,所以让我们看看内部发生了什么,深入到一些Python内部的源代码!
什么时候
for i in foo
GET_ITER
foo
导致a
PyObject_GetIter
调用对象,该对象是提供iterable的实际实现。让我们看看
what it does
PyObject * PyObject_GetIter(PyObject *o)
{
PyTypeObject *t = o->ob_type;
getiterfunc f = NULL;
if (PyType_HasFeature(t, Py_TPFLAGS_HAVE_ITER))
f = t->tp_iter;
if (f == NULL) {
if (PySequence_Check(o))
return PySeqIter_New(o);
return type_error("'%.200s' object is not iterable", o);
}
else {
PyObject *res = (*f)(o);
if (res != NULL && !PyIter_Check(res)) {
PyErr_Format(PyExc_TypeError,
"iter() returned non-iterator of type '%.100s'",
res->ob_type->tp_name);
Py_DECREF(res);
res = NULL;
}
return res;
}
}
如您所见(如果您至少了解一些基本的C语言),首先从对象中查找底层类型(
o->ob_type
t->tp_iter
).
因为您已经实现了
__iter__
else
iter
对象上的函数
o
. 结果是非null的,但我们仍然得到返回的非迭代器消息,因此
PyIter_Check(res)
似乎失败了。让我们看看
what that does
#define PyIter_Check(obj) \
(PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_ITER) && \
(obj)->ob_type->tp_iternext != NULL && \
(obj)->ob_type->tp_iternext != &_PyObject_NextNotImplemented)
所以这个基本上是检查
ob_type
)传递的对象的
next
tp_iternext
)这并不是下一个未实现的功能。
仔细检查检查发生在哪里:在结果上
类型
,而不是结果本身。这个
对象确实具有
下一个
函数,但其类型
Foo
没有。
setattr(foo, 'next', MethodType(next, foo, Foo))
foo.next = next.__get__(foo, Foo)
只设置边界
下一个
在实例上
如果你要设置
下一个
类型
foo = Foo()
Foo.next = next
for i in foo:
print i
classmethod
工作:您在
类型
而不是它的具体实例。