python新手入门学习30 迭代器 生成器 如何实现循环细致剖析

1、两个常用的迭代器内置函数

迭代:每一次迭代的结果被当作下一次迭代的初始值
迭代只是实现了next的一个对象,可以理解为具有指向下一项功能的指针

iter(),表示获取该函数的迭代器
next(),表示返回该迭代器的下一个值

也就是for循环实现迭代的原理

实例:

string = 'abcdefg'
it  =iter(string)
next(it)
  
  运行:
>>> next(it)
'b'
>>> next(it)
'c'
>>> next(it)
'd'
>>> next(it)
'e'
>>> next(it)
'f'
>>> next(it)
'g'
>>> next(it)				#当到达迭代器的最后之后会返回一个StopIteration
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    next(it)
StopIteration
>>>     

例如:用迭代器实现for循环 打印的功能

mylist = range(5)
it = iter(mylist)			#获取函数mylist的迭代器(指针)

while True:
    try:
        print(next(it))		#返回该指针指向的下一个数据

    except StopIteration:
        break
        

2、相应的迭代器函数也对应着魔法方法

__iter__()
__next__()

1、用迭代器实现斐波那契数列的输出

class Fibs:
    def __init__(self,n=10):
        self.a = 0
        self.b = 1
        self.n =n

    def __iter__(self):
        return self

    def __next__(self):
        self.a,self.b = self.b,self.a+self.b
        if self.a>self.n:
            raise StopIteration
        return self.a
    

运行:
>>> fibs =Fibs()
>>> for each in fibs:
	print(each)

	
1
1
2
3
5
8
>>> 

2、用迭代器实现闰年的输出

import datetime as dt

class LeapYear:
    def __init__(self):
        self.now  = dt.date.today().year	#调用datetime模块的函数返回当前的年份作为上限

    def isLeapYear(self,year):				#判断是否是闰年
        if (year%4 ==0 and year%100 != 0) or (year%400==0):
            return True
        else:
            return False

    def __iter__(self):					#表示获取类的实例的迭代器
        return self

    def __next__(self):
        while not self.isLeapYear(self.now):
            self.now -= 1

        temp = self.now
        self.now -=1

        return temp
        print(temp)

运行:
>>> for i in leapyear:
	if i>=2000:
		print(i)
	else:
		break

	
2016
2012
2008
2004
2000

3、用迭代器实现字符串翻转

class MyRev():
     def __init__(self,data):
         self.data = data
         self.index = len(data)


     def __iter__(self):
         return self

     def __next__(self):
         if self.index ==0:
             raise StopIteration

         self.index = self.index - 1
         return self.data[self.index]
       
运行:         
>>>myrev = MyRev()
>>>for i in myrev():
    print(i)
         

二、生成器 generater

最大的作用是节约内存空间,如果一个很长的列表,如果每一个都显示出来存储就非常的占空间,此时利用生成器的原理,不算出来,而是将他存储在一个表达式里,需要时算出来。所以大部分时候生成器会和next()混在一起,但为了更简便,一般生成器是用for循环实现的。

g = (x * x for x in range(10))
for n in g:
    print(n)

运行:
0
1
4
9
16
25
36
49
64
81

1、作用:yeild 控制程序中断挂起或者继续
如何理解yeild?相当于return和next()的混合
函数执行到yeild后,此时相当于return,也就是返回yeild后面的那个数,然后程序结束
当再次运行,比如next(),这一次开始的地方是接着上一次的停止的地方执行的。

def Mydemo():
    print('我是生成器')
    yield 1
    print('我是第2步')
    yield 2

>>> c = Mydemo()
>>> next(c)
我是生成器
1				#此时相当于一个return,返回1,结束。
>>> next(c)		#next()程序继续从上次借宿的地方开始,打印出了我是第2步,接着又停在了yeild
我是第22
>>> next(c)
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    next(c)
StopIteration
>>> 

2、用生成器实现字符串翻转

def myRev(data):
     for index in range(len(data)-1,-1,-1):		#range的范围是[len(data)-1,-1],每次减少的步长是1
          yield data[index]						#相当于return data[index]

运行:
>>> for i in myRev('today'):			#这个for循环打印myRev里面全部的字符
	print(i,end = '')

	
yadot
def libs():
    a = 0
    b = 1
    while True:
        a,b = b,a+b
        yield a					#生成器将值返回至a并暂停
        

>>> for each in libs():
	if each >100:
		break
	print(each,end=' ')
		
1 1 2 3 5 8 13 21 34 55 89 
>>> 

2、生成器的推导式

a = [i for i in range(50) if not (i%2) and i%3]			#列表推导式
print(a)
b = {i:i%2==0 for i  in range(5)}						#字典推导式
print(b)
c = (i for i in range(10))								#生成器推导式,not 元组推导式
print(c)

[2, 4, 8, 10, 14, 16, 20, 22, 26, 28, 32, 34, 38, 40, 44, 46]
{0: True, 1: False, 2: True, 3: False, 4: True}
<generator object <genexpr> at 0x0000026B995A7F48>


>>> next(c)
0
>>> next(c)
1
>>> next(c)
2
>>> next(c)
3
>>> next(c)
4
>>> next(c)
5
>>> next(c)
6
>>> 

3、用生成器实现素数求和

import math

def is_prime(number):				#判断是否是素数
    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语句前后加几个标记点就明白了。如下补充
            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()
运行:
142913828922


#关于判断如何循环,加一个打印
def get_primes(number):		
    while True:
        if is_prime(number):	
            print('标点三')
            yield number
            print('标点四')
        number += 1

def solve():					
    total = 2
    for next_prime in get_primes(3):
        if next_prime < 10:
            total += next_prime
        else:
            print(total)
            return
        print('第一次循环结束')

运行:
标点三				#1、solve里面的for循环,第一次循环时,get_primes(3)会跳到get_primes函数,打印标点三
第一次循环结束		#2、在get_primes里面的if成立时,执行yield number之后,程序会返回到solve里面的for循环中调用它的地方,继续循环,直至循环结束
标点四				#3、在for循环的第一次循环结束之后,程序会跳回yield number这里,然后才开始执行number += 1,后面依次继续循环
标点三
第一次循环结束
标点四
标点三
第一次循环结束
标点四
标点三
17
发布了70 篇原创文章 · 获赞 5 · 访问量 3520

猜你喜欢

转载自blog.csdn.net/qq_42647903/article/details/102652737