被python这一时代语言的迭代器iterator
和生成器generator
的特性时给深深吸引了。虽然还没看完和理解这些新特性,但还是忍不住激动的心情分享现在的所得。撇去目录式写法,这次使用代码来说明。
p.s.1 默认使用python3.x,以及新式类的写法
__metaclass__ = type
p.s.2 使用经典的斐波那契数列
来说明吧
简单版,直接打印版
def Fib(maxN = 10):
a, b = 0, 1
for i in range(maxN):
a, b = b, a + b
print(a)
Fib(10)
此版本问题:print会导致函数复用性差
简单版,返回一个list
def Fib(maxN = 10):
a, b = 0, 1
retList = []
for i in range(maxN): # 循环在函数内部完成
a, b = b, a + b
retList.append(a) # list.append()代替print
return retList
fib = Fib(10)
print(fib)
此版本问题:随着maxN的增大,函数的临时变量retList也会随之变大占用大量内存
迭代器版,iterator
关键字: iter, next
class Fibs:
def __init__(self, maxN = 10):
self.a = 0
self.b = 1
self.maxN = maxN
self.i = 0
def __iter__(self):
return self
def __next__(self):
if self.i < self.maxN: # if代替for循环,作为迭代判断的条件
self.i += 1
(self.a, self.b) = (self.b, self.a + self.b)
return self.a # __next__中需要return
raise StopIteration()
fibs = Fibs(10)
f = []
for i in fibs:
f.append(i)
print(f)
此版本优势:每次迭代内存只产生一个迭代值
此版本问题:语句稍显啰嗦
生成器版,generator
关键字:yield
def fib(maxN = 10):
a, b = 0, 1
for i in range(maxN):
a, b = b, a + b
yield a
f = []
for i in fib(10):
f.append(i)
print(f)
此版本原理:调用生成器函数fib()是不会执行这个函数的,而是返回一个iterable对象
当在for循环时,每次循环才会执行一次fib内部的代码。而执行到yield时,函数就返回一个迭代值
。下次迭代时,代码从yield的下一条语句继续执行
犹如冻结
和解冻
生成器generator的理解
generator的优点:
- 即保持iterator特性
- 但又能简洁表达函数
保持iterator特性可从下述代码中窥见一斑
f3 = fib(3)
try:
print(f3.__next__())
print(f3.__next__())
print(f3.__next__())
print(f3.__next__())
except StopIteration:
print("reach StopIteration")