在 for 循环上下文中使用列表理解或in
关键字时,即:
for o in X:
do_something_with(o)
或者
l=[o for o in X]
- 背后的机制如何
in
运作? - 它调用了哪些函数\方法
X
? - 如果
X
可以遵守不止一种方法,优先级是什么? - 如何编写一个高效的
X
,以便列表理解会很快?
在 for 循环上下文中使用列表理解或in
关键字时,即:
for o in X:
do_something_with(o)
或者
l=[o for o in X]
in
运作?X
?X
可以遵守不止一种方法,优先级是什么?X
,以便列表理解会很快?的,afaik,完整和正确的答案。
for
,在 for 循环和列表推导中,都调用iter()
. 如果有方法或方法,将返回一个可迭代的。如果它同时实现,则使用。如果它既没有你得到。X
iter()
X
__iter__
__getitem__
__iter__
TypeError: 'Nothing' object is not iterable
这实现了一个__getitem__
:
class GetItem(object):
def __init__(self, data):
self.data = data
def __getitem__(self, x):
return self.data[x]
用法:
>>> data = range(10)
>>> print [x*x for x in GetItem(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
这是一个实现的例子__iter__
:
class TheIterator(object):
def __init__(self, data):
self.data = data
self.index = -1
# Note: In Python 3 this is called __next__
def next(self):
self.index += 1
try:
return self.data[self.index]
except IndexError:
raise StopIteration
def __iter__(self):
return self
class Iter(object):
def __init__(self, data):
self.data = data
def __iter__(self):
return TheIterator(data)
用法:
>>> data = range(10)
>>> print [x*x for x in Iter(data)]
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
如您所见,您既需要实现迭代器,又__iter__
需要返回迭代器。
您可以将它们组合起来:
class CombinedIter(object):
def __init__(self, data):
self.data = data
def __iter__(self):
self.index = -1
return self
def next(self):
self.index += 1
try:
return self.data[self.index]
except IndexError:
raise StopIteration
用法:
>>> well, you get it, it's all the same...
但是你一次只能有一个迭代器。好的,在这种情况下,您可以这样做:
class CheatIter(object):
def __init__(self, data):
self.data = data
def __iter__(self):
return iter(self.data)
但这是作弊,因为你只是在重用__iter__
. list
一个更简单的方法是使用yield,并制作__iter__
成一个生成器:
class Generator(object):
def __init__(self, data):
self.data = data
def __iter__(self):
for x in self.data:
yield x
最后一种是我推荐的方式。简单高效。
X
必须是可迭代的。它必须实现__iter__()
which 返回一个迭代器对象;迭代器对象必须实现next()
,每次调用时返回下一项,StopIteration
如果没有下一项则引发 a 。
列表、元组和生成器都是可迭代的。
请注意,普通for
运算符使用相同的机制。
回答问题的评论我可以说在这种情况下阅读来源并不是最好的主意。对于第一次看到 Python 源代码的人来说,负责执行编译代码 ( ceval.c ) 的代码似乎不是很冗长。这是代表 for 循环中迭代的代码段:
TARGET(FOR_ITER)
/* before: [iter]; after: [iter, iter()] *or* [] */
v = TOP();
/*
Here tp_iternext corresponds to next() in Python
*/
x = (*v->ob_type->tp_iternext)(v);
if (x != NULL) {
PUSH(x);
PREDICT(STORE_FAST);
PREDICT(UNPACK_SEQUENCE);
DISPATCH();
}
if (PyErr_Occurred()) {
if (!PyErr_ExceptionMatches(
PyExc_StopIteration))
break;
PyErr_Clear();
}
/* iterator ended normally */
x = v = POP();
Py_DECREF(v);
JUMPBY(oparg);
DISPATCH();
要找到这里实际发生的事情,您需要深入研究一堆其他文件,这些文件的详细程度并没有好多少。因此,我认为在这种情况下,文档和诸如 SO 之类的网站是首选,而应仅检查源代码以获取未发现的实现细节。
X
必须是一个可迭代的对象,这意味着它需要有一个__iter__()
方法。
因此,要开始for..in
循环或列表推导,首先调用 firstX
的__iter__()
方法来获取迭代器对象;然后为每次迭代调用该对象的next()
方法,直到StopIteration
引发,此时迭代停止。
我不确定您的第三个问题是什么意思,以及如何为您的第四个问题提供有意义的答案,除非您的迭代器不应一次在内存中构建整个列表。
也许这会有所帮助(教程http://docs.python.org/tutorial/classes.html第 9.9 节):
在幕后,for 语句在容器对象上调用 iter()。该函数返回一个迭代器对象,该对象定义了 next() 方法,该方法一次访问容器中的一个元素。当没有更多元素时,next() 会引发一个 StopIteration 异常,告诉 for 循环终止。
要回答您的问题:
背后的机制是如何运作的?
正如其他人已经指出的那样,它与用于普通 for 循环的机制完全相同。
它调用了 X 中的哪些函数\方法?
正如下面的评论中所指出的,它调用iter(X)
获取迭代器。如果定义X
了方法函数__iter__()
,则调用 this 以返回迭代器;否则,如果X
定义了__getitem__()
,这将被重复调用以迭代X
。请参阅iter()
此处的 Python 文档:http: //docs.python.org/library/functions.html#iter
如果 X 可以遵守不止一种方法,那么优先级是什么?
我不确定您的问题到底是什么,但是 Python 有关于如何解析方法名称的标准规则,并且在此处遵循它们。以下是对此的讨论:
如何编写一个高效的 X,以便列表理解很快?
我建议您阅读更多关于 Python 中的迭代器和生成器的内容。使任何类支持迭代的一种简单方法是为iter () 创建一个生成器函数。下面是对生成器的讨论: