可迭代对象

  • 若一个数据类型能够用for循环来遍历,则该类型为可迭代对象,这种遍历行为称为迭代。
1
2
3
4
5
6
7
8
9
# 如列表就是可迭代
L = [1,2,3,4,5]
for i in L:
print(i)

# 迭代中的双变量迭代:
L = [(1,2),(3,4),(5,6)]
for x,y in L:
print(x,y)

列表生成式

  • 利用for循环构建列表
1
2
3
4
5
6
7
# 构建一个包含100以内完全平方数的列表
>>> print([x**2 for x in range(1,10)])
[1, 4, 9, 16, 25, 36, 49, 64, 81]

# 双循环构建全排列数组
>>> print([m+n for m in "123" for n in "abc"])
['1a', '1b', '1c', '2a', '2b', '2c', '3a', '3b', '3c']
  • 利用for+if构建列表
1
2
3
4
5
6
7
# 构造10以内的偶数列表
>>> print([x for x in range(11) if x % 2 ==0])
[0, 2, 4, 6, 8, 10]

# 构造10以内的偶数列表,奇数用0代替
>>> print([x if x%2 == 0 else 0 for x in range(11)])
[0, 0, 2, 0, 4, 0, 6, 0, 8, 0, 10]

迭代器Iterator

迭代器的创建与使用

  • 迭代器是作为访问容器元素的一种方式。容器提供迭代器,而迭代器一某种顺序提供对其元素的访问。
  • iter(iterable) 创建迭代器
    • 接受一个可迭代对象,返回一个对应的迭代器
  • next(iterator) 推进迭代器
    • 返回迭代器指向的对象,并使迭代器指向下一个元素
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
>>> s = [[1,2],3,4,5]
>>> t = iter(s)
>>> t
<list_iterator object at 0x000001D496C5BE80>
>>> next(t)
[1, 2]
>>> next(t)
3
>>> next(t)
4
>>> next(t)
5
# 此时迭代器已经不指向容器中的任何元素
>>> next(t)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
  • 使用for遍历迭代器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> r = list(range(3,6))
>>> for i in r:
... print(i)
...
3
4
5
>>> ri = iter(r)
>>> for i in ri:
... print(i)
...
3
4
5
# 此时已经将迭代器推进至末尾以后,无法再次使用
>>> for i in ri:
... print(i)
...
>>>
# 不产生任何效果

内置函数

  • lazy computation:只有在请求时才计算结果。解释器准备了计算所需的内容,但只有在使用该值的时候才进行计算。 同理,只有当我们请求下一个元素时,函数才会应用并计算结果。

  • map函数:

    • 接受一个函数名,和一个可迭代对象.
    • 返回一个迭代器遍历 func(x) for x in literable
  • filter函数:

    • 接受一个谓词函数和一个可迭代对象,
    • 返回一个迭代器遍历 x for x in literable if func(x)
  • zip函数

    • 接受多个可迭代对象
    • 返回迭代器遍历共同索引的(x1,x2,…)对.
  • reversed函数:

    • 返回一个迭代器按照序列的反向遍历
1
2
3
4
map(func,iterable)
filter(func,iterable)
zip(first_iter,second_iter)
reversed(sequence)
  • 查看迭代器中的内容
    • list(iterable)
      • 创建一个列表包含迭代器的所有指向元素
    • tuple(iterable)
      • 创建一个元组包含迭代器的所有指向元素
    • sorted(iterable)
      • 创建一个已排序列表包含迭代器的所有指向元素

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
>>> bcd = ['b','c','d']
>>> map(lambda x : x.upper() , bcd)
<map object at 0x000001D496E29E70>
>>> m=map(lambda x : x.upper() , bcd)
>>> next(m)
'B'
>>> next(m)
'C'
>>> next(m)
'D'

>>> def double(x):
... print("**", x ,"=>",2*x,"**")
... return 2*x
...
>>> m = map(double,[3,5,7])
>>> m = map(double,range(3,7))
>>> f = lambda x : x>=10
>>> t = filter(f,m)
# t实际上只有两个元素 10,12
''' 只有当访问t的下一个元素时,map函数才开始计算(lazy computation)'''
>>> next(t)
** 3 => 6 **
** 4 => 8 **
** 5 => 10 **
10
>>> next(t)
** 6 => 12 **
12
>>> list(t)
[]

# zip的使用
>>> list(zip([1,2],[3,4,5]))
[(1, 3), (2, 4)]
>>> list(zip([1,2],[3,4,5],[6,7]))
[(1, 3, 6), (2, 4, 7)]

Ex. 实现回文序列的判断

  • 题目练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# Tip: 可以使用all(也可以不使用)函数实现对迭代其中每个元素的and操作
# all接受一个可迭代对象,只有该对象所有元素全为真时返回真
'''
>>> all([1==1,2==2,3==3])
True
>>> all([1==1,2==3])
False
'''

def palindrome(n):
'''
>>> palindrome([1,2,3,2,1])
True
>>> palindrome("abcba")
True
>>> palindrome("abc ba")
False
'''

return _______________ #ONLY your code here
  • 两种实现
1
2
3
4
5
6
7
# 实现1
def palindrome(s):
return list(s) == list(reversed(s))

# 实现2
def palindrome(s):
return all([x == y for x,y in zip(s,reversed(s))])

生成器

  • 生成器是一种特殊的迭代器,从生成器函数返回。
  • 生成器对象,可以迭代调用函数产生的所有值。
  • 同理,遵循lazy computation 的计算方式。

生成器函数

  • 语法上,跟普通函数的区别在于用 yield 语句返回值。
  • 生成器函数是一种产生值的函数(返回生成器),而不是返回值的函数。
  • 可以返回多次yield。
  • 每一次执行时都会执行到yield语句,并暂停,下次调用时再继续从yield的下一个语句开始执行,直到遇到下一个yield语句。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# 生成器函数
>>> def evens(start,end):
... even = start + start%2
... while even<end:
... yield even
... even+=2
...
>>>
>>> t = evens(2,10)
>>> next(t)
2
>>> next(t)
4
>>> next(t)
6
>>> next(t)
8
>>> next(t)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration

yield from 语句

  • 此语句允许生成器从其他迭代器中产生所有元素,从可迭代对象中产生所有值。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 生成器遍历可迭代对象的循环形式
>>> def a_then_b(a,b):
... for x in a:
... yield x
... for x in b:
... yield x
...
>>> list(a_then_b([1,2],[3,4]))
[1, 2, 3, 4]

# 简写为
>>> def a_then_b(a,b):
... yield from a
... yield from b
...
>>> list(a_then_b([1,2],[3,4]))
[1, 2, 3, 4]

# 产生倒序数组
>>> def countdown(k):
... if k > 0:
... yield k
... for x in countdown(k-1):
... yield x
...
>>> list(countdown(5))
[5, 4, 3, 2, 1]
# yield from
>>> def countdown(k):
... if k > 0:
... yield k
... yield from countdown(k-1)
...
>>> list(countdown(5))
[5, 4, 3, 2, 1]

# 更复杂的例子
>>> def prefixes(s):
... if s:
... yield from prefixes(s[:-1])
... yield s
...
>>> list(prefixes("tops"))
['t', 'to', 'top', 'tops']

>>> def substrings(s):
... if s:
... yield from prefixes(s)
... yield from substrings(s[1:])
...
>>> list(substrings("tops"))
['t', 'to', 'top', 'tops', 'o', 'op', 'ops', 'p', 'ps', 's']

Ex.利用生成器函数构造杨辉三角

  • 题目练习
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def triangles(n):
''' Your code here'''

# test
for i in triangles(10):
print(i)
#[output]
[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
2
3
4
5
6
7
8
9
10
def triangles(k):
    i = 1
    res = [1]
    while i < k:
        yield res
        prev = res[:]
        for j in range(1,i):
            res[j] += prev[j-1]
        res.append(1)
        i+=1