构建一个基本的Python迭代器
如何在python中创建迭代函数(或迭代器对象)?
python中的迭代器对象符合迭代器协议,这意味着它们提供了两种方法: __iter__()
和next()
。 __iter__
返回迭代器对象,并在循环开始时隐式调用。 next()
方法返回下一个值,并在每个循环增量中隐式调用。 next()
会在没有更多值返回时引发StopIteration异常,这是通过循环结构隐式捕获以停止迭代。
以下是一个简单的计数器示例:
class Counter:
def __init__(self, low, high):
self.current = low
self.high = high
def __iter__(self):
return self
def next(self): # Python 3: def __next__(self)
if self.current > self.high:
raise StopIteration
else:
self.current += 1
return self.current - 1
for c in Counter(3, 8):
print c
这将打印:
3
4
5
6
7
8
如前面的回答所述,使用生成器可以更轻松地进行编写:
def counter(low, high):
current = low
while current <= high:
yield current
current += 1
for c in counter(3, 8):
print c
打印的输出将是相同的。 在引擎盖下,生成器对象支持迭代器协议,并执行与类Counter类似的操作。
David Mertz的文章“迭代器和简单生成器”是非常好的介绍。
有四种方法来构建迭代函数:
__iter__
和__next__
(或Python 2.x中的next
)) __getitem__
) 例子:
# generator
def uc_gen(text):
for char in text:
yield char.upper()
# generator expression
def uc_genexp(text):
return (char.upper() for char in text)
# iterator protocol
class uc_iter():
def __init__(self, text):
self.text = text
self.index = 0
def __iter__(self):
return self
def __next__(self):
try:
result = self.text[self.index].upper()
except IndexError:
raise StopIteration
self.index += 1
return result
# getitem method
class uc_getitem():
def __init__(self, text):
self.text = text
def __getitem__(self, index):
result = self.text[index].upper()
return result
要查看所有四种实际操作方法:
for iterator in uc_gen, uc_genexp, uc_iter, uc_getitem:
for ch in iterator('abcde'):
print ch,
print
其结果是:
A B C D E
A B C D E
A B C D E
A B C D E
注意 :
两种生成器类型( uc_gen
和uc_genexp
)不能reversed()
; 普通迭代器( uc_iter
)将需要__reversed__
魔法方法(它必须返回一个新的迭代器向后); 并且getitem可迭代( uc_getitem
)必须具有__len__
魔法方法:
# for uc_iter
def __reversed__(self):
return reversed(self.text)
# for uc_getitem
def __len__(self)
return len(self.text)
要回答Panic上校关于无限懒惰评估迭代器的第二个问题,下面是使用上述四种方法中的每一种的例子:
# generator
def even_gen():
result = 0
while True:
yield result
result += 2
# generator expression
def even_genexp():
return (num for num in even_gen()) # or even_iter or even_getitem
# not much value under these circumstances
# iterator protocol
class even_iter():
def __init__(self):
self.value = 0
def __iter__(self):
return self
def __next__(self):
next_value = self.value
self.value += 2
return next_value
# getitem method
class even_getitem():
def __getitem__(self, index):
return index * 2
import random
for iterator in even_gen, even_genexp, even_iter, even_getitem:
limit = random.randint(15, 30)
count = 0
for even in iterator():
print even,
count += 1
if count >= limit:
break
print
其结果(至少对我的样本运行):
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 52 54
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30
0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32
首先,itertools模块对于迭代器会很有用的各种情况都非常有用,但是您需要在python中创建一个迭代器:
产量
这不是很酷吗? 产量可以用来取代函数中的正常返回 。 它返回的对象是一样的,但不是销毁状态并退出,而是为了当你想执行下一次迭代时保存状态。 下面是一个直接从itertools函数列表中拉出来的例子:
def count(n=0):
while True:
yield n
n += 1
正如函数描述中所述(它是itertools模块的count()函数...),它会生成一个迭代器,它返回从n开始的连续整数。
发生器表达式是一个完整的蠕虫(真棒蠕虫!)。 它们可以用来代替列表理解来节省内存(列表解析在内存中创建一个列表,如果没有分配给一个变量,它将在使用后被销毁),但是生成器表达式可以创建一个生成器对象...这是一种奇特的方式说迭代器)。 这是一个生成器表达式定义的例子:
gen = (n for n in xrange(0,11))
这与我们上面的迭代器定义非常相似,除了整个范围预定在0和10之间。
我刚刚发现xrange() (惊讶我以前没见过......)并将其添加到上面的示例中。 xrange()是range()的可迭代版本,其优点是不会预建列表。 如果你有一个巨大的数据集来迭代,并且只有很多内存来完成它,那将是非常有用的。
链接地址: http://www.djcxy.com/p/5139.html上一篇: Build a Basic Python Iterator
下一篇: How to import an SQL file using the command line in MySQL?