当前位置:小鱼儿玄机二站 > 编程应用 > Python循环结构用法,比如讲授怎么样在Python编制

Python循环结构用法,比如讲授怎么样在Python编制

文章作者:编程应用 上传时间:2019-09-03

举例讲解如何在Python编程中进行迭代和遍历,python编程

迭代 首先理解下什么是迭代,python中所有从左往右扫面对象的方式都是可迭代的

有哪些方式是可迭代的:

1.文件操作

   我们读取文件的时候,会用到一个readline()方法,其实它就是一个迭代器,它会返回当前的数据,然后自动的调用内置的next()方法来让文件的读取头自动的移动到当前的下面一行,准备下次的读取,到达文件末尾时,就会返回空字符串.

>>> f=open('hello.py')
>>> f.readline()
'#!/usr/bin/python2.5n'
>>> f.readline()
'print "hello.word!"n'
>>> f.readline()
'n'
>>> f.readline()
''

>>> for i in open('hello.py'):
...       print(i)
... 
#!/usr/bin/python2.5
print "hello.word!"

用上面这样方式来读取文件内容的话,速度很快,内存占用也比较低,特别适合操作大文件.

下面这个方式适合操作一些小的文件,速度和效率没有上面的好,所以建议以后操作文件的话,尽量用上面的。

>>> for i in open('hello.py').readlines():
...     print i
... 
#!/usr/bin/python2.5
print "hello.word!"

read方法和readline方法,
read()方法把整个文件的内容放到字符串里
readline()方法则把文件的内容按照行为单位放到列表里。
一般要替换文件里的某个字符的话,最好有readline,然后用循环把一行一行内容循环出来,再查找替换,这样效率比整个读到一个字符串里来查找匹配效果更高。

2 for循环

例如:

>>> for i in range(5):
...    print(i)
... 

它中间处理的过程和下面的是一样的:

>>> L=[0,1,2,3,4]
>>> I=iter(L)
>>> I.next()
0
>>> I.next()
1
>>> I.next()
2
>>> I.next()
3
>>> I.next()
4
>>> I.next()

Traceback (most recent call last):
 File "<stdin>", line 1, in <module>
StopIteration

每次调用迭代器调用next()方法返回结果,并让文件指针往下移动一行,最后已StopIteration异常结束迭代。

3.列表解析:

相比python for循环速度会快很多

例如:

>>> L=[x+10 for x in range(10)]
>>> L

[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
python会在解释器里对range(10)进行迭代,依次把列表里的内容取出来,赋值给最左边的x,然后执行x+10的操作,
并且把执行好的结果保存在列表里。等range(10)迭代完以后就新生成了一个列表,结果就是[10,11,12,13,14,15,16,17,18,19]
从上面可以看出,这也是建立python 列表的一个方法。

上面例子也可以用for循环来实现.

>>> res=[]
>>> for x in range(10):
...    res.append(x+10)
... 
>>> res
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19]

从上面可以看出,python列表解析比手动的for 更加精简,而且运行的更快(往往速度回快一倍),因为他们的迭代在解析器内部是以C语言的速度执行的,而不是以手动python代码执行的,特别对于较大的数据集合,这是使用列表解析的一个主要的性能优点.

遍历
1.通过序列取元素的方法进行遍历

[email protected]:python# vim 3.py 

#!/usr/bin/python2.5
for i in 'hello':  #序列里的字符串
  print i,

y = [1,2,3,4,5,6]  #列表
for i in y:
  print i,



[email protected]:python# python 3.py 

h e l l o 1 2 3 4 5 6

2.通过序列本身偏移指数(索引)的方法进行遍历

也就是迭代序列索引,注:迭代,重复执行一条指令.

[email protected]:python# vim 3.py 

#!/usr/bin/python2.5
x='hello'
for i in range(len(x)):
  print x[i]

y = [1,2,3,4,5,6]
for i in range(len(y)):
  print y[i],

[email protected]:python# python 3.py 

h e l l o 1 2 3 4 5 6

字典有2种方式取到其值:

1.先取字典key,在取索引的值

[email protected]:python# vim 5.py 

#!/usr/bin/python2.5
z = {1:'a',2:'b',3:'c'}
for i in z:
  print z[i]

[email protected]:python# python 5.py 

a
b
c

2.通过字典items方法,获取所有键值对,在利用元组拆分的方法获得对应值.

[email protected]:python# cat 5.py 

#!/usr/bin/python2.5
z = {1:'a',2:'b',3:'c'}
print z.items()
for m,n in z.items():
  print m,n 



[email protected]:python# python 5.py



[(1, 'a'), (2, 'b'), (3, 'c')]
1 a
2 b
3 c

本文介绍python中的while循环、for循环。在python中for可以用于循环,也可用于另一种近亲的列表解析,列表解析是python中非常重要的特性,详细内容见后面的文章。

您可能感兴趣的文章:

  • Python中的迭代器漫谈
  • Python专用方法与迭代机制实例分析
  • python 的列表遍历删除实现代码
  • Python3遍历目录树实现方法
  • Python递归遍历列表及输出的实现方法
  • Python实现遍历数据库并获取key的值
  • Python遍历指定文件及文件夹的方法
  • python中for语句简单遍历数据的方法
  • python通过索引遍历列表的方法
  • python遍历数组的方法小结
  • python遍历类中所有成员的方法
  • Python实现遍历windows所有窗口并输出窗口标题的方法
  • Python通过递归遍历出集合中所有元素的方法
  • Python中的字典遍历备忘

迭代 首先理解下什么是迭代,python中所有从左往右扫面对象的方式都是可迭代的 有哪...

一般来说,python写for循环比写while更容易、方便,而且python中的for比while效率要更高,如果可以,用for而不是while。

while循环

python中的while/for循环和其它语言的while循环有些不一样,它支持else分支。结构如下:

while <CONDITION>:    CODEelse:    CODE_ELSE

注意,condition部分只能是表达式,不能是语句,所以condition中不能包含赋值语句,如while a = x:是错误的。

while和for的else分支表示当正常退出while/for循环的时候所执行的代码分支。所谓正常退出,是指不是通过break跳出的情况,也就是正常把所有循环条件轮完的情况。这对于那些需要通过设置标志位来判断的情况来说非常方便,而标志位通常是用于离开循环的时候,提供一个额外的标记、通知功能,比如退出循环时想找的数据是否找到。

例如搜索一个列表,并在退出时告知是否找到。如果使用标志位来实现,如下:

found = Falsewhile x and not found:    if match:        print("found it")        found = True    else:        x = x[1:]if not found:    print("not found")

如果通过else,则逻辑更清晰:

while x:    if match:        print("found it")        break    x = x[1:]else:    print("not found")

再例如,判断一个数是否是质数。

y = 21x = y // 2while x > 1:    if y % x == 0:        print( y, "has a factor: ", x)        break    x -= 1else:    print("y is a prime")

想象一下如果不使用while的else,上面的功能该如何实现。

pass、break、continue、else

这几个关键字都能用在while/for中。

  • break:退出整个循环(while/for),如果嵌套了循环,则退出break所在的那个层次
  • continue:直接跳到下一次循环
  • else:在循环正常退出(不是break中断的循环)时执行的所执行的默认代码块
  • pass:在python中作为空的占位符,表示什么也不做。比如:
    • if x:pass
    • while x:pass
    • def x():pass
    • class x:pass

在python 3.x中,pass的另一种方式是...,它也表示什么也不做的占位符。

for循环

python中的for是一个通用的序列迭代器,和bash的for语法类似。python中没有for(i=0;i<N;i++)的语法,但for结合range可以实现一样的功能,后文介绍。

for语法:

for i in <Sequence>:    CODEelse:    CODE_ELSE

每次迭代时,for从序列中取一个元素赋值给控制变量i,下一轮迭代取下一个元素再赋值给i。和其它语言不太一样,for中的控制变量不会在for循环完后消失,它会保持最后一个被迭代的元素值。之所以会这样,是因为其它语言中for是一个代码块,而python中for不算是代码块,也就是说没有自己的名称空间。

实际上不止序列,只要是可迭代的对象,都能用for进行遍历。关于什么是可迭代的,将专门在迭代器相关的文章中解释。

例如,遍历一个字符串,因为它是序列。

for i in 'xiaofang':    printprint("var i after: ",i)   # 输出g

遍历一个列表:

L = ["aa","bb","cc"]for i in L:    print

嵌套:

L = ["aa","bb","cc"]for i in L:    for j in i:        print

计算序列中所有数值的和:

L = [1,2,3,4,5]sum = 0for i in L:    sum += iprint

for迭代字典

for迭代字典时,迭代的是key

D = {'a': 1,     'b': 2,     'c': 3}for key in D:    print(key, "=>", D[key])

其它迭代字典的几种方式:

1.通过keys()迭代字典

for k in D.keys():    print(key, "=>", D[key])

2.直接迭代字典的value

for v in D.values():    print

3.同时迭代key和value

for k, v in D.items():    print

for中的赋值和序列解包

for迭代时,实际上是从可迭代对象中取元素并进行赋值的过程,python中各种变量赋值的方式在for中都支持。而且,python中变量赋值是按引用赋值的,所以每次迭代过程中赋值给控制变量的是那个元素的引用,而不是拷贝这个元素并赋值给控制变量。所以,如果赋值给控制变量的是可变对象时,修改控制变量会直接修改原始数据。

例如:

T = [, , ]for i in T:     printfor  in T:    print

输出:

1 23 45 6

for还支持序列解包的赋值形式。

例如:

for  in [(1, 2, 3, 4), (5, 6, 7, 8)]:    print

结果:

1 [2, 3] 45 [6, 7] 8

因为python是按引用赋值的,所以控制变量都是直接指向迭代元素的,而不是拷贝副本后进行赋值。看下面的结果:

L = [1111, 2222]printprintprint("-" * 15)for i in L:    print

输出结果:

4699009646990128---------------4699009646990128

可见,变量i和列表中元素的内存地址是一致的。

正因为是按引用赋值,所以迭代过程中修改赋值给控制变量i的不可变对象时会创建新对象,从而不会影响原始数据,但如果赋值给i的是可变对象,则修改i会影响原始数据。

例如:

L = [1111, 2222]for i in L:    i += 1print

列表L不会改变:

[1111, 2222]

而下面修改控制变量i会改变原始对象:

L = [[1],[1,2],[1,2,3],[1,2,3,4]]for i in L:    i.appendprint

结果:

[[1, 0], [1, 2, 0], [1, 2, 3, 0], [1, 2, 3, 4, 0]]

for + range

python中并没有直接支持for i=0;i<N;i++的for语法,但是,通过for + range(),可以实现类似的功能。

先介绍一下range()。它像Linux下的seq命令功能一样,用来返回一些序列数值。range()返回一个可迭代对象,目前无需知道可迭代对象是什么,只需知道它可以转换成list、tuple、Set,然后可以在通用迭代器for中进行迭代。

>>> rangerange>>> list,set,tuple([0, 1, 2], {0, 1, 2}, 

可见,range()返回的序列值是前闭后开的。

还可以指定起始值,步进。

>>> list(range[1, 2, 3, 4]>>> list(range[-1, 0, 1, 2, 3, 4]>>> list(range[-1, 1, 3]

步进值指定为负数的时候,可以生成降序的序列值。

>>> list(range[10, 9, 8, 7, 6]

range()返回了生成序列值的迭代器后,可以用for来进行迭代。

for i in range:    print

range()还经常用于for中作为序列的索引位。例如:

L = ["a","b","c","d"]for i in range:    print

分析for + range迭代的过程

下面两个例子,在结果上是等价的:

for i in range:    printfor i in [0,1,2]:    print

但除了结果上,过程并不一样。range()既然返回可迭代对象,说明序列数值是需要迭代一个临时生成一个的,也就是说range()从始至终在内存中都只占用一个数值的内存空间。而[0,1,2]则是在内存中占用一个包含3数值元素的列表,然后for从这个列表对象中按照索引进行迭代。

再通俗地解释下,for i in range开始迭代的时候,生成一个数值0,第二次迭代再生成数值1,第三次迭代再生成数值2,在第一次迭代的时候,1和2都是不存在的。而[0,1,2]则是早就存在于内存中,for通过list类型编写好的迭代器进行迭代,每次迭代从已存在的数值中取一个元素。

所以,在效率上,使用range()要比直接解析列表要慢一点,但是在内存应用上,range()的方式要比直接解析已存在的列表要好,特别是列表较大的时候。一般来说,python中最简单的方式总是最好的、效率很大可能上也是最高的,所以能直接解析的时候,不使用range的效率总会更高一些。

这种效率的区别,也可以应用于其它迭代方式的分析上。例如,按行读取文件的两种方式:

for i in open("filename"):    printfor i in open("filename").readlines():    print

第一种方式,open()返回一个文件迭代器,每次需要迭代的时候才会去读需要的那一行,也就是说从始至终在内存中都只占用一行数据的空间。而第二种通过readlines()读取时,它会一次性将文件中所有行都读取到一个列表中,然后for去迭代这个列表。如果文件比较大,第二种方式可能会占用比较大的内存,甚至可能比原文件大小还要大,因为很可能会一次性为400M的文件分配500M内存,以免后续不断的内存分配。

for + range的步进以及分片

无论是range(),还是序列的分片计数,都支持步进。例如步进为2:

>>> list(range[1, 3, 5]>>> L = [1,2,3,4,5]>>> L[::2][1, 3, 5]

它们都能用于for。

for i in range:    printL = [1,2,3,4,5]for i in L[::2]:    print

它们的结果是一样的。但是和前面分析的一样,range除了在内存应用上比较有优势,在效率上是不及直接列表解析的,包括这里分片步进。

for修改列表元素

有一个列表,想要为列表中的值都加1。

L = [1,2,3,4]for i in L:    i += 1

这是无效的,虽然python中是按照引用进行赋值的,但数值类型是不可变类型,所以每次修改i实际上都会创建新的数据对象,并不会直接影响L中的元素。这些前文已经解释过了。

如果想要修改L本身,直接迭代L是没法实现的,可以通过迭代它的索引,然后通过索引的方式来修改L的元素值。例如:

L = [1,2,3,4]for i in range:    L[i] += 1print       # 输出:[2,3,4,5]

通过while也可以实现。但更简单的方式是后面的文章要详细解释的"列表解析":

L = [1,2,3,4]L = [x + 1 for x in L]print

for + zip并行迭代

zip()函数可以将多个序列(实际上是更通用的可迭代对象)中的值一一对应地取出来,然后放进一个元组中。它也返回一个可迭代对象,可以直接通过list/set等函数将它们的内容一次性展现出来。

例如:

L = [1,2,3,4]S = {'a','b','c','d'}>>> zip<zip object at 0x03684148>>>> list[('d', 1), ('a', 2), ('b', 3), ('c', 4)]

注意,集合是无序的,所以这里从S中去的元素是随机顺序的。但无论如何,已经可以看出zip()的功能了:从容器1和容器2中同时取出一个元素,组成元组返回,再取第二个元素返回。

>>> list[, , , ]

如果容器中元素数量不等,则以长度最短的为基准进行截断。例如:

L1 = [1,2,3,4,5]L2 = [11,22,33,44,55,66]L3 = [111,222,333]>>> list(zip)[(1, 11, 111), (2, 22, 222), (3, 33, 333)]

zip()还常用于构造dict,例如:

keys = ['a', 'b', 'c', 'd']values = [1, 3, 5, 7]D = dict(zip(keys, values))>>> D{'a': 1, 'b': 3, 'c': 5, 'd': 7}

了解了zip(),就可以将它结合for来进行并行迭代:从每个zip()返回的元组中取来自各个容器中的元素。

例如:

L1 = [1,2,3,4,5]L2 = [11,22,33,44,55,66]L3 = [111,222,333]for  in zip:    print("%d + %d + %d = %d" % (x, y, z, x + y + z))

结果:

1 + 11 + 111 = 1232 + 22 + 222 = 2463 + 33 + 333 = 369

enumerate()取得索引位和元素

在其他语言中,可能会有专门的工具在迭代每一个序列元素时同时取得这个元素的索引位和元素值。python中可以通过enumerate()来实现。

例如:

>>> L =  ['a', 'b', 'c', 'd']>>> list(enumerate[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]

于是,可以通过for迭代器来迭代enumerate()生成的(index, value)元素:

for  in enumerate:    print

enumerate()还可以用它的第二个参数指定从哪个索引值开始标记索引。例如:

>>> list(enumerate[(2, 'a'), (3, 'b'), (4, 'c'), (5, 'd')]

需要注意的是,像dict这样的类型不应该去用enumerate()去取索引和值,因为它会将dict的key作为元素值,并自己生成数值索引,也就是说dict的value被丢弃了。

>>> D{'a': 1, 'b': 3, 'c': 5, 'd': 7}>>> list(enumerate[(0, 'a'), (1, 'b'), (2, 'c'), (3, 'd')]

for迭代的陷阱

for是一个通用的迭代器,它按照next的方式一次取一个元素,下一轮迭代取下一个元素。所以,如果在for内部修改了正在迭代的序列(所以这里是说可变序列,且特指列表类型),可能会引起一些奇怪现象。

这是for的一个陷阱,或者说是迭代器的一个陷阱:迭代的对象在迭代过程中被修改了。

陷阱一

迭代操作是递归到数据对象中去的,而不是根据变量名进行迭代的。也就是说迭代的对象是内存中的数据对象。

例如:

L = [1,2,3,4]for i in L:    ...

这个for迭代器在迭代刚开始的时候,先找到L所指向的迭代对象,即内存中的[1,2,3,4]。如果迭代过程中如果L变成了一个集合,或另一个列表对象,for的迭代并不会收到影响。但如果是在原处修改这个列表,那么迭代将会收到影响,例如新增元素也会被迭代到。

看下面的例子:

L = ['a','b','c','d','e']## 原处修改列表,新元素f、g也会被迭代for i in L:    if i in "de":        L += ["f", "g"]    print## 创建新列表,新元素f、g不会被迭代for i in L:    if i in "de":        L = L + ["f", "g"]    print

陷阱二

例如,迭代一个列表,迭代过程中删除一个列表元素。

L = ['a','b','c','d','e']for i in L:    if i in "bc":        L.remove        printprint

输出的结果将是:

b['a', 'c', 'd', 'e']

这个for循环的本意是想删除b、c元素,但结果却只删除了b。通过结果可以发现,c根本就没有被for迭代。之所以会这样,是因为迭代到b的时候,满足if条件,然后删除了列表中的b元素。正因为删除操作,使得列表中b后面的元素整体前移一个位置,也就是c元素的索引位置变成了index=1,而index=1的元素已经被for迭代过,使得c幸运地逃过了for的迭代。

如果迭代并修改的是集合或字典呢?将会报错。虽然它们是可变序列,但是它们是以hash key作为迭代依据的,只要增、删元素,就会导致整个对象的顺序hash key发生改变,这显然是编写这两种类型的迭代器时所需要避免的问题。如下:

D = {'a':1,     'b':2,     'c':3,     'd':4,     'e':5}for i in D:    if i in "bc":        L.remove        printprint

报错:

bTraceback (most recent call last):  File "g:/pycode/lists.py", line 12, in <module>    for i in D:RuntimeError: dictionary changed size during iteration

S = {'a','b','c','d','e'}for i in S:    if i in "bc":        S.remove        printprint

报错:

bTraceback (most recent call last):  File "g:/pycode/lists.py", line 4, in <module>    for i in L:RuntimeError: Set changed size during iteration

迭代并修改集合、字典是非常常见的需求,但很多第三方模块在迭代并修改它们的时候都隐隐忽略了这种问题。那么如何实现这种需求且不会出错?可以考虑迭代它们的副本,并修改它们自身

例如:

D = {'a':1,'b':2,'c':3,'d':4,'e':5}for i in D.copy():    if i in "bc":        D.pop        printprintS = {'a','b','c','d','e'}for i in S.copy():    if i in "bc":        S.remove        printprint

结果:

bc{'a': 1, 'd': 4, 'e': 5}cb{'e', 'd', 'a'}

注意,别使用dict的keys()函数,在python 2.x是可以的,因为返回的是一个列表,但是在python 3.x中,它返回的是一个迭代器。

除了使用copy(),使用其它的方式也可以,只要保证迭代的对象和修改的对象不是同一个对象即可。例如,list()方法转换Set/Dict,在转换的过程中会创建新的数据对象,所以迭代和修改操作是互不影响的。

D = {'a':1,'b':2,'c':3,'d':4,'e':5}for i in list:    if i in "bc":        D.pop        printprint

本文由小鱼儿玄机二站发布于编程应用,转载请注明出处:Python循环结构用法,比如讲授怎么样在Python编制

关键词: