《Python3.6官方文档》– 4.更多流程控制语句

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

(0)
上一篇 2021年8月10日 21:06
下一篇 2021年8月10日

相关推荐

发表回复

登录后才能评论