除了之前介绍的while语句,Python还从其他语言借鉴了一些流程控制功能,并有所改变。
4.1 if语句
也许最有名的是if语句:
x = int(input("Please enter an integer: "))
Please enter an integer: 23
if x < 0:
x = 0
print('负数自动改为0')
elif x == 0:
print ('Zero')
elif x == 1:
print('Single')
else:
print('More')
More
可能会有多个elif,也可以没有。else也是可选的。关键字’elif’是’else if’的缩写,这个可以有效的避免过深的缩进。if ….elif…elif…用于替代其他语言中的switch..case语句。
4.2 for 语句
Python 中的for语句和C或Pascal中的略有不同。通常的循环会根据一个等差数值步进过程,或由用户来定义迭代步骤和终止条件,Python 的for语句依据任意序列(列表或字符串)中的子项,按它们在序列中的顺序来进行迭代。例如:
words = ['cat', 'window', 'defenestrate']
for w in words:
print (w,len(w))
cat 3
window 6
defenestrate 12
在迭代过程中修改迭代序列很不安全(也只有在列表这种可变序列时才会发生这样的情况)。如果你想修改你迭代的序列(例如,复制选择项),你可以迭代它的副本。使用切割标识就可以很方便的做到这一点:
words = ['cat', 'window', 'defenestrate']
for w in words[:]: #迭代副本
if len(w) > 6:
words.insert(0, w) #insert(a,b)方法,在索引a位置添加b元素
words
['defenestrate', 'cat', 'window', 'defenestrate']
4.3.range()函数
如果你需要一个数值序列,内置函数range()会很方便,它生成一个等差级数列表:
for i in range(5):
print(i)
0
1
2
3
4
range(10)
生成了一个包含10个值的链表,它用列表的索引值填充了这个长度为10的列表,所生成的列表中不包括范围中的结束值(头为0,尾为指定数-1)。也可以让range()操作从另一个数值开始,或者还能指定一个不同的步进值(甚至是负数):
range(5, 10) 5到9,取头不取尾
range(0, 10, 3) 0,3,6,9从0开始,到9,不包括10,每步进3个
range(-10 , -100, -30) -10, -40, -70 从-10开始,到-99结束,每步进-1
for i in range(-10 , -100, -1):
print(i, end = ',')
-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,-53,-54,-55,-56,-57,-58,-59,-60,-61,-62,-63,-64,-65,-66,-67,-68,-69,-70,-71,-72,-73,-74,-75,-76,-77,-78,-79,-80,-81,-82,-83,-84,-85,-86,-87,-88,-89,-90,-91,-92,-93,-94,-95,-96,-97,-98,-99,
需要迭代列表索引的话,如下所示结合使用range()与len()
a = ['Mary', 'had', 'a', 'little', 'lamb']
for i in range(len(a)):
print (i, a[i])
0 Mary
1 had
2 a
3 little
4 lamb
不过,这种场合可以方便地使用enumerate(),见5.6循环技巧
如果你只是打印一个序列的话会发生很奇怪的事情:
print(range(10))
range(0, 10)
在不同方面range()函数返回的对象表现为它是一个列表,但事实上它并不是。当你迭代它时,他是一个能够像期望的序列返回连续项的对象
;但为了节省空间, 它并不真正构造列表。
我们称此类对象是可迭代的,适合作为那些期望从某些东西中获得连续项直到结束的函数或结构的一个目标。我们已经见过for语句就是这样一个迭代器。list()函数是另外一个迭代器,它可以从可迭代对象中创建列表:
list(range(5))
[0, 1, 2, 3, 4]
稍后我们会看到更多返回可迭代(对象)和以可迭代(对象)作为参数的函数。
4.4.break和continue语句,以及循环中的else子句
break语句中和C中的类似,用于跳出最近的一级for或while循环。
循环可以有一个else
子句;它在循环迭代完整个列表(对于for)或执行条件为false(对于while) 时执行,但循环被break中止的情况下不会执行。
for n in range(2, 10):
for x in range(2, n):
if n % x == 0:
print(n, 'equals', x, 'x', n//x)
break
else:
#当循环正常走完全程会执行
print (n ,'is a prime number')
2 is a prime number
3 is a prime number
4 equals 2 x 2
5 is a prime number
6 equals 2 x 3
7 is a prime number
8 equals 2 x 4
9 equals 3 x 3
#自己写一个试试
a_list = [1, 3, 5, 7]
for a in a_list:
if a % 2 ==0:
print(a,'是偶数')
break
else:
#如果一个偶数都没有
print("列表内全是奇数")
列表内全是奇数
与循环一起使用时,else
子句与try语句的else
子句比与if语句的else
子句具有更多的共同点:try语句的else
子句在未出现异常时运行,循环的else
在未出现break时运行。更多try语句和异常的内容,参见之后的异常处理。
continue语句是从C中借鉴来的,它表示循环继续执行下一次迭代:
for num in range(2, 10):
if num % 2 == 0:
print("Found an even number", num)
continue
print ("Found a number", num)
Found an even number 2
Found a number 3
Found an even number 4
Found a number 5
Found an even number 6
Found a number 7
Found an even number 8
Found a number 9
4.5. pass语句
pass语句什么都不做,它用于那些语法上必须要有什么语句,但程序什么也不需要做的场合,例如:
while True:
pass
这通常用于创建最小结构的类:
class MyEmptyClass:
pass
另一方面,pass可以在创建新代码时用来做函数或控制体的占位符,可以让你在更抽象的级别上思考。pass可以被忽略:
def initlog(*args):
pass #记得要完善这个函数!
4.6.定义函数
我们可以创建一个用来生成制定便捷的斐波那契数列的函数:
def fib(n): #写出从0到n的斐波那契数
"""打印出从0到n的斐波那契数"""
a, b = 0, 1
while a < n:
print(a, end=' ')
a,b = b, a+b
print()
fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键字def引入了一个函数定义。在其后必须跟有函数名和包括形式参数的圆括号。函数体语句从下一行开始,必须缩进。
函数体的第一行语句
可以是可选的字符串文本,这个字符串是函数的文档字符串
,或者称为docstring.有些工具通过docstrings自动生成在线的或可打印的文档,或者让用户通过代码交互浏览;在你的代码中包含docstrings是一个好的行为,让它成为习惯吧。
函数调用会为函数局部变量生成一个新的符号表。确切的说,所有函数中的变量赋值都是将值存储在局部符号表。变量引用首先在局部符号表中查找,然后是包含函数的局部符号表,然后是全局符号表,最后是内置名字表。因此,全局变量不能在函数中直接赋值(除非使用global语句命名),尽管他们可以被引用。
函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是传值调用
(这里的值总是一个对象引用,而不是该对象的值)。 一个函数被另一个函数调用时,一个新的局部符号表在调用的过程中被创建。
实际上, 引用对象调用 描述的更为准确。如果传入一个可变对象,调用者会看到调用操作带来的任何变化(如子项插入到列表中)。
#此例证明如果传入可变对象,调用者会通过调用操作改变原对象。
def plus_one(num_list):
'''写一个函数试试传入可变对象'''
for n in range(len(num_list)):
num_list[n] += 1
print('number_list in method:', num_list)
num_list = [0,1,2,3,4,5]
plus_one(num_list)
print('number_list not in method:',num_list)
number_list in method: [1, 2, 3, 4, 5, 6]
number_list not in method: [1, 2, 3, 4, 5, 6]
#此例证明如果传入不可变对象,则不会改变原对象
def plus_one(num):
'''写一个函数试试传入不可变对象'''
num += 1
print('number in method:', num)
num = 0
plus_one(num)
print('numbernot in method:',num)
number in method: 1
numbernot in method: 0
一个函数定义会在当前符号表内引入函数名。函数名指代的值(即函数体)有一个被Python解释器认定为用户自定义函数
的类型。这个值可以赋予其他的名字(即变量名),然后它也可以被当做函数使用。这可以帮函数重命名:
fib
<function __main__.fib(n)>
f = fib
f
<function __main__.fib(n)>
f(100)
0 1 1 2 3 5 8 13 21 34 55 89
如果你使用过其他语言,你可能会反对说,fib不是一个函数,因为它不返回任何值。事实上,return语句的函数确实也会返回一个值,虽然是一个相当让人厌烦的值(None)。这个词被称为None
,如果None是唯一的返回值,那么在写的时候荣昌会被解释器忽略而不输出任何内容,如果你想看到这个值的输出内容,请使用print()函数:
fib(0)
print(fib(0))
None
定义一个返回斐波那契数列数字列表
的函数,而不是直接打印它,也是很简单的:
def fib2(n):
'''返回一个从0到n的包含斐波那契数列数字的列表'''
result = []
a, b = 0, 1
while a< n:
result.append(a)
a, b = b, a+b
return result
f100 = fib2(100)
f100
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
和之前一样,这个例子演示了一些新的Python功能:
- return语句从函数中返回一个值,不带表达式的return返回None
。
- 语句result.append(b)称为链表对象result的一个方法
。方法是一个属于某个对象的函数,它被命名为obj.methodename
, 这里的obj
是某个对象(可能是一个表达式),methodename
是某个在该对象类型定义中的方法的命名。
不同的类型定义不同的方法。不用类型可能有同样名字的方法,但不会混淆。 (当你定义自己的对象类型和方法时,可能会出现这种情况)。示例中演示的append()方法由链表对象定义,它向链表中加入一个新元素。在示例中它等同于result = result + [a],不过效率更高。