几个基本概念在正式开始前先补充一些基本概念在 Python 中存在容器 与 可迭代对象
- 容器:用来存储多个元素的数据结构,例如 列表,元组,字典,集合等内容;
- 可迭代对象:实现了 iter 方法的对象就叫做可迭代对象。
从可迭代对象中还衍生出 迭代器 与 生成器:
- 迭代器:既实现了 iter,也实现了 next 方法的对象叫做迭代器;
-
1 迭代与循环
迭代是Python最重要的功能之一。
最常见的迭代形式是循环一个序列(字符串、列表、元组、字典等)的所有成员。
循环语句用于实现迭代,最常见的语句是for语句。for n in [1,2,3,4,5,6,7,8,9]:print ("2 to the %d power is %d " % (n,2**n))
str1="Hello,World."for ch in str1:print(ch)
scores = {"chinese": 90, "English": 88, "Math": 100}for key in scores:print(key,scores[key])
如果for语句迭代的对象都是静态的,可能导致无法实现或者系统资源的大量消耗。可以创建自定义的迭代对象或者生成器函数来创建迭代的序列。
2 迭代器对象
2.1 迭代器对象的概念
迭代器(Iterator)是访问集合内元素的一种方式,提供了一种遍历序列对象的方法。用来迭代操作对象,可以像列表一样,迭代的获取其中的每一个元素,任何实现了next方法的对象,都可以称之为迭代器。
迭代器的特点 iter方法返回迭代器本身;
- next()方法返回容器的下一个元素
- 当没有下一个元素时,会报出StopIteration异常
- 用户不关心迭代器的内部细节,只需要通过next这个特定的接口获得数据
- 不能随机访问迭代器中的某个值,只能从头到尾依次访问
- 不能回退
- 便于循环比较的数据集合,节省内存
迭代器与列表的区别
构建迭代器的时候,不需要像列表一样,把所有的元素一次性加载到内存,而是通过使用延迟计算(lazy evaluation)的方式返回元素,这是迭代器的优点之一。
举例:如果一个列表包含一千万个整数,需要占用400M的内存,如果使用迭代器,只需要几十字节的内存。因为迭代器没有把所有元素加载到内存,而是调用迭代器的next方法时才返回该元素。
alist=[1,2,3,4]it=iter(alist)print(it)print(next(it))print(next(it))print(next(it))print(next(it))#print(next(it))
说明:
(1)iter() 函数是python内置函数用来生成迭代器 ,返回一个迭代器对象。
(2)next()函数是Python内置函数, 返回迭代器的下一个项目。next() 函数要和生成迭代器的 iter() 函数一起使用。
alist=[1,2,3,4]it = iter(alist)while True:try:x = next(it)print(x)except StopIteration:# 遇到StopIteration就退出循环break
alist=[1,2,3,4]it = iter(alist)for x in it:print(x)
不是所有对象都是可迭代的,可以通过isinstance()判断一个对象是否是一个迭代器,是否可以迭代。
from collections.abc import Iterator,Iterable#从colletcions.abc包中导入Iterator和Iterable类alist=[1,2,3,4]it = iter(alist)#iter函数把alist列表容器转换成了迭代器对象for x in it:print(x)print(isinstance(alist,Iterator))#isinstance函数用来判断alist是不是一个Iterator类对象。print(isinstance(alist,Iterable))#isinstance函数用来判断alist是不是一个Iterable类对象。print(isinstance(it,Iterator))print(isinstance(it,Iterable))c=999print(isinstance(c,Iterator))print(isinstance(c,Iterable))
2.2 使用itertools获得迭代器
itertools,是python的一个内置模块,功能强大,主要用于高效循环创建迭代器。注意一点,他返回的不是list,而是iterator
itertools主要来分为三类函数,分别为无限迭代器、输入序列迭代器、组合生成器。
常用迭代器生成函数简介
1 Itertools.count(start=0, step=1)
创建一个迭代对象,生成从start开始的连续整数,步长为step。
如果省略了start则默认从0开始,步长默认为1
如果超过了sys.maxint,则会移除并且从-sys.maxint-1开始计数。
from itertools import *for i in count(1):print(i)
from itertools import *for i in count(1):if i>10:breakelse:print(i)
2、Itertools.cycle(iterable)
创建一个迭代对象,对于输入的iterable的元素反复执行循环操作,内部生成iterable中的元素的一个副本,这个副本用来返回循环中的重复项。
from itertools import *i = 0for item in cycle(['a', 'b', 'c']):i += 1if i == 10:breakprint (i, item)
3、Itertools.repeat(object[, times])
创建一个迭代器,重复生成object,如果没有设置times,则会无线生成对象。
from itertools import *for i in repeat('kivinsae', 5):print(i)
2.3 自定义迭代器
要创建一个对象/类作为迭代器,必须实现iter()和next()方法。
正如在Python 类和对象一章中所了解的那样,所有类都有一个名为init()的函数,该函数可以在创建对象时进行一些初始化。
iter()方法的行为类似,可以执行操作(初始化等),但必须始终返回迭代器对象本身。
next()方法还允许你进行操作,并且必须返回序列中的下一项。
class MyNumbers:def __iter__(self):self.a = 1return selfdef __next__(self):x = self.aself.a += 1return xmyclass = MyNumbers()myiter = iter(myclass)print(next(myiter))print(next(myiter))print(next(myiter))print(next(myiter))print(next(myiter))
2.4 迭代器应用的例子
def fib(n):if (n == 1):return [1]if(n == 2):return [1, 1]fibs = [1, 1]i=2while i<n:fibs.append(fibs[i-1] + fibs[i-2])i=i+1return fibsprint(fib(15))
def fib(n):#fib函数用来求取斐波那契数列的第n项if (n == 1) or (n == 2):return 1return fib(n - 1) + fib(n - 2)#fib函数直接或者间接调用了它自己,则这种调用称为递归调用i=1while i<=15:print(fib(i),end=" ")i=i+1print()
def fib(n):a, b = 1, 1for i in range(n - 1):a, b = b, a + breturn ai=1while i<=15:print(fib(i),end=" ")i=i+1
3 生成器(函数)
生成器本质上也是迭代器,不过它比较特殊。
以 list 容器为例,在使用该容器迭代一组数据时,必须事先将所有数据存储到容器中,才能开始迭代;而生成器却不同,它可以实现在迭代的同时生成元素。
也就是说,对于可以用某种算法推算得到的多个数据,生成器并不会一次性生成它们,而是什么时候需要,才什么时候生成。
不仅如此,生成器的创建方式也比迭代器简单很多,大体分为以下 2 步:
- 定义一个以 yield 关键字标识返回值的函数;
- 调用刚刚创建的函数,即可创建一个生成器。
```python
def intNum():
print(“开始执行”)
for i in range(5):
yield iprint("继续执行")
num = intNum() print(“num=”,next(num)) print(“num=”,next(num)) print(“num=”,next(num)) print(“num=”,next(num))
由此,我们就成功创建了一个 num 生成器对象。显然,和普通函数不同,intNum() 函数的返回值用的是 yield 关键字,而不是 return 关键字,此类函数又成为生成器函数。<br />和 return 相比,yield 除了可以返回相应的值,还有一个更重要的功能,即每当程序执行完该语句时,程序就会暂停执行。不仅如此,即便调用生成器函数,[Python](http://c.biancheng.net/python/) 解释器也不会执行函数中的代码,它只会返回一个生成器(对象)。<br />要想使生成器函数得以执行,或者想使执行完 yield 语句立即暂停的程序得以继续执行,有以下 2 种方式:- 通过生成器(上面程序中的 num)调用 next() 内置函数或者 __next__() 方法;- 通过 for 循环遍历生成器。生成器的练习题<br />**问题 1:输入一个数字 n,写一个程序判断 0 到 n 之间的偶数,并用逗号分隔来输出。**<br />比如输入:10<br />输出结果:0,2,4,6,8,10<br />题目分析<br />我们首先需要一个循环,找到 10 以内的所有数字,然后判断是否是偶数。题目要求用生成器的方式,我们只需要写一个生成器函数,在找到符合条件的数字后,使用 yield 输出。最后直接循环生成器,找到需要的值放入列表,最后用逗号分隔输出即可。```pythondef EvenGenerator(n):i = 0while i <= n:if i%2 == 0:yield ii += 1n = int(input())values = []for i in EvenGenerator(n):values.append(str(i))print(",".join(values))
问题2:输入一个数字 n,写一个程序判断 0 到 n 之间的可以同时被 5 和 7 整除的数字,并用逗号分隔来输出。
比如输入:100
输出结果:
0,35,70
题目分析
此题目和上一个类似,你会发现这一次只是核心判断条件有变化,输入和输出不一样,但其实套路没变,还是用一个生成器函数,对应条件的地方用 yield 把数据返回即可。
def NumGenerator(n):for i in range(n+1):if i%5 == 0 and i%7 == 0:yield in = int(input())values = []for i in NumGenerator(n):values.append(str(i))print(",".join(values))
