几个基本概念在正式开始前先补充一些基本概念在 Python 中存在容器 与 可迭代对象

  • 容器:用来存储多个元素的数据结构,例如 列表,元组,字典,集合等内容;
  • 可迭代对象:实现了 iter 方法的对象就叫做可迭代对象。

从可迭代对象中还衍生出 迭代器 与 生成器:

  • 迭代器:既实现了 iter,也实现了 next 方法的对象叫做迭代器;
  • 生成器:具有 yield 关键字的函数都是生成器。

    1 迭代与循环

    迭代是Python最重要的功能之一。
    最常见的迭代形式是循环一个序列(字符串、列表、元组、字典等)的所有成员。
    循环语句用于实现迭代,最常见的语句是for语句。

    1. for n in [1,2,3,4,5,6,7,8,9]:
    2. print ("2 to the %d power is %d " % (n,2**n))
    1. str1="Hello,World."
    2. for ch in str1:
    3. print(ch)
    1. scores = {"chinese": 90, "English": 88, "Math": 100}
    2. for key in scores:
    3. print(key,scores[key])

    如果for语句迭代的对象都是静态的,可能导致无法实现或者系统资源的大量消耗。可以创建自定义的迭代对象或者生成器函数来创建迭代的序列

    2 迭代器对象

    2.1 迭代器对象的概念

    迭代器(Iterator)是访问集合内元素的一种方式,提供了一种遍历序列对象的方法。用来迭代操作对象,可以像列表一样,迭代的获取其中的每一个元素,任何实现了next方法的对象,都可以称之为迭代器。
    迭代器的特点

  • iter方法返回迭代器本身;

  • next()方法返回容器的下一个元素
  • 当没有下一个元素时,会报出StopIteration异常
  • 用户不关心迭代器的内部细节,只需要通过next这个特定的接口获得数据
  • 不能随机访问迭代器中的某个值,只能从头到尾依次访问
  • 不能回退
  • 便于循环比较的数据集合,节省内存

迭代器与列表的区别
构建迭代器的时候,不需要像列表一样,把所有的元素一次性加载到内存,而是通过使用延迟计算(lazy evaluation)的方式返回元素,这是迭代器的优点之一。
举例:如果一个列表包含一千万个整数,需要占用400M的内存,如果使用迭代器,只需要几十字节的内存。因为迭代器没有把所有元素加载到内存,而是调用迭代器的next方法时才返回该元素。

  1. alist=[1,2,3,4]
  2. it=iter(alist)
  3. print(it)
  4. print(next(it))
  5. print(next(it))
  6. print(next(it))
  7. print(next(it))
  8. #print(next(it))

说明:
(1)iter() 函数是python内置函数用来生成迭代器 ,返回一个迭代器对象。
(2)next()函数是Python内置函数, 返回迭代器的下一个项目。next() 函数要和生成迭代器的 iter() 函数一起使用。

  1. alist=[1,2,3,4]
  2. it = iter(alist)
  3. while True:
  4. try:
  5. x = next(it)
  6. print(x)
  7. except StopIteration:
  8. # 遇到StopIteration就退出循环
  9. break
  1. alist=[1,2,3,4]
  2. it = iter(alist)
  3. for x in it:
  4. print(x)

不是所有对象都是可迭代的,可以通过isinstance()判断一个对象是否是一个迭代器,是否可以迭代。

  1. from collections.abc import Iterator,Iterable
  2. #从colletcions.abc包中导入Iterator和Iterable类
  3. alist=[1,2,3,4]
  4. it = iter(alist)
  5. #iter函数把alist列表容器转换成了迭代器对象
  6. for x in it:
  7. print(x)
  8. print(isinstance(alist,Iterator))
  9. #isinstance函数用来判断alist是不是一个Iterator类对象。
  10. print(isinstance(alist,Iterable))
  11. #isinstance函数用来判断alist是不是一个Iterable类对象。
  12. print(isinstance(it,Iterator))
  13. print(isinstance(it,Iterable))
  14. c=999
  15. print(isinstance(c,Iterator))
  16. 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开始计数。

  1. from itertools import *
  2. for i in count(1):
  3. print(i)
  1. from itertools import *
  2. for i in count(1):
  3. if i>10:
  4. break
  5. else:
  6. print(i)

2、Itertools.cycle(iterable)
创建一个迭代对象,对于输入的iterable的元素反复执行循环操作,内部生成iterable中的元素的一个副本,这个副本用来返回循环中的重复项。

  1. from itertools import *
  2. i = 0
  3. for item in cycle(['a', 'b', 'c']):
  4. i += 1
  5. if i == 10:
  6. break
  7. print (i, item)

3、Itertools.repeat(object[, times])
创建一个迭代器,重复生成object,如果没有设置times,则会无线生成对象。

  1. from itertools import *
  2. for i in repeat('kivinsae', 5):
  3. print(i)

2.3 自定义迭代器

要创建一个对象/类作为迭代器,必须实现iter()和next()方法。
正如在Python 类和对象一章中所了解的那样,所有类都有一个名为init()的函数,该函数可以在创建对象时进行一些初始化。
iter()方法的行为类似,可以执行操作(初始化等),但必须始终返回迭代器对象本身。
next()方法还允许你进行操作,并且必须返回序列中的下一项。

  1. class MyNumbers:
  2. def __iter__(self):
  3. self.a = 1
  4. return self
  5. def __next__(self):
  6. x = self.a
  7. self.a += 1
  8. return x
  9. myclass = MyNumbers()
  10. myiter = iter(myclass)
  11. print(next(myiter))
  12. print(next(myiter))
  13. print(next(myiter))
  14. print(next(myiter))
  15. print(next(myiter))

2.4 迭代器应用的例子

  1. def fib(n):
  2. if (n == 1):
  3. return [1]
  4. if(n == 2):
  5. return [1, 1]
  6. fibs = [1, 1]
  7. i=2
  8. while i<n:
  9. fibs.append(fibs[i-1] + fibs[i-2])
  10. i=i+1
  11. return fibs
  12. print(fib(15))
  1. def fib(n):
  2. #fib函数用来求取斐波那契数列的第n项
  3. if (n == 1) or (n == 2):
  4. return 1
  5. return fib(n - 1) + fib(n - 2)
  6. #fib函数直接或者间接调用了它自己,则这种调用称为递归调用
  7. i=1
  8. while i<=15:
  9. print(fib(i),end=" ")
  10. i=i+1
  11. print()
  1. def fib(n):
  2. a, b = 1, 1
  3. for i in range(n - 1):
  4. a, b = b, a + b
  5. return a
  6. i=1
  7. while i<=15:
  8. print(fib(i),end=" ")
  9. i=i+1

3 生成器(函数)

生成器本质上也是迭代器,不过它比较特殊。
以 list 容器为例,在使用该容器迭代一组数据时,必须事先将所有数据存储到容器中,才能开始迭代;而生成器却不同,它可以实现在迭代的同时生成元素。
也就是说,对于可以用某种算法推算得到的多个数据,生成器并不会一次性生成它们,而是什么时候需要,才什么时候生成。
不仅如此,生成器的创建方式也比迭代器简单很多,大体分为以下 2 步:

  1. 定义一个以 yield 关键字标识返回值的函数;
  2. 调用刚刚创建的函数,即可创建一个生成器。 ```python def intNum(): print(“开始执行”) for i in range(5):
    1. yield i
    2. print("继续执行")

num = intNum() print(“num=”,next(num)) print(“num=”,next(num)) print(“num=”,next(num)) print(“num=”,next(num))

  1. 由此,我们就成功创建了一个 num 生成器对象。显然,和普通函数不同,intNum() 函数的返回值用的是 yield 关键字,而不是 return 关键字,此类函数又成为生成器函数。<br />和 return 相比,yield 除了可以返回相应的值,还有一个更重要的功能,即每当程序执行完该语句时,程序就会暂停执行。不仅如此,即便调用生成器函数,[Python](http://c.biancheng.net/python/) 解释器也不会执行函数中的代码,它只会返回一个生成器(对象)。<br />要想使生成器函数得以执行,或者想使执行完 yield 语句立即暂停的程序得以继续执行,有以下 2 种方式:
  2. - 通过生成器(上面程序中的 num)调用 next() 内置函数或者 __next__() 方法;
  3. - 通过 for 循环遍历生成器。
  4. 生成器的练习题<br />**问题 1:输入一个数字 n,写一个程序判断 0 n 之间的偶数,并用逗号分隔来输出。**<br />比如输入:10<br />输出结果:0,2,4,6,8,10<br />题目分析<br />我们首先需要一个循环,找到 10 以内的所有数字,然后判断是否是偶数。题目要求用生成器的方式,我们只需要写一个生成器函数,在找到符合条件的数字后,使用 yield 输出。最后直接循环生成器,找到需要的值放入列表,最后用逗号分隔输出即可。
  5. ```python
  6. def EvenGenerator(n):
  7. i = 0
  8. while i <= n:
  9. if i%2 == 0:
  10. yield i
  11. i += 1
  12. n = int(input())
  13. values = []
  14. for i in EvenGenerator(n):
  15. values.append(str(i))
  16. print(",".join(values))

问题2:输入一个数字 n,写一个程序判断 0 到 n 之间的可以同时被 5 和 7 整除的数字,并用逗号分隔来输出。
比如输入:100
输出结果:
0,35,70
题目分析
此题目和上一个类似,你会发现这一次只是核心判断条件有变化,输入和输出不一样,但其实套路没变,还是用一个生成器函数,对应条件的地方用 yield 把数据返回即可。

  1. def NumGenerator(n):
  2. for i in range(n+1):
  3. if i%5 == 0 and i%7 == 0:
  4. yield i
  5. n = int(input())
  6. values = []
  7. for i in NumGenerator(n):
  8. values.append(str(i))
  9. print(",".join(values))