4 更多流程控制语句
除了刚才介绍的while语句,Python也引入了其它语言常见的流程控制语法,并稍作变化。
4.1 if语句
或许最广为人知的控制语句就是if语句。例如:
>>> x = int(input("Please enter an integer: "))
Please enter an integer: 42
>>> if x < 0:
... x = 0
... print('Negative changed to zero')
... elif x == 0:
... print('Zero')
... elif x == 1:
... print('Single')
... else:
... print('More')
...
More
if语句可以有零个或者更多elif
分支,else
分支是非强制要求有的。关键词‘elif’是比‘else if’短的,这可以有效避免过度缩进问题。而且,if … elif … elif …
语句可以替换其它语言中的switch/case
语句。
4.2. for Statements
Python中的for语句与你可能用过的C或者Pascal语言中的for语句有点不同。与通常通过一个等差数列进行迭代(像Pascal语言),或者给予用户自主迭代和终止步骤(就像C语言),Python的For语句以集合(list或者string)中的元素为迭代单元,按照它们在集合中的顺序逐个迭代。例如(我并没有含沙射影):
>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words:
... print(w, len(w))
...
cat 3
window 6
defenestrate 12
如果你需要在迭代中时修改集合(例如为集合复制某个元素),我们建议你先为集合创建副本。直接迭代集合并不能为集合创建副本,切片操作可以很方便的做到这一点。
>>> for w in words[:]: # Loop over a slice copy of the entire list.
... if len(w) > 6:
... words.insert(0, w)
...
>>> words
['defenestrate', 'cat', 'window', 'defenestrate']
靠着使用for w in words:
语法,我们可以用不断插入defenestrate
单词,来尝试创建出很大的集合。
4.3. range()函数
如果你需要迭代一组连续数字,内建函数range()正好可以帮上忙。它生成递增数列:
>>> for i in range(5):
... print(i)
...
0
1
2
3
4
指定的尾数入参永远不是生成序列的一部分; range(10)生成十个数字,代表着会生成十个长度的序列。我们甚至可以让序列从另一个数字开始,或者指定另一个递增值(尽管被否认,但它有时被称为‘步长’):
range(5, 10)
5, 6, 7, 8, 9
range(0, 10, 3)
0, 3, 6, 9
range(-10, -100, -30)
-10, -40, -70
为了迭代集合的索引,我们可以把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()更方便,参见Looping Techniques章节
如果你打印一个range函数,会发生奇怪的事情:
>>> print(range(10))
range(0, 10)
从很多特性上看,rang()函数返回的对象都表现的像是一个list,但实际上它不是。当你迭代它时,它返回了你想要的连续数字,但是它为了节省内存空间,不是个真正的list。
我们称这种对象为可迭代的,即适合成为可以期待得到有限连续项的函数或者结构的目标。我们已经知道,for语句是一个类似的迭代器,list()函数也是一个类似的迭代器;它以可迭代对象创建list。
>>> list(range(5))
[0, 1, 2, 3, 4]
稍后我们可以看到更多函数可以返回可迭代对象,或者把可迭代对象作为入参。
4.4.循环中的break、continue语句和else子句
break语句,就像在C语言中一样,跳出最内层的for或者while循环。
循环语句也许有一个else子句;它在for语句的list循环终结时或者while语句的条件变为false时执行,但在循环被break终结时它并不执行。下面以搜索素数为典型示例演示下:
>>> for n in range(2, 10):
... for x in range(2, n):
... if n % x == 0:
... print(n, 'equals', x, '*', n//x)
... break
... else:
... # loop fell through without finding a factor
... print(n, 'is a prime number')
...
2 is a prime number
3 is a prime number
4 equals 2 * 2
5 is a prime number
6 equals 2 * 3
7 is a prime number
8 equals 2 * 4
9 equals 3 * 3
(是的,这是一段没有错误的代码。仔细看:else子句是属于for循环,而不是if语句)
当与循环一起使用时,它的else子句与在try语句块和if语句块的else子句功能类似:当try语句块没有异常时,else分支触发执行;当循环没有被break终止时,else分支触发执行。想要学习更多try语句块和异常,参见Handling Exceptions
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 # Busy-wait for keyboard interrupt (Ctrl+C)
...
它通常被用于创建一个最小的类:
>>> class MyEmptyClass:
... pass
...
另一个用处是,当你正在写新的代码,可以将pass写在函数体或者条件子句体中,用以标记占位,这使你在更抽象层面思考。pass会被自动忽略。
>>> def initlog(*args):
... pass # Remember to implement this!
...
4.6 函数定义
我们可以写一个可以输出不超过指定边界值的斐波那契数列的函数:
>>> def fib(n): # write Fibonacci series up to n
... """Print a Fibonacci series up to n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')
... a, b = b, a+b
... print()
...
>>> '# Now call the function we just defined:
... fib(2000)
0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597
关键词def定义了一个函数。它后边是函数名字和被括号包括起来的一串参数。函数体的声明是从下一行开始的,而且必须缩进。
函数体的第一行可以是一个随意的字符串数组;字符串数组是函数的文档字符串或者docstring。(更多关于docstring的说明可以在文档API部分找到)。有一些工具可以使用docstrings制作在线文档或者打印文档,或者让用户交互式的浏览代码;在代码中写入docstrings是一个很好的做法,你应该养成习惯。
函数执行时会为局部变量引入一个新的符号表。所有的局部变量都存储在这个局部符号表中。引用参数时,会先从局部符号表中查找,然后是全局符号表,然后是内置命名表。因此,全局参数虽然可以被引用,但它们不能在函数中直接赋值(除非它们在全局声明语句中)。
函数引用的实际参数在函数调用时引入局部符号表,因此,实参总是传值调用(这里的值指的是对象引用,而不是该对象的值)。[1] 一个函数被另一个函数调用时,一个新的局部符号表在调用过程中被创建。
函数的定义过程会在函数当前参数列表前定义函数名字。作为用户定义函数,函数名有一个为解释器认可的类型值。这个值可以赋给其它命名,使其能够作为一个函数来使用。这就像一个重命名机制:
>>>
>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89
类比其它编程语言,你可能认为fib不是一个函数( function ),而是一个过程( procedure )。Python 和 C 一样,过程只是一个没有返回值的函数。实际上,没有显式声明返回值的过程也有一个返回值,虽然是一个不讨人喜欢的值。这个值被称为 None (这是一个内置命名)。如果一个值只是 None 的话,通常解释器不会写一个 None 出来,如果你真想要查看它的话,可以这样做:
>>>
>>> fib(0)
>>> print(fib(0))
None
我们来写一个简单的示例,用于演示如何从函数中返回一个包含菲波那契数列的数值链表,而不是打印它: 、
>>>
>>> def fib2(n): # return Fibonacci series up to n
... """Return a list containing the Fibonacci series up to n."""
... result = []
... a, b = 0, 1
... while a < n:
... result.append(a) # see below
... a, b = b, a+b
... return result
...
>>> f100 = fib2(100) # call it
>>> f100 # write the result
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]
和以往一样,上面的例子演示了一些新的 Python 功能:
- return 语句从函数中返回一个值,不带表达式的 return 返回 None。过程结束后也会返回 None 。
- 语句result.append(b)称为链表对象 result 的一个函数。函数是一个“属于”某个对象的,它被命名为 obj.methodename,这里的 obj 是某个对象(可能是一个表达式),methodename是某个在该对象类型定义中的方法的命名。不同的入参类型定义不同的方法。不同入参类型也有可能名字相同,但不会混淆。(当你定义自己的对象类型和方法时,可能会出现这种情况,本指南后面的章节会介绍如何使用类型)。示例中演示的 append()方法由链表对象定义,它向链表中加入一个新元素。在示例中它等同于””result = result + [b]””,不过效率更高。
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/61740.html