Python随记(18) 迭代器 生成器(yield)生成器表达式

迭代器

每一次重复的过程被称作一次迭代,每一次迭代得到的结果会被用作下一次迭代的初值,而提供迭代方法的容器就是迭代器。列表,元组,字符,字典都是迭代器。
关于迭代有两个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()
发布了25 篇原创文章 · 获赞 0 · 访问量 296

猜你喜欢

转载自blog.csdn.net/weixin_46192930/article/details/105041252