您的位置:首页 > 编程语言 > Python开发

python~迭代器~生成器~

2015-10-22 16:27 549 查看
class Fibs:
def __init__(self):
self.a = 0
self.b = 1
def next(self):
self.a, self.b = self.b, self.a+self.b
return self.a
def __iter__(self):
return self

fibs = Fibs()
for f in fibs:
print f
if f>500:
break
print "**********Done!Tada!!**********"

这就是一个简单的斐波那契数列的迭代器。

所谓的迭代器就是具有next()方法的对象,在调用next方法时,迭代器会返回它的下一个值。如果next方法被调用但是迭代器没有值可以返回,就会引发一个stopIteration异常。

相比于列表,迭代器更加通用和优雅。如果有一个函数,可以一个接一个的计算值,那么在使用时就可以是计算一个值时获取一个值,而不是通过列表一次性获取所有值。如果有很多值,列表就会占用太多内存。class TestIterator:
value = 0
def next(self):
self.value += 1
if self.value > 10: raise StopIteration
return self.value
def __iter__(self):
return self

ti = TestIterator()
print list(ti)
print "**********Done!Tada!!**********"上面这段代码使用了异常来停止了迭代。输出结果如下:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

**********Done!Tada!!**********

下面来说说生成器:

任何包含yield的函数称为生成器。来看个栗子:

def flatten(nested):
for sublist in nested:
for element in sublist:
yield element

nested = [[1,2],[3,2],[1]]
print list(flatten(nested))
print "**********Done!Tada!!**********"

输出结果为:
[1, 2, 3, 2, 1]

**********Done!Tada!!**********

生成器函数可以返回多个值。每次产生一个值(yield语句),函数就会停住,停在那里等待被再次唤醒,然后继续从这一点开始运行。

但是上述生成器只能处理两层嵌套,如果要处理任意层的嵌套,则需要用到递归~

def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested

print list(flatten([[1],[[1,2],[1],[[1],2]]]))

print "**********Done!Tada!!**********"


输出结果:
[1, 1, 2, 1, 1, 2]

**********Done!Tada!!**********

代码的理解:当我们试图用for循环展开一个基本元素,比如数字的时候,就会引发typeerror异常,这时候,这个异常就会被except捕捉到,然后直接用yield语句把这个元素返回。

但是如果我们需要展开的是一个数组什么的,for循环就会正常的进行下去,然后检查这个数组的sublist是否还可以展开。如果不可以展开了,那么递归函数就会将sublist返回来,在上层函数中yield~如果可以展开,就会递归下去了blahblah~

但是如果上面的代码改成这样子:

def flatten(nested):
try:
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested

print list(flatten(['a','b','c']))

print "**********Done!Tada!!**********"

哥们儿你还敢运行一下不~不要怪我木有警告你喔~~
好吧,我告诉你喔,会导致无穷迭代的,因为一个字符串的第一个元素是一个长度为1的字符串,而长度为一的字符串的第一个元素就是字符串本身。

别着急别着急,下面这样写就好了:

def flatten(nested):
try:
try: nested+' '
except TypeError:pass
else:raise TypeError
for sublist in nested:
for element in flatten(sublist):
yield element
except TypeError:
yield nested

print list(flatten(['a',['b',['c']]]))

print "**********Done!Tada!!**********"

如果表达式
try: nested+' '

引发了一个TypeError,就会被忽略(表示此时nested不是一个字符串),如果没有引发的话(此时nested是一个字符串),那么就会自己引发一个TypeError异常。

总结一下:生成器是一个包涵yield关键字的函数,当它被调用时,在函数体中的代码不会被执行,而是会返回一个迭代器。每次请求一个值,就会执行生成器中的代码,直到遇到一个yield语句:意味着生成一个值。

ok~就酱紫啦~兔几要去吃果果了~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: