while 循环

一般格式:

[python] view plain copy
while <test>:  
    <statements1>  
else <test>:  
    <statements2>  
else为可选部分,当控制权离开循环而又没有碰到break语句时会执行。
[python] view plain copy
>>> x = 'spam'  
>>> while x :  
    print (x,end=' ')  
    x = x[1:]  
  
      
spam pam am m   
注意:这里使用end = ' '关键字参数,使所有输出都出现在同一行,之间用空格隔开
------------------------------------------------------------------------------------------------------------------------------------------------
break、continue、pass和循环else

break:跳出最近所在的循环(跳过整个循环语句)
continue:跳到最近所在循环的开头处(来到循环的首行)
pass:什么事也不做,只是空占位语句
循环else块:只有当循环正常离开时才会执行(也就是没有碰到break语句)

------------------------------------------------------------------------------------------------------------------------------------------------

一般循环格式

加入break和continue后,while的一般循环格式变为:

[python] view plain copy
while <test1>:  
    <statements1>  
    if <test2>:break  
    if <test3>:continue  
else:  
    <statements2>  
------------------------------------------------------------------------------------------------------------------------------------------------
pass语句是无运算的占位语句,当语法需要语句并且还没有任何使用的语句可写时,就可以使用它。它通常用于为复合语句编写一个空的主体。例如,如果想写个无限循环,每次迭代什么也不做,就写个pass
[python] view plain copy
>>> while True :pass  
因为主体只是空语句,Python陷入了死循环,这个程序并没有什么用处。以后将会看到它更有意义的用处。例如,忽略try语句所捕获的异常,以及定义带属性的空类对象,而该类实现的对象行为就像其他语言的结构和记录。pass有时指的是“以后会填上”,只是暂时用于填充函数主体而已
[python] view plain copy
def func1():  
    pass  
  
def func2():  
    pass  
我们无法保持函数体为空而不产生语法错误,因此,可以使用pass来替代
【另外:在Python3.0以后,程序中可以使用三个点...来代替pass,这样似乎更加简洁明了】
------------------------------------------------------------------------------------------------------------------------------------------------

continue语句会立即跳到循环的顶端,即跳过本次循环,执行下一次循环

break 语句会立即离开循环

[python] view plain copy
>>> while True:  
    name = input('Enter name:')  
    if name == 'stop':break  
    age = input('Enter age:')  
    print('Hello',name,'=>',int(age)**2)  
  
      
Enter name:Gavin  
Enter age:2  
Hello Gavin => 4  
Enter name:Spam  
Enter age:20  
Hello Spam => 400  
Enter name:stop  
------------------------------------------------------------------------------------------------------------------------------------------------
循环else
和循环else子句结合时,break语句通常可以忽略其他语言中所需要的搜索状态标志位。

例如,下列程序搜索大于1的因子,来决定正整数y是否为质数:

[python] view plain copy
>>> def judge(y):  
    x = y//2  
    while x >1:  
        if y % x ==0:  
            print(y,'has factor',x)  
            break  
        x -= 1  
    else:  
        print(y,'is prime')  
  
          
>>> judge(8)  
8 has factor 4  
>>> judge(19)  
19 is prime  
>>> judge(119)  
119 has factor 17  
除了设置标志位在循环结束时进行测试外,也可以在找到因子时插入break。这样一来,循环else分句可以视为只有当没有找到因子时才会执行。如果你没有碰到break,该数就是质数。
【注意,当第一次判断while循环条件就不满足时,也就是一次循环也没有进行时,还是会执行else子句的】
=================================================================================

for循环

一般用法:

[python] view plain copy
for <target> in <object>:  
    <statements>  
else:  
    <statements>  
当python运行for循环时,会逐个将序列对象中的元素赋值给目标,然后为每个元素执行循环主体。
for循环也可以用break、continue和else子句

完整格式如下:

[python] view plain copy
for <target>  in <object>:  
    <statements>  
    if <test>:break  
    if <test>:continue  
else:  
    <statements>  
------------------------------------------------------------------------------------------------------------------------------------------------
基础应用:
[python] view plain copy
>>> for x in ['spam','eggs','ham']:  
    print(x,end=  ' ')  
  
      
spam eggs ham  
下面两个例子会计算列表得到所有元素的和与乘积。
[python] view plain copy
>>> s = 0  
>>> for x in [1,2,3,4]:  
    s += x  
  
      
>>> x  #这里x这个变量依然是有值的  
4  
>>> s  
10  
[python] view plain copy
>>> p = 1  
>>> for x in [1,2,3,4]:  
    p *= x  
  
      
>>> p  
24  
在以后,还会知道Python有一些工具,可以自动对列表中的元素应用诸如‘+’和'*'类似的运算,但是使用for循环通常也一样简单
------------------------------------------------------------------------------------------------------------------------------------------------
其他数据类型
不止对于列表适用,for循环对任何序列都适用,for循环还可以应用于字符串和元组,这里就不举例了。
实际上,for循环甚至可以应用在一些根本不是序列的对象上,对于文件和字典也有效。
------------------------------------------------------------------------------------------------------------------------------------------------

在for 循环中的元组赋值

[python] view plain copy
>>> T = [(1,2),(3,4),(5,6)]  
>>> for (a,b) in T:  
    print(a,b)  
  
      
1 2  
3 4  
5 6  
[python] view plain copy
>>> for x in T :  
    print(x)  
  
      
(1, 2)  
(3, 4)  
(5, 6)  
注意上述两个例子的区别。第一个例子可以看做元组解包的赋值运算
这种形式通常和我们将要介绍的zip调用一起使用,以实现并行遍历。在Python中,它通常还和SQL数据库一起使用,其中,查询结果表作为这里使用的列表这样的序列的序列而返回——外围的列表就是数据库表,嵌套的元组是表中的行,元组赋值和列对应
for 循环中的元组使得用items方法来遍历字典中的键和值变得很方便,而不必再遍历键并手动索引以获取值:

[python] view plain copy
>>> D = {'a':1,'b':2,'c':3}  
>>> for key in D:  
    print(key,'=>',D[key])  
  
      
b => 2  
c => 3  
a => 1  
[python] view plain copy
>>> list(D.items())  
[('b', 2), ('c', 3), ('a', 1)]  
>>> for (key,value) in D.items():  
    print(key,'=>',value)  
  
      
b => 2  
c => 3  
a => 1  
注意for循环中的元组赋值并非一种特殊情况,这一点很重要;单词for之后的任何赋值目标在语法上都是有效的。尽管我们总是在for循环中手动地赋值以解包:
[python] view plain copy
>>> for both in T:  
    a,b = both  
    print(a,b)  
  
      
1 2  
3 4  
5 6  
------------------------------------------------------------------------------------------------------------------------------------------------
Python3.0 在for循环中扩展的序列赋值

实际上,for循环中的循环变量真的可以是任何赋值目标,在这里,也可以使用Python3.0的扩展序列解包赋值语法,来提取序列中的序列的元素和部分。

扩展序列赋值可以参考这里
------------------------------------------------------------------------------------------------------------------------------------------------

嵌套for循环

这段代码会在对象列表中搜索每个键,然后报告其搜索结果:

[python] view plain copy
>>> items = ['aaa',111,(4,5),2.01]  
>>> tests = [(4,5),3.14]  
>>> for key in tests:  
    for item in items:  
        if key == item:  
            print(key,'was found')  
            break  
    else:  
        print(key,'not found')  
  
          
(4, 5) was found  
3.14 not found  
=================================================================================
编写循环的技巧
1.内置range函数返回一系列连续增加的整数,可作为for中的索引
2.内置zip函数返回并行元素的元组的列表,可用于在for中内遍历整个序列。
------------------------------------------------------------------------------------------------------------------------------------------------

循环计数器:while和range

range函数是通用的工具,可用在各种环境中,虽然range常用在for循环中来产生索引,但也可以用在任何需要整数列表的地方。在Python3.0中,range是一个迭代器,会根据需要产生元素,因此,我们需要将其包含到一个list调用中以一次性显示其结果:

[python] view plain copy
>>> list(range(5)),list(range(2,5)),list(range(0,10,2))  
([0, 1, 2, 3, 4], [2, 3, 4], [0, 2, 4, 6, 8])  
一个参数时,range会产生从零算起的整数列表,但其中不包括该参数的值;
如果传进两个参数,第一个视为下边界。
第三个选用参数可以提供步进值,使用时,Python会对每个连续整数加上步进值(步进值默认为1).
range也可以是非正数或非递增的:
[python] view plain copy
>>> list(range(-5,5))  
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]  
>>> list(range(5,-5,-2))  
[5, 3, 1, -1, -3]  
从内部实现上来看,for循环以这种方式使用时,会自动处理迭代的细节。如果你真的想要明确得掌控索引逻辑,可以用while循环来实现:
[python] view plain copy
>>> s = 'gavin'  
>>> i = 0  
>>> while i<len(s):  
    print(s[i],end = ' ')  
    i+=1  
  
g a v i n   
------------------------------------------------------------------------------------------------------------------------------------------------
非完备遍历:range和分片
一般情况下,在对序列进行遍历时,最好使用Python中的简单的for循环,不要使用while,并且不要在for循环中使用range调用,只将其视为最后的手段。

[python] view plain copy
>>> for item in X:print(item)  
然而利用range进行索引的用处是,我们可以通过控制range来实现特殊的遍历,例如,在遍历的过程中跳过一些元素
[python] view plain copy
>>> S = 'abcdefghijklmn'  
>>> for i in range(0,len(S),2):print(S[i],end = ' ')  
  
a c e g i k m   
在这里,我们通过所产生的range列表,访问了字符串S中每隔一个的元素,要使用每隔两个的元素,可以把range的第三个参数改为3,以此类推。

然而,这可能不是如今Python中最理想情况下实现的技术,如果你真想跳过序列中的元素,可以用前面介绍的扩展的第三个限制值形式的分片表达式,例如,要使用S中每隔一个的字符串,可以用步进值2来分片:
[python] view plain copy
>>> for item in S[::2]:print(item,end=' ')  
  
a c e g i k m  
结果是相同的,但对我们来说更容易编写,对其他人来说,更容易阅读。
------------------------------------------------------------------------------------------------------------------------------------------------
修改列表:range

可以使用range和for的组合的常见场合就是在循环中遍历列表时对其进行修改。例如,假设你因某种理由要为列表中的每个元素都加1,你可以通过简单的for循环来做,但结果可能不是你想要的:

[python] view plain copy
>>> L = [1,2,3,4,5]  
>>> for x in L:  
    x+=1  
  
      
>>> L  
[1, 2, 3, 4, 5]  
>>> x  
6  
这样并不行,因为修改的是循环变量x,而不是列表L.
要真的在我们遍历列表时对其修改,我们需要使用索引,让我们可以在遍历时替每个位置赋一个一个已更新的值。range/len组合可以替我们产生所需要的索引。
[python] view plain copy
>>> L = [1,2,3,4,5]  
>>> for i in range(len(L)):  
    L[i] +=1  
  
      
>>> L  
[2, 3, 4, 5, 6]  
用while循环也可以做,只是运行比较慢。
[python] view plain copy
[x+1 for x in L]  
这种形式的列表解析表达式也能做类似的工作,而且没有对最初的列表进行在原处的修改(我们可以把表达式的新列表对象赋值给L,但是这样不会更新原始列表的其他任何引用值)。因为这是循环的核心概念,我们将在以后对列表解析做一个完整的介绍。
------------------------------------------------------------------------------------------------------------------------------------------------
并行遍历:zip和map
内置zip函数可以让我们使用for循环来并行使用多个序列,在基本运算中,zip会取得一个或多个序列为参数,然后返回元组的列表,将这些序列中的并排的元素配成对

例如,假设我们要使用两个列表:

[python] view plain copy
>>> A = [1,2,3,4]  
>>> B = [11,22,33,44]  
要合并这些列表中的元素,我们可以使用zip来创建一个元组对的列表(和range一样,zip在Python3.0中也是一个可迭代对象,因此,我们必须将其包含在一个list调用中以便一次性显示所有结果)
[python] view plain copy
>>> C = zip(A,B)  
>>> C  
<zip object at 0x0405BE18>  
>>> list(C)  
[(1, 11), (2, 22), (3, 33), (4, 44)]  
这样的结果在其他环境下也有用,然而搭配for循环中,它就会支持并行迭代:
[python] view plain copy
>>> for (x,y) in zip(A,B):  
    print(x,y,'---',x+y)  
  
      
1 11 --- 12  
2 22 --- 24  
3 33 --- 36  
4 44 --- 48  
zip可以接受任何类型的序列(其实就是任何可迭代的对象,包括文件),并且可以有两个以上的参数。例如
[python] view plain copy
>>> T1,T2,T3 = (1,2,3),(4,5,6),(7,8,9)  
>>> T2  
(4, 5, 6)  
>>> list(zip(T1,T2,T3))  
[(1, 4, 7), (2, 5, 8), (3, 6, 9)]  
当参数长度不同时,zip会以最短序列的长度为准来截断所得到的元组:
[python] view plain copy
>>> S1 = 'abc'  
>>> S2 = 'xyz123'  
>>> list(zip(S1,S2))  
[('a', 'x'), ('b', 'y'), ('c', 'z')]  
------------------------------------------------------------------------------------------------------------------------------------------------
使用zip构造字典
前面介绍过,当键和值的集合必须在运行时计算时,这里所用的zip调用也可用于产生字典,并且非常方便。

假设有下列的键和值的列表:

[python] view plain copy
>>> keys = ['spam','eggs','toast']  
>>> vals=[1,2,3]  
将这些列表变成字典的一种做法就是将这些字符zip起来,并通过for循环并行步进处理:
[python] view plain copy
>>> list(zip(keys,vals))  
[('spam', 1), ('eggs', 2), ('toast', 3)]  
>>> D2 = {}  
>>> for (key,val) in zip(keys,vals):  
    D2[key] = val  
  
      
>>> D2  
{'toast': 3, 'spam': 1, 'eggs': 2}  
不过,在Python2.2和后续版本中,可以完全跳过for循环,直接把zip过的键/值列表传给内置的dict构造函数:
[python] view plain copy
>>> D3 = dict(zip(keys,vals))  
>>> D3  
{'toast': 3, 'spam': 1, 'eggs': 2}  
------------------------------------------------------------------------------------------------------------------------------------------------

产生偏移和元素:enumerate

之前,我们讨论过通过range来产生字符串中元素的偏移值,而不是那些偏移处的元素,不过,在有些程序中,我们两者都需要:需要的元素以及这个元素的偏移值。

可以按照下面这个简单的例子做:

[python] view plain copy
>>> S = 'spam'  
>>> offset = 0  
>>> for item in S:  
    print(item,'appears at offset',offset)  
    offset += 1  
  
      
s appears at offset 0  
p appears at offset 1  
a appears at offset 2  
m appears at offset 3  
不过内置函数enumerate可以为我们做这件事情:
[python] view plain copy
>>> S = 'spam'  
>>> for (offset,item) in enumerate(S):  
    print(item,'appears at offset',offset)  
  
      
s appears at offset 0  
p appears at offset 1  
a appears at offset 2  
m appears at offset 3  
可以看到:
[python] view plain copy
>>> enumerate(S)  
<enumerate object at 0x03602FA8>  
>>> list(enumerate(S))  
[(0, 's'), (1, 'p'), (2, 'a'), (3, 'm')]  
enumerate函数返回一个生成器对象:这种对象支持接下来要学习的迭代协议。简而言之,这个对象有一个__next__方法,由下一个内置函数调用它,并且在循环中每次迭代的时候它会返回一个(index,value)的元祖。我们可以在for循环中通过元组赋值将元组解包(很像是使用zip)
[python] view plain copy
>>> E = enumerate(S)  
>>> E  
<enumerate object at 0x03602F80>  
>>> next(E)  
(0, 's')  
>>> next(E)  
(1, 'p')  
>>> next(E)  
(2, 'a')  
[python] view plain copy
>>> [c*i for (i,c) in enumerate(S)]  
['', 'p', 'aa', 'mmm']