python基础学习笔记(十一)
2013-05-14 23:31 虫师 阅读( ... ) 评论( ... ) 编辑 收藏
迭代器
本节进行迭代器的讨论。只讨论一个特殊方法 ---- __iter__ ,这个方法是迭代器规则的基础。
迭代器规则
迭代的意思是重复做一些事很多次 --- 就像在循环中做的那样。 __iter__ 方法返回一个迭代器,所谓迭代器就是具有 next 方法的对象,在调用 next 方法时,迭代器会返回它的下一个值。如果 next 方法被调用,但迭代器没有值可以返回,就会引发一个 StopIteration 异常。
这里是一个婓波那契数例,使用迭代器如下:
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:
if
f > 1000
:
print
f
break
#
因为设置了break ,所以循环在这里停止。
1597
内建函数 iter 可以从可迭代的对象中获得迭代器。
>>> it = iter([1,2,3
])
>>>
it.next()
1
>>>
it.next()
2
从迭代器得到序列
除了在迭代器和可迭代对象上进行迭代外,还能把它们转换为序列。在大部分能使用序列的情况下,能使用迭代器替换。
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()
>>>
list(ti)
[
1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
生成器
生成器也叫 简单生成器,生成器可以帮助读者写出非常优雅的代码,当然,编写任何程序时不使用生成器也是可以的。
创建生成器
创建一个生成器就像创建函数一样简单。
>>>
def
flatten(nested):
for
sublist
in
nested:
for
element
in
sublist:
yield
element
>>> nested = [[1,2],[3,4],[5
]]
#
使用for循环
>>>
for
num
in
flatten(nested):
print
num
1
2
3
4
5
#
或使用list函数
>>>
list(flatten(nested))
[
1, 2, 3, 4, 5]
递归生成器
上面创建的生成器只能处理两层嵌套,为了处理嵌套使用了两个 for 循环,如果要处理任意层的嵌套呢?例如,可以每层嵌套需要增加一个 for 循环,但不知道有几层嵌套,所以必须把解决方案变得更灵活,现在可以用递归来解决。
>>>
def
fla(aa):
try
:
for
bb
in
aa:
for
cc
in
fla(bb):
yield
cc
except
TypeError:
yield
aa
>>> list(fla([[[1],2],3,4,[5,[6,7]],8]))
#
注意括号层次比较多
[1, 2, 3, 4, 5, 6, 7, 8]
当 fla 被调用时有两种情况: 基本情况和需要递归的情况
在基本的情况中,函数被告知展开一个元素,这种情部下, for 循环会引发一个 TypeError 异常,生成会产生一个元素。
如果展开的是一个列表,那么就需要特殊情况处理。程序必须遍历所有的子列表,并对它们调用 fla 。
-------------------
上面的做法有一个问题:如果 aa 是一个类似于字符串的对象(字符串、 Unicode 、 UserString 等),那么它就是一个序列,不会引发 TypeError ,但是你不想对这样的对象进行迭代。
为了处理这种情况,则必须在生成器的开始处添加一个检查语句。试着将传入的对象和一个字符串拼接,看看会不会出现 TypeError ,这是检查一个对象是不是类似于字符串最简单快速的方法。
>>>
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
>>> list(flatten([
'
foo
'
,[
'
bar
'
,[
'
baz
'
]]]))
[
'
foo
'
,
'
bar
'
,
'
baz
'
]
如果 nested+ ’’ 引发了一个 TypError ,它就会被忽略。如果没有引发 TypeError ,那么内层 try 语句就会引发一个它自己的 TypeError 异常。
生成器方法
生成器新属性是在开始运行后为生成器提供值的能力。表现为生成器和“外部世界”进行交流的渠道:
* 外部作用域访问生成器的 send 方法,就像访问 next 方法一样,只不过前者使用一个参数(发送的“消息” --- 任意对象)
* 在内部则挂起生成器, yield 现在作为表达式而不是语句使用,换句话说,当生成器重新运行的时候, yield 方法返回一个值,也就是外部通过 send 方法发送的值。如果 next 方法被使用,那么 yield 方法返回 None.
下面简单的方例子来说明这种机制:
>>>
def
repeater(value):
while
True:
new
=(
yield
value)
if
new
is
not
None:value =
new
>>> r = repeater(42
)
>>>
r.next()
42
>>> r.send(
"
hello, world!
"
)
'
hello, world!
'
生成器的另两个方法:
* throw 方法(使用异常类型调用,还有可选的值以及回溯对象)用于在生成器内引发一个异常(在 yield 表达式中)
* close 方法(调用时不用参数)用于停止生成器。

