weg*_*gry 14 python python-2.7 python-3.x
对于我来说,这在Python 2.7.6和3.3.3中会发生.当我定义这样的类时
class foo:
def __getitem__(self, *args):
print(*args)
Run Code Online (Sandbox Code Playgroud)
然后尝试在一个实例上迭代(以及我认为会称之为iter),
bar = foo()
for i in bar:
print(i)
Run Code Online (Sandbox Code Playgroud)
它只是为一个args计算,并永远打印无.就语言设计而言,这是故意的吗?
样本输出
0
None
1
None
2
None
3
None
4
None
5
None
6
None
7
None
8
None
9
None
10
None
Run Code Online (Sandbox Code Playgroud)
Ray*_*ger 24
是的,这是一个预期的设计.它经过记录,经过充分测试,并且依赖于序列类型,例如str.
在Python拥有现代迭代器之前,__ getitem__版本是遗留的.我们的想法是,任何序列(可索引且具有长度的东西)都可以使用系列s [0],s [1],s [2],...自动迭代,直到引发IndexError或StopIteration.
例如,在Python 2.7中,由于__getitem__方法(str类型没有__iter__方法),字符串是可迭代的.
相反,迭代器协议允许任何类可迭代,而不必是可索引的(例如,dicts和sets).
以下是如何使用序列的遗留样式创建可迭代类:
>>> class A:
def __getitem__(self, index):
if index >= 10:
raise IndexError
return index * 111
>>> list(A())
[0, 111, 222, 333, 444, 555, 666, 777, 888, 999]
Run Code Online (Sandbox Code Playgroud)
以下是使用__iter__方法进行迭代的方法:
>>> class B:
def __iter__(self):
yield 10
yield 20
yield 30
>>> list(B())
[10, 20, 30]
Run Code Online (Sandbox Code Playgroud)
对于那些对细节感兴趣的人,相关的代码在Objects/iterobject.c中:
static PyObject *
iter_iternext(PyObject *iterator)
{
seqiterobject *it;
PyObject *seq;
PyObject *result;
assert(PySeqIter_Check(iterator));
it = (seqiterobject *)iterator;
seq = it->it_seq;
if (seq == NULL)
return NULL;
result = PySequence_GetItem(seq, it->it_index);
if (result != NULL) {
it->it_index++;
return result;
}
if (PyErr_ExceptionMatches(PyExc_IndexError) ||
PyErr_ExceptionMatches(PyExc_StopIteration))
{
PyErr_Clear();
Py_DECREF(seq);
it->it_seq = NULL;
}
return NULL;
}
Run Code Online (Sandbox Code Playgroud)
在Objects/abstract.c中:
int
PySequence_Check(PyObject *s)
{
if (s == NULL)
return 0;
if (PyInstance_Check(s))
return PyObject_HasAttrString(s, "__getitem__");
if (PyDict_Check(s))
return 0;
return s->ob_type->tp_as_sequence &&
s->ob_type->tp_as_sequence->sq_item != NULL;
}
Run Code Online (Sandbox Code Playgroud)
__iter__是迭代可迭代对象的首选方式。如果未定义,解释器将尝试使用__getitem__. 看看这里