迭代
定义
用for循环对list或tuple进行遍历我们称之为迭代(Iteration)
- 只要属于list类型的对象都可以被迭代.
- Python的
for循环抽象程度要比Java的高,迭代不仅可以用在list或tuple上还可以用在其他迭代对象上.比如dict,str.
>>> d = {'a':1,'b':2,'c':3}
>>> for x in d:
... print x
...
a
c
b
>>> str = 'abc'
>>> for s in str:
... print s
...
a
b
c
dict是无序的所以输出结果也无序.dict默认迭代的是key,如果要迭代value呢?可以使用for value in d.itervalues(),如果需要同时迭代key和value可以用for k, v in d.iteritems().
- 但是如何判断一个对象是否是可迭代对象呢?我们可以通过collection模块里的Iterable类进行判断.
>>> from collections import Iterable
>>> isinstance('abc',Iterable)
True
>>> isinstance((1,2,3),Iterable)
True
>>> isinstance([1,2,3],Iterable)
True
>>> isinstance(123,Iterable)
False
for可以同时迭代两个变量
>>> for x,y in ((1,1),(2,2),(3,3)):
... print x ,y
...
1 1
2 2
3 3
开拓思维要是需要迭代2个以上的对象呢?
>>> for a,b,c in [(1,1,1),(2,2,2),(3,3,3)]:
... print a,b,c
...
1 1 1
2 2 2
3 3 3
列表生成式
定义
列表生成式是Python内置的非常强大的可以用来创建list的生成式
例:生成[1…10]的list
>>> range(1,11)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
但是如果生成[1x1,2x2,3x3….10x10]的list怎么办?
方法1:循环
>>> for x in range(1,11):
... y = x * x
... L.append(y)
...
>>> L
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
>>>
方法2:列表生成式
>>> [x*x for x in range(1,11)]
[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
x*x代表目标list的元素要放在最前面,后面就是跟for循环取值然后赋值给x带入x*x 进行运算.
生成式的其它用法
for循环后添加if判断
>>> [x*x for x in range(1,11) if x%2 == 0] #筛选出偶数
[4, 16, 36, 64, 100]
>>> [x*x for x in range(1,11) if x%2 != 0] #筛选出奇数
[1, 9, 25, 49, 81]
#只输出符合if语句的内容
- 两层循环
>>> [m + n for m in 'abc' for n in '123']
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']
>>> [m + n for m in ['a','b','c'] for n in [1,2,3]]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
>>> [m + n for m in ('a','b','c') for n in (1,2,3)]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: cannot concatenate 'str' and 'int' objects
#只能对同类型的数据进行组合
>>> [m + n for m in ('a','b','c') for n in ('1','2','3')]
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']
>>> [m + n for m in ['a','b','c'] for n in ['1','2','3']]
['a1', 'a2', 'a3', 'b1', 'b2', 'b3', 'c1', 'c2', 'c3']
>>> [m + n for m in [1,2,3] for n in [4,5,6]]
[5, 6, 7, 6, 7, 8, 7, 8, 9] #以m为基础进行求和,逐次运行.
三层及三层以上的循环基本用不到了.
生成器
定义
所谓生成器就是列表生成器的进化版本:
列表生成器虽然方便创建数组但是也会占用大量内存,如果生成的数组太大,内存就会溢出,有什么好的解决办法呢?生成器(generator)就横空出世了!
生成器会根据数组推算后续数值,一边循环一边计算,这样就不会占用大量空间.
那么问题来了,怎么创建生成器呢?非常简单,把列表生成器的中括号[]改为小括号就可以了()
>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> (x for x in range(10))
<generator object <genexpr> at 0x7fea306baa50> #后面0x..是generator对象的内存地址.
通过上面的代码我们可以看到,生成器不会直接生成列表只是占用一点内存空间,若是需要输出数值有两个方法:一个是直接调用生成器的next()方法;二是通过for循环.
方法1:
>>> g = (x for x in range(10))
>>> g.next()
0
>>> g.next()
1
>>> g.next()
2
>>> g.next()
3
>>> g.next()
4
>>> g.next()
5
>>> g.next()
6
>>> g.next()
7
>>> g.next()
8
>>> g.next()
9
>>> g.next()
Traceback (most recent call last): #循环完毕跳出error
File "<stdin>", line 1, in <module>
StopIteration
方法2:
>>> g = (x for x in range(10))
>>> for x in g:
... print x
...
0
1
2
3
4
5
6
7
8
9
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
#单个输出数值
>>> g = (x for x in range(10))
>>> l = []
>>> for x in g:
... l.append(x)
...
>>> l
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# 直接生成list
>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> [x for x in range(10)]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 列表生成器可以重复执行
通过比较方法1和方法2,方法2较方法1更方便,尤其是需要计算的数组比较大的时候.
另外细心的朋友估计能发现,不像列表生成器一样可以重复输出数组.
生成器是一种线性迭代是一次性的不能回头滴.撞了南墙也回不了头啊~只能说句say you error.
更加强大的generator
碰到更复杂的算法的时候,生成器的for循环就不能胜任了,这时候就要请出我们的函数君来解决问题.
以著名的斐波拉契数列(Fibonacci)来举例子吧.
**说明**Fibonacci数列是怎么一回事儿呢? 除了它的第一个和第二个数相等,任意一个数都可以由前面两个数相加得到.
1,1,2,3,5,8,13,21,….
普通文艺函数君:
>>> def fib(n):
... i,a,b = 0,0,1
... while i < n:
... print b # print b 要放在公式的前面执行.
... a, b = b, a+b
... i = i + 1
...
>>> fib(5)
1
1
2
3
5
>>> def fib(n):
... i,a,b = 0,0,1
... while i < n:
... print b
... a, b = b, a+b
... i = i + 1
... print 'new: ',b #添加一个放在后面的
...
>>> fib(5)
1
new: 1
1
new: 2
2
new: 3
3
new: 5
5
new: 8
# 比较一下输出结果,得出的是(n+1)位的结果.
有可能有一部分同学已经迷糊了~这a , b, a+b,到底咋回事?
其实很好理解,我们先在Fibonacci数列前加个0,
> a b a+b # 第一次循环n=0的时候,a,b,a+b相对应的数值
> 0, 1, 1, 2, 3, 5, 8
> a b a+b # 第二次循环n=1的时候,a,b,a+b相对应的数值
通过上面内容我们可以看到a,b,a+b是整体逐次步进的,再去对应下代码,是不是非常好理解~
理解之后我们发现,fib函数也是从第一个元素开始推算后续任意元素的,这个和generator的逻辑非常相似,所以我对普通文艺函数君稍微改造下就可能把他变为逗比generator函数君.
怎么改造呢?只要把fib函数里面的print b改为yield b就可以了!是高富帅还是吊丝就是一步之遥啊.
逗比generator函数君:
>>> def fib(n):
... i,a,b = 0,0,1
... while i < n:
... yield b
... a, b = b, a+b
... i = i + 1
...
>>> fib(5)
<generator object fib at 0x7f29e33c9af0>
# 就是不输出,占坑不拉,你咬我啊.
怎么输出呢?
>>> f = fib(5)
>>> f.next()
1
>>> f.next()
1
>>> f.next()
2
>>> f.next()
3
>>> f.next()
5
>>> f.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# next()方法单个输出
>>> for n in fib(5):
... print n
...
1
1
2
3
5
# for循环一次性输出
yield和print有啥区别呢?可以这么理解yield,只能通过next()或for循环来调用,在调用的过程中边运行边计算,当函数在循环过程中碰到yield就会输出一个数值.直到循环结束没有yield了然后返回一个error,当然只有使用next()方法的时候才会返回error,使用for循环的时候没有error返回.
本文介绍了Python中的迭代概念,包括对列表、字典、字符串等的迭代,并讲解了列表生成式及其用法。此外,文章深入探讨了生成器,阐述了它们如何节省内存,并通过实例展示了生成器表达式和自定义生成器函数的实现。最后,通过斐波拉契数列的例子解释了生成器在处理复杂算法时的优势。
521

被折叠的 条评论
为什么被折叠?



