python基础(15)——迭代器 & 生成器 & 字节串和字节数组

 一、迭代器Iterator

  什么是迭代器
       迭代器是访问可迭代对象的工具
       迭代器是指用iter(obj) 函数返回的对象(实例)
       迭代器可以用next(it) 函数获取可迭代对象的数据

1、迭代器函数 iter和next

   iter(iterable) 

        从可迭代对象中返回一个迭代器,iterable 必须是能提供一个迭代器的对象
   next(iterator) 

        从迭代器iterator中获取下一个记录,如果无法获取下一条记录,则触发StopIterator异常

  说明:
     1. 迭代器只能往前取值,不会后退
     2. 用iter函数可以返回一个可迭代对象的迭代器
   示例:
     L = [1, 3, 5, 7]
     it = iter(L)  # 让L提供一个能访问自己的迭代器
     next(it)  # 1 从迭代器中取值,让迭代器去获取L中的一个元素
     next(it)  # 3
     next(it)  # 5
     next(it)  # 7
     next(it)  # StopIteration 异常

     it = iter(range(1, 10, 3))
     next(it)  # 1
     next(it)  # 4
     next(it)  # 7
     next(it)  # StopIteration

 1 # L = [2, 3, 5, 7]
 2 # for x in L:
 3 #     print(x)  # 2 3 5 6
 4 # 以下用迭代器来访问L列表中的元素
 5 
 6 
 7 # L = [2, 3, 5, 7]
 8 # it = iter(L)  # 先拿到迭代器用iter绑定
 9 # while True:
10 #     try:
11 #         x = next(it)  # 获取一个数据并绑定到x
12 #         print(x)  # 2 3 5 7
13 #     except StopIteration:
14 #         break
15 
16 
17 L = [2, 3, 5, 7]
18 it = iter(L)  # 先拿到迭代器用iter绑定
19 try:
20     while True:
21         x = next(it)  # 获取一个数据并绑定到x
22         print(x)  # 2 3 5 7
23 except StopIteration:
24     pass
iteator_while.py

2、迭代器的用途

   用迭代器可以依次访问可迭代对象的数据
示例:
   L = [2, 3, 5, 7]
   for x in L:
       print(x)  # 2 3 5 6
   # 以下用迭代器来访问L列表中的元素
   L = [2, 3, 5, 7]
   it = iter(L)  # 先拿到迭代器用iter绑定
   while True:
       x = next(it)  # 获取一个数据并绑定到x
       print(x)  # 2 3 5 7

练习:
   有一个集合:
      s = {'唐僧', '悟空', '八戒','沙僧'}

  用for语句来遍历所有元素如下:
     for x in s:
         print(x)
     else:
         print('遍历结束')
   将上面的for语句改写为while语句和迭代器实现

 1 # 方法1
 2 s = {'唐僧', '悟空', '八戒', '沙僧'}
 3 myit = iter(s)
 4 while True:
 5     try:
 6         x = next(myit)
 7         print(x)
 8     except StopIteration:
 9         print("遍历结束")
10         break
方法1
1 # 方法2
2 s = {'唐僧', '悟空', '八戒', '沙僧'}
3 myit = iter(s)
4 try:
5     while True:
6         x = next(myit)
7         print(x)
8 except StopIteration:
9     print("遍历结束")
方法2

二、生成器 Generator

1、什么是生成器

        生成器是能够动态提供数据的对象,生成器对象也是可迭代对象(实例)

2、生成器有两种

        生成器函数
        生成器表达式

3、生成器函数的定义:

   含有yield语句的函数是生成器函数,此函数被调用将返回一个生成器对象
     yield翻译为产生(或生成)

4、yield 语句

   语法:
      yield 表达式
   说明:
        yield 用于 def 函数中,目的是将此函数作用生成器函数使用
        yield 用来生成数据,供迭代器和next(it) 函数使用
   示例见:

 1 # yield语句的函数为生成器函数,及用yield生成整数
 2 def myyield():
 3     yield 2
 4     yield 3
 5     yield 5
 6     yield 7
 7     print("生成器生成结束")
 8 
 9 
10 for x in myyield():
11     print(x)   # 2 3 5 7
12 
13 # 调用生成器函数来创建一个生成器,此生成器能生成
14 # 2 3 5 7 这样四个数
15 gen = myyield()
16 
17 it = iter(gen)  # 用生成器拿到对应的迭代器
18 print(next(it))  # 2  访问迭代器
19 print(next(it))  # 3  访问迭代器
20 print(next(it))  # 5  访问迭代器
yield1.py
 1 # 示意含有yield语句的生成器函数的调用顺序
 2 # 生成器函数只有在next(it) 函数调用时才会执行,且遇到yield后
 3 # 返回相应的值给next(it)函数
 4 def myyield():
 5     print("即将生成2")
 6     yield 2
 7     print("即将生成3")
 8     yield 3
 9     print("即将生成5")
10     yield 5
11     print("即将生成7")
12     yield 7
13     print("生成器生成结束")
14 
15 gen = myyield()
16 it = iter(gen)
17 print(next(it))  # 2
18 print(next(it))  # 3
19 print(next(it))  # 5
20 print(next(it))  # 7
21 print(next(it))  # StopIteration
yield2.py
 1 # 此示例示意含有yield语句的生成器函数的调用顺序
 2 # 生成器函数只有在next(it) 函数调用时才会执行,且遇到yield后
 3 # 返回相应的值给next(it)函数
 4 def myyield():
 5     print("即将生成2")
 6     yield 2
 7     print("即将生成3")
 8     return "在生成3之前用return返回"
 9     yield 3
10     print("即将生成5")
11     yield 5
12     print("即将生成7")
13     yield 7
14     print("生成器生成结束")
15 
16 gen = myyield()
17 it = iter(gen)
18 print(next(it))  # 2
19 print(next(it))  # StopIteration异常
yield_return.py
 1 # 用生成器函数生成从0开始到n结束的一系列的整数
 2 def myinteger(n):
 3     i = 0
 4     while i < n:
 5         yield i
 6         i += 1
 7 
 8 for x in myinteger(30000000000):
 9     print(x)  # 0 1 2
10 
11 
12 L = [x for x in myinteger(100) if x % 2 == 1]
13 print("L =", L)
myinteger

生成器函数说明:
     生成器函数的调用将返回一个生成器对象,生成器对象是一个可迭代对象,通常用来动态生成数据
     生成器函数调用 return 语句会触发一个StopIterator异常

练习:

 1、写一个生成器函数 myeven(start, stop) 用来生成 start开始到stop结束(不包含stop)的偶数
   如:
     def myeven(start, stop):
         ....

    for x in myeven(1, 10):
          print(x)  # 2 4 6 8
     L = [x ** 2 for x in myeven(1, 20)]
     print(L)

 1 def myeven(start, stop):
 2     while start < stop:
 3         if start % 2 == 0:
 4             yield start
 5         start += 1
 6 
 7 
 8 for x in myeven(1, 10):
 9     print(x)  # 2 4 6 8
10 L = [x ** 2 for x in myeven(2, 20)]
11 print(L)
练习1

 2、写一个生成器函数myfactorial(n)此函数用来生成n个从1开始的阶乘

     def myfactorial(n):
          ...

     L = list(myfactorial(5))  # L = [1, 2, 6, 24, 120]
                             #      1! 2! 3!  4!  5!

 1 def myfactorial(n):
 2     s = 1  # 用来保存阶乘
 3     for x in range(1, n + 1):
 4         s *= x
 5         yield s
 6 
 7 
 8 L = list(myfactorial(5))  # L = [1, 2, 6, 24, 120]
 9 print(L)
10 
11 print(sum(myfactorial(5)))
练习2

三、生成器表达式

   语法:
       (表达式 for 变量 in 可迭代对象 [if 真值表达式])
   作用:
       用推导式形式创建一个新的生成器
   说明:
       if 子句可以省略
   示例:
     gen = (x**2 for x in range(1, 5))
     it = iter(gen)
     print(next(it))  # 1
     print(next(it))  # 4
     print(next(it))  # 9
     print(next(it))  # 16
     print(next(it))  # StopIteration

练习:
    已知有列表:
      L = [2, 3, 5, 7]
      1) 写一个生成器函数,让此函数能够动态提供数据,数据为原列表的数字的平方加1
      2) 写一个生成器表达式,让此表达式能够动态提供数据,数据为原列表的数字的平方加1
      3) 生成一个列表,此列表内的数据是原列表数据的平方加1

 1 L = [2, 3, 5, 7]
 2 # 1) 写一个生成器函数,让此函数能够动态提供数据,数据为原列表的数字的平方加1
 3 def mygen(L):
 4     for x in L:
 5         yield x ** 2 + 1
 6 
 7 
 8 gen = mygen(L)
 9 for a in gen:
10     print(a)  # 5 10 26 50
11 print('------------')
12 # 生成器函数生成的数据已经被取完,再次遍历将拿不到数据
13 for a in gen:
14     print(a)  # 5 10 ....
15 print('++++++++++++')
16 # 2) 写一个生成器表达式,让此表达式能够动态提供数据,数据为原列表的数字的平方加1
17 for a in (x ** 2 + 1 for x in L):
18     print(a)
19 # 3) 生成一个列表,此列表内的数据是原列表数据的平方加1
20 L = [x ** 2 + 1 for x in L]
21 print(L)
练习.py

生成器表达式和列表推导式的区别:

       生成器表达式是现用现生成,列表推导式是一次性生成静态数据

 1 # 生成器表达式和列表推导式区别  
 2  
 3 # 列表推导式
 4 L = [2, 3, 5, 7]
 5 L2 = [x ** 2 + 1 for x in L]
 6 it = iter(L2)
 7 print(next(it))  # 5
 8 L[1] = 30
 9 print(next(it))  # 10
10 
11 # 生成器表达式
12 L = [2, 3, 5, 7]
13 gen = (x ** 2 + 1 for x in L)
14 it = iter(gen)
15 print(next(it))  # 5
16 L[1] = 30
17 print(next(it))  # 901
gen_vs_list_comprehension.py

四、迭代工具函数:

   作用是生成一个个性化的可迭代对象

函数:
   zip(iter1 [, iter2[....]]) 

          返回一个zip对象,此对象用于生成元组,此元组的每个数据来源于参数中的可迭代对象,当最小的可迭代对象不再提供数据时迭代结束

   enumerate(iterable [, start])

          生成带索引的枚举对象,返回的迭代类型为索引-值对(index-value)对,默认索引从零开始,也可以用start指定

zip示例:

1 numbers=[10086,10000,10010,95588]
2 names = ['中国移动','中国电信','中国联通']
3 
4 for t in zip(numbers,names):
5     print(t)
6     
7 for No, number, name in zip(range(1, 100),numbers,names):
8     print("序号",No, name, '的客服电话是:', number)
zip.py
 1 def myzip(iter1, iter2):
 2     it1 = iter(iter1)  # 拿到两个对象的迭代器
 3     it2 = iter(iter2)
 4     while True:
 5         try:
 6             t = (next(it1), next(it2))  # StopIteration
 7             yield t
 8         except StopIteration:
 9             break
10 
11 numbers = [10086, 10000, 10010, 95588]
12 names = ['中国移动', '中国电信', '中国联通']
13 
14 for t in myzip(numbers, names):
15     print(t)
myzip.py

enumerate示例:

1 names = ['中国移动','中国电信','中国联通']
2 
3 for t in enumerate(names):
4     print(t)   #(0, '中国移动')(1, '中国电信')(2, '中国联通')
5 for t in enumerate(names, 101):
6     print(t)   #(101, '中国移动')(102, '中国电信')
enumerate.py

练习:
   写一个程序,读入任意行文字,当输入空行时结束输入
   打印带有行号的输入结果
     如:
       请输入: abcde<回车>
       请输入: hello<回车>
       请输入: bye<回车>
       请输入: <回车>
     输出如下:
       第1行: abcde
       第2行: hello
       第3行: bye

 1 def get_lines():
 2     L = []
 3     while True:
 4         s = input("请输入: ")
 5         if not s:
 6             break
 7         L.append(s)
 8     return L
 9 
10 
11 def print_lines(L):
12     for t in enumerate(L, 1):
13         print("第%d行: %s" % t)
14 
15 
16 L = get_lines()
17 print(L)
18 print_lines(L)
练习.py

五、字节串和字节数组

序列的种类:
      字符串 str
      列表 list
      元组 tuple
      字节串 bytes
      字节数组 bytearray

1、字节串(也叫字节序列) bytes

1、作用:
     存储以字节为单位的数据
     字节串是不可变的字节序列

2、字节:
   字节是0~255之间的整数,字节是数据传输和数据存储的基本单位
     (例如:中国移动的流量...,文件大小等)

3、创建空字节串的字面值
      b''
      b""
      b""""""
      b''''''
4、创建非空的字节串的字面值
      b'ABCD'
      b"ABCD"
      b'\x41\x42'

5、字节串的构造函数:
       bytes()  # 生成一个字的字节串,等同于 b''
       bytes(整型可迭代对象)  用可迭代对象创建一个字节串
       bytes(整数n)  生成n个值为0的字节串
       bytes(字符串, encoding='utf-8')  用字符串的转换编码生成一个字节串

  示例:
       b = bytes() 
       b = bytes(range(65, 90))
       b = bytes(10)
       b = bytes('hello', 'utf-8')
       b = bytes('中文', 'utf-8')

6、bytes 的运算:
   与其它序列的运算规则完全相同
   + += * *=
   < <= > >= == !=
   in / not in
   索引和切片

   len(x), max(x), min(x), sum(x), any(x), all(x)

7、bytes 与 str的区别
   bytes 存储字节(0~255)
   str 存储字符(用来表示文字信息,值为0~65535或更大)

8、bytes与 str转换
         编码(encode)
   str   ---------->  bytes
       b = s.encode(encoding='utf-8')

         解码(decode)
   bytes  ---------> str
       s = b.decode(encoding='utf-8')

2、字节数组 bytearray

   可变的字节序列

1、构造函数:
    bytearray(b'')
    bytearray()  # 生成一个字的字节串
    bytearray(整型可迭代对象)  用可迭代对象创建一个字节数组
    bytearray(整数n)  生成n个值为0的字节数组
    bytearray(字符串, encoding='utf-8')  用字符串的转换编码生成一个字节数组

2、运算和字节串完全相同
   * *= + +=
   < <= > >= == !=
   in / not in
   索引 index / 切片 slice
   字节数组支持索引和切片赋值(重要)

3、bytearray的方法:

 

方法说明
B.clear() 清空
B.append(n) 追加一个字节(n为0-255的整数)
B.remove(value) 删除第一个出现的字节,如果没有出现,则产生ValueError错误
B.reverse() 字节的顺序进行反转
B.decode(encoding='utf-8')  
B.find(sub[, start[, end]])

4、序列:
   str(不可变)
   list(可变)      ----> tuple(不可变)
   bytearray(可变) ----> bytes(不可变)

练习:

   1. 用生成器函数,生成素数,给出起始值begin和终止值 end, 生成begin到end范围内的素数
     如:
       def prime(begin, end):
         ...

      L=[x for x in prime(10, 20)]  #L=[11,13,17,19]

 1 def is_prime(x):
 2     if x < 2:
 3         return False
 4     for i in range(2, x):
 5         if x % i == 0:
 6             return False
 7     return True
 8 
 9 
10 def prime(begin, end):
11     for i in range(begin, end):
12         # 如果i是素数
13         if is_prime(i):
14             yield i
15 
16 L = [x for x in prime(10, 20)]  # L=[11,13,17,19]
17 print(L)
练习1

  2. 写一个生成器函数myxrange([start, ], stop[, step]) 来生成一系列整数
     要求:
       myxrange功能与range功能相同(不允许调用range函数)
     用自己写的myxrange函数结合生成器表达式求1~10内奇数的平方和

 1 def myxrange(start, stop=None, step=1):
 2     if stop is None:
 3         stop = start
 4         start = 0
 5     if step > 0:
 6         while start < stop:
 7             yield start  # 生成当前数送回给迭代器next函数
 8             start += step
 9     elif step < 0:
10         while start > stop:
11             yield start
12             start += step
13     else:
14         raise ValueError("步长不允许为0")
15 
16 for x in myxrange(1, 10, 3):
17     print(x)
18 
19 for x in myxrange(10, 0, -3):
20     print(x)   # 10, 7, 4, 1
练习2

posted on 2018-10-12 17:35  破天荒的谎言、谈敷衍  阅读(517)  评论(0)    收藏  举报

导航