【Python入门 学习笔记】6.生成器与迭代器 & 杨辉三角排列的生成

写在前面:为了更好的学习python,博主记录下自己的学习路程。本学习笔记基于廖雪峰的Python教程,如有侵权,请告知删除。欢迎与博主一起学习Pythonヽ( ̄▽ ̄)ノ


高级特性

切片

slice,即切片的意思。在Python中可以用切片的方式来取一个list或tuple甚至字符串的其中一部分。

>>>L = list(range(0,101))                  #创建一个0到100的list
>>>L[1:10]                                 #取索引1开始,到索引10为止但不含10的元素
[1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>>L[0:10]                                 #取索引0开始,到索引10为止但不含10的元素
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>>L[:10]                                  #如果从索引0开始取,那么0可以省略
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9] 
>>>L[:]                                    #取所有元素
[0, 1, 2, 3, 4, 5...96, 97, 98, 99, 100] 

我们也可以直接取后面的元素,需要注意的是第一个元素的索引号是0,倒数第一个元素的索引号是-1。切片必须顺序取值,如L[10:1]、L[-1:-10]都是无法取值的。

>>>L[-10:-1]                               #从索引-10开始到索引-1为止但不含-1的元素
[91, 92, 93, 94, 95, 96, 97, 98, 99] 
>>>L[-10:]                                 #取最后10个元素
[91, 92, 93, 94, 95, 96, 97, 98, 99, 100]

后面再加一个冒号可以实现间隔取值,如

>>>L[:10:2]                                #从索引号0开始,每2个取1个,到索引号10为止不含10
[0, 2, 4, 6, 8] 
>>>L[:30:3]                                #从索引号0开始,每3个取1个,到索引号30为止不含30
[0, 3, 6, 9, 12, 15, 18, 21, 24, 27] 

当然,tuple和字符串也是可以进行切片的。

>>>T=(0,1,2,3,4)                           #tuple切片
>>>T[1:3]
(1, 2) 
>>>S='abcdef'                              #字符串切片
>>>S[1:3]
bc 

【练习】去除字符串首尾空格的函数实现

利用切片操作,实现一个trim()函数,去除字符串首尾的空格,注意不要调用str的strip()方法。(该练习来自廖雪峰的Python教程。)

# -*- coding: utf-8 -*-
def trim(s):

    while s[:1] == ' ':
        s = s[1:]
    while s[-1:] == ' ':
        s = s[:-1] 
    return s

# 测试:
if trim('hello  ') != 'hello':
    print('测试失败!')
elif trim('  hello') != 'hello':
    print('测试失败!')
elif trim('  hello  ') != 'hello':
    print('测试失败!')
elif trim('  hello  world  ') != 'hello  world':
    print('测试失败!')
elif trim('') != '':
    print('测试失败!')
elif trim('    ') != '':
    print('测试失败!')
else:
    print('测试成功!')

迭代

Iteration,当我们用for循环来遍历list或tuple时,这种遍历就是Iteration,即迭代。
在其他语言中如c,在迭代时需要通过下标来实现,而在Python中,没有下标也能实现迭代,Python的可迭代对象有很多,如list、tuple、dict、字符串等。

• 迭代tuple

>>>T = (1, 2, 3)                                
>>>for a in T:                                  #迭代tuple
...    print(a) 
...
1
2
3

• 迭代dict中的key

>>>D = {'Ming':50, 'Hong':70, 'Lily':100}       
>>>for key in D:                                #迭代dict中的key
...    print(key)
...
Ming 
Hong 
Lily 

如果要想迭代dict中的value的话,迭代对象变为D.values(),还能用D.items()同时迭代key和value。

• 迭代dict中的value

>>>for value in D.values():                     #迭代dict中的value
...    print(value)
...
50 
70 
100 

• 同时迭代dict中的key和value

>>>for k, v in D.items():                       #同时迭代dict中的key和value
...    print(k,v)
...
Ming 50 
Hong 70 
Lily 100 

• 拥有迭代下标

如果想要和其他语言一样想要有下标,可以通过Python内置的enumerate( )函数来实现

>>>for i, a in enumerate(T):                    #同时迭代去索引和元素本身
...    print(i,a)
...
0 1 
1 2 
2 3 

• 判断是否为可迭代对象

判断一个对象是否可迭代可以通过collections模块的Iterable类型判断。(以下代码转自廖雪峰的官方网站)

>>> from collections import Iterable
>>> isinstance('abc', Iterable)                 # str是否可迭代
True
>>> isinstance([1,2,3], Iterable)               # list是否可迭代
True
>>> isinstance(123, Iterable)                   # 整数是否可迭代
False

【练习】取list中的最大最小值的函数实现

请使用迭代查找一个list中最小和最大值,并返回一个tuple:(该练习来自廖雪峰的Python教程。)

# -*- coding: utf-8 -*-
def findMinAndMax(L):

    if L == []:
        return(None,None)
    else:
        max = L[0]
        min = L[0]
        for x in L:
            if max > x:
                max = c
            if min < x:
                min = x

    return (max,min)

# 测试
if findMinAndMax([]) != (None, None):
    print('测试失败!')
elif findMinAndMax([7]) != (7, 7):
    print('测试失败!')
elif findMinAndMax([7, 1]) != (1, 7):
    print('测试失败!')
elif findMinAndMax([7, 1, 3, 9, 5]) != (1, 9):
    print('测试失败!')
else:
    print('测试成功!')

列表生成器

列表生成器可通过[ ]直接构建。
我们想要生成一个列表的话可以先通过list(range(,))生成初始列表,然后在循环语句或判断语句加入条件与算法从而得到想要的列表,但这种方法有点麻烦。而列表生成器可以把这个过程用一行代码实现!如我们要生成12,22,32…102这样的数列,这样就可以:

>>>[x * x for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100] 

还能在后面加入判断条件,只算奇数的平方:

>>>[x * x for x in range(1,11) if x % 2 != 0]           #除以2取余数不为0的话即为奇数
[1, 9, 25, 49, 81] 

还能采用两层循环,生成全排列

>>>[a + b for a in 'ABC' for b in 'abc']
['Aa', 'Ab', 'Ac', 'Ba', 'Bb', 'Bc', 'Ca', 'Cb', 'Cc'] 

还能同时使用两个或多个变量,如用dict生成

>>>D={'A':'a', 'B':'b', "C":'c'}
>>>[k+'-->'+v for k, v in D.items()]
['A-->a', 'B-->b', 'C-->c'] 

生成器 generator

generator,是生产者的意思。在Python中,generator意为生成器,是一种可以一边循环一边计算的机制。相比列表生成器,generator的优点在于算法不用生成全部数列,而只生成我们需要的一部分,从而节省很多空间。

• generator的定义

generator的定义有两种方式,第一种是直接通过( )创建,这种方式与列表生成器相似,只是把[ ]换成( )。


>>>g=(x * x  for x in range(1,11))
>>>g
<generator object <genexpr> at 0x00000000023427C8>

第二种方式是通过函数的形式创建,在定义函数的过程中加入yield关键字,yield后面需生成的值,则这个函数不是一个普通的函数而是一个generator。如我们可以构建一个斐波拉契数列生成器(斐波拉契数列的例子转自廖雪峰的官方网站)

著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到


def fib(max):
    n, a, b = 0, 0, 1
    while n < max:
        yield b 
        a, b = b, a + b 
        n = n + 1
    return 'done'

generator与函数的执行方式不一样,函数的执行方式是顺序执行,直到return返回,则退出函数。而generator的执行方式是顺序执行,直到yield返回停止,下次再调用时从上次返回的yield语句后继续执行。可见正常情况下generator是不会得到return返回值的,想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中,具体操作会在后面介绍。

• generator的调用

generator的调用不能像列表生成器和函数那样直接调用。

>>>fib(6)
<generator object fib at 0x0000000000692840> 

想要调用generator,可以用next( )

>>>next(fib(6))
1
>>>next(fib(6))
1
>>>next(fib(6))
2
>>>next(fib(6))
3
>>>next(fib(6))
5

这种方式太过繁琐,generator是可迭代对象,一般采用for…in循环来调用。

>>>for n in fib(6):
...    print(n)
...
1 
1 
2 
3 
5 
8 

【练习】杨辉三角排列的生成

(该练习来自廖雪峰的Python教程。)
杨辉三角定义如下:

          1
        1   1
      1   2   1
    1   3   3   1
  1   4   6   4   1
1   5  10  10   5   1

把每一行看做一个list,试写一个generator,不断输出下一行的list:

# -*- coding: utf-8 -*-

def triangles():
    L = [1]                      #初始排列L为[1]
    while True:    
        yield L                  #返回L
        if L == [1]:
            L = L + [1]          #在L只有一个元素时,在加[1],时排列为[1,1]
        else:
            L = [1]+[L[x]+L[x+1]for x in range(len(L)-1)]+[1]    
                                 #当排列L有两个或以上的元素时,按顺序把每两个值相加生成一个值,并在前后加[1]

n = 0
results = []
for t in triangles():
    print(t)
    results.append(t)
    n = n + 1
    if n == 10:                  #生成十行排列
        break

输出结果

[1] 
[1, 1] 
[1, 2, 1] 
[1, 3, 3, 1] 
[1, 4, 6, 4, 1] 
[1, 5, 10, 10, 5, 1] 
[1, 6, 15, 20, 15, 6, 1] 
[1, 7, 21, 35, 35, 21, 7, 1] 
[1, 8, 28, 56, 70, 56, 28, 8, 1] 
[1, 9, 36, 84, 126, 126, 84, 36, 9, 1] 

迭代器 Iterator

• 可迭代对象 Iterable

可用for循环来迭代的对象称可迭代对象——Iterable,包括list、tuple、set、str、generator。可通过isinstance()来判断一个对象是否为可迭代对象

>>> from collections import Iterable
>>> isinstance([], Iterable)
True
>>> isinstance(10, Iterable)
False

• 迭代器 Iterator

而可以被next( )函数调用不断返回下个值得对象称迭代器——Iterator,如generator。可通过isinstance()来判断一个对象是否为迭代器。

>>> from collections import Iterator
>>> isinstance((x for x in range(100)), Iterator)
True
>>> isinstance([], Iterator)
False
>>> isinstance({}, Iterator)
False
>>> isinstance('abcd', Iterator)
False

• Iterable转成Iterator

可以通过iter()函数把Iterable转成Iterator。

>>> isinstance(iter([]), Iterator)
True
>>> isinstance(iter('abcd'), Iterator)
True

补充笔记

‘字符串’.lower( )函数可以把字符串变成小写。

问题记录

1.在廖雪峰的官方网站中的Python代码运行助手中 使用isinstance( )语句时会出现警告信息,但依然能用

from collections import Iterator
print(isinstance({}, Iterator))

输出结果

C:\Users\ADMINI~1\AppData\Local\Temp\learn_python_vkm_fbut_py\test_222.py:2: DeprecationWarning: Using or importing the ABCs from 'collections' instead of from 'collections.abc' is deprecated, and in 3.8 it will stop working 
  from collections import Iterator 
False 

2.在生成器一节的练习中,用L=L.append( )替换L=L+[1],输出结果不变,但最终的测试显示失败。


感谢你的阅读,有些知识点可能简略记录,有任何问题或想法欢迎评论与吐槽,和博主一起学习Python吧( ̄▽ ̄)~*

猜你喜欢

转载自blog.csdn.net/lecorn/article/details/81460646