迭代器
每一次重复的过程被称作一次迭代,每一次迭代得到的结果会被用作下一次迭代的初值,而提供迭代方法的容器就是迭代器。列表,元组,字符,字典都是迭代器。
关于迭代有两个BIF: iter() next() 对一个容器对象调用iter()就得到它的迭代器,调用next()就会返回下一个值。若迭代器没有值就可以返回,抛出一个StopIteration异常
it = iter('hello')
while 1:
try:
each = next(it)
except StopIteration:
break
print(each,end=' ')
>>> h e l l o
是不是很像for的作用。
实现迭代器的方法就是__iter_() __next_(),一个容器如果时迭代器,就必须实现__iter_()方法,这个方法实际上就是返回迭代器本身,而__next_()决定迭代的规则。
class MyNumbers:
def __iter__(self):
self.a = 1
return self
def __next__(self):
if self.a <= 20:
x = self.a
self.a += 1
return x
else:
raise StopIteration
a=MyNumber()
for x in a:
print(x)
生成器
生成器其实时迭代器的一种实现。生成器是为了让代码更加简洁,迭代器需要我们去定义一个类和实现的相关方法,而生成器只需要在普通的函数上加一个 yield 语句 。另外生成器的出现时python模仿协同程序的概念得以实现。就是可以运行的独立函数的调用,函数可以挂起,并在需要的时候从程序离开的地方继续或重新开始。
对于普通的函数,从第一行代码开始到return 异常 或执行完毕结束。一旦函数将控制权交还给调用者,函数中所做的工作和保存在局部变量中的数据都会丢失,再次调用一切都会从头再来。
所以通过生成器将函数暂时挂起,保留函数的局部变量等数据,再次调用时从上次暂停的位置继续执行。执行到 yield 时, 函数就返回一个迭代值,下次迭代时,代码从 yield 的下一条语句继续执行,而函数的本地变量看起来和上次中断执行前是完全一样的,于是函数继续执行,直到再次遇到 yield。
>>> def A():
print('我是生成器')
yield 1
yield 2
>>> a = A()
>>> next(a)
我是生成器
1
>>> next(a)
2
>>> next(a)
Traceback (most recent call last):
File "<pyshell#31>", line 1, in <module>
next(a)
StopIteration
在一个 generator function 中,如果没有 return,则默认执行至函数完毕,如果在执行过程中 return,则直接抛出 StopIteration 终止迭代。
生成器表达式
列表推导式[i for i in range(100) if not (i%2) and (i%3)]
求一百以内能被2整除但不能被3整除的数
字典推导式{i : i%2 == 0 for i in range(10)} >>>{0:True,1:False,2:True,3:False,....}
是二的倍数就是True。
集合推导式{i for i in [1,1,2,3,3,4,5,5,5]} >>>{1,2,3,4,5}
生成器表达式 (i for i in range(10))
a=(i for i in range(10))
>>> a
<generator object <genexpr> at 0x000001B27694A120>
>>> next(a)
0
>>> next(a)
1
sum(i for i in range(100) if i%2)
>>>2500 #将生成器表达式作为函数的参数使用,可以直接写推导式,不用加小括号。。。
- 运用列表生成式,可以写出非常简洁的代码。例如,列出当前目录下的所有文件和目录名,可以通过一行代码实现:
[x for x in os.listdir('.')]
- for循环其实可以同时使用两个甚至多个变量,比如dict的items()可以同时迭代key和value
[k + '=' + v for k, v in d.items()]
练习
写个功能和reversed()功能相同的类
class A:
def __init__(self,date):
self.date = date
self.index = len(date)
def __iter__(self):
return self
def __next__(self):
if self.index == 0:
raise StopIteration
self.index -= 1
return self.date[self.index]
a=A('love')
for i in a:
print(i,end=' ') >>>e v o l
def myRev(data): #生成器的例子,是不是简洁很多
for index in range(len(data)-1, -1, -1):
yield data[index]
10 以内的素数之和是:2 + 3 + 5 + 7 = 17,那么请编写程序,计算 2000000 以内的素数之和?如果你的策略是将 2000000 以内的所有素数找到并存放到一个列表中,再依次进行求和计算,那么这个列表极有可能会撑爆你的内存。所以这道题就必须用到生成器来实现啦。
import math
def is_prime(number): #大佬的思路就是nb。。。
if number > 1:
if number == 2:
return True
if number % 2 == 0:
return False
for current in range(3, int(math.sqrt(number) + 1), 2):
if number % current == 0:
return False
return True
return False
def get_primes(number):
while True:
if is_prime(number):
yield number
number += 1
def solve():
total = 2
for next_prime in get_primes(3):
if next_prime < 2000000:
total += next_prime
else:
print(total)
return
if __name__ == '__main__':
solve()