python基本教程8(入门教程4)

2021-07-21|

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 语句
Python 的 for 语句与 C 或 Pascal 中的不同。Python 的 for 语句不迭代算术递增数值(如 Pascal),或是给予用户定义迭代步骤和暂停条件的能力(如 C),而是迭代列表或字符串等任意序列,元素的迭代顺序与在序列中出现的顺序一致。 例如:

>>>
>>> # Measure some strings:
... words = ['cat', 'window', 'defenestrate']
>>> for w in words:
...     print(w, len(w))
...
cat 3
window 6
defenestrate 12
遍历某个集合的同时修改该集合的内容,很难获取想要的结果。要在遍历时修改集合的内容,应该遍历该集合的副本或创建新的集合:

# Strategy:  Iterate over a copy
for user, status in users.copy().items():
    if status == 'inactive':
        del users[user]

# Strategy:  Create a new collection
active_users = {}
for user, status in users.items():
    if status == 'active':
        active_users[user] = status
4.3. range() 函数
内置函数 range() 常用于遍历数字序列,该函数可以生成算术级数:

>>>
>>> for i in range(5):
...     print(i)
...
0
1
2
3
4
生成的序列不包含给定的终止数值;range(10) 生成 10 个值,这是一个长度为 10 的序列,其中的元素索引都是合法的。range 可以不从 0 开始,还可以按指定幅度递增(递增幅度称为 '步进',支持负数):

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

>>> list(range(0, 10, 3))
[0, 3, 6, 9]

>>> list(range(-10, -100, -30))
[-10, -40, -70]
range() 和 len() 组合在一起,可以按索引迭代序列:

>>>
>>> a = ['Mary', 'had', 'a', 'little', 'lamb']
>>> for i in range(len(a)):
...     print(i, a)
...
0 Mary
1 had
2 a
3 little
4 lamb
不过,大多数情况下,enumerate() 函数更便捷,详见 循环的技巧 。

如果只输出 range,会出现意想不到的结果:

>>>
>>> range(10)
range(0, 10)
range() 返回对象的操作和列表很像,但其实这两种对象不是一回事。迭代时,该对象基于所需序列返回连续项,并没有生成真正的列表,从而节省了空间。

这种对象称为可迭代对象 iterable,函数或程序结构可通过该对象获取连续项,直到所有元素全部迭代完毕。for 语句就是这样的架构,sum() 是一种把可迭代对象作为参数的函数:

>>>
>>> sum(range(4))  # 0 + 1 + 2 + 3
6
下文将介绍更多返回可迭代对象或把可迭代对象当作参数的函数。 在 数据结构 这一章节中,我们将讨论有关 list() 的更多细节。

4.4. 循环中的 break、continue 语句及 else 子句
break 语句和 C 中的类似,用于跳出最近的 for 或 while 循环。

循环语句支持 else 子句;for 循环中,可迭代对象中的元素全部循环完毕时,或 while 循环的条件为假时,执行该子句;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 语句。)

与 if 语句相比,循环的 else 子句更像 try 的 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 an odd number", num)
...
Found an even number 2
Found an odd number 3
Found an even number 4
Found an odd number 5
Found an even number 6
Found an odd number 7
Found an even number 8
Found an odd 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,详见 文档字符串。利用文档字符串可以自动生成在线文档或打印版文档,还可以让开发者在浏览代码时直接查阅文档;Python 开发者最好养成在代码中加入文档字符串的好习惯。

函数在 执行 时使用函数局部变量符号表,所有函数变量赋值都存在局部符号表中;引用变量时,首先,在局部符号表里查找变量,然后,是外层函数局部符号表,再是全局符号表,最后是内置名称符号表。因此,尽管可以引用全局变量和外层函数的变量,但最好不要在函数内直接赋值(除非是 global 语句定义的全局变量,或 nonlocal 语句定义的外层函数变量)。

在调用函数时会将实际参数(实参)引入到被调用函数的局部符号表中;因此,实参是使用 按值调用 来传递的(其中的 值 始终是对象的 引用 而不是对象的值)。 1 当一个函数调用另外一个函数时,会为该调用创建一个新的局部符号表。

函数定义在当前符号表中把函数名与函数对象关联在一起。解释器把函数名指向的对象作为用户自定义函数。还可以使用其他名称指向同一个函数对象,并访问访该函数:

>>>
>>> fib
<function fib at 10042ed0>
>>> f = fib
>>> f(100)
0 1 1 2 3 5 8 13 21 34 55 89
fib 不返回值,因此,其他语言不把它当作函数,而是当作过程。事实上,没有 return 语句的函数也返回值,只不过这个值比较是 None (是一个内置名称)。一般来说,解释器不会输出单独的返回值 None ,如需查看该值,可以使用 print():

>>>
>>> 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(a) 语句调用了列表对象 result 的 方法 。方法是“从属于”对象的函数,命名为 obj.methodname,obj 是对象(也可以是表达式),methodname 是对象类型定义的方法名。不同类型定义不同的方法,不同类型的方法名可以相同,且不会引起歧义。(用 类 可以自定义对象类型和方法,详见 类 )示例中的方法 append() 是为列表对象定义的,用于在列表末尾添加新元素。本例中,该方法相当于 result = result + [a] ,但更有效。

4.7. 函数定义详解
函数定义支持可变数量的参数。这里列出三种可以组合使用的形式。

4.7.1. 默认值参数
为参数指定默认值是非常有用的方式。调用函数时,可以使用比定义时更少的参数,例如:

def ask_ok(prompt, retries=4, reminder='Please try again!'):
    while True:
        ok = input(prompt)
        if ok in ('y', 'ye', 'yes'):
            return True
        if ok in ('n', 'no', 'nop', 'nope'):
            return False
        retries = retries - 1
        if retries < 0:
            raise ValueError('invalid user response')
        print(reminder)
该函数可以用以下方式调用:

只给出必选实参:ask_ok('Do you really want to quit?')

给出一个可选实参:ask_ok('OK to overwrite the file?', 2)

给出所有实参:ask_ok('OK to overwrite the file?', 2, 'Come on, only yes or no!')

本例还使用了关键字 in ,用于确认序列中是否包含某个值。

默认值在 定义 作用域里的函数定义中求值,所以:

i = 5

def f(arg=i):
    print(arg)

i = 6
f()
上例输出的是 5。

重要警告: 默认值只计算一次。默认值为列表、字典或类实例等可变对象时,会产生与该规则不同的结果。例如,下面的函数会累积后续调用时传递的参数:

def f(a, L=[]):
    L.append(a)
    return L

print(f(1))
print(f(2))
print(f(3))
输出结果如下:

[1]
[1, 2]
[1, 2, 3]
不想在后续调用之间共享默认值时,应以如下方式编写函数:

def f(a, L=None):
    if L is None:
        L = []
    L.append(a)
    return L
4.7.2. 关键字参数
kwarg=value 形式的 关键字参数 也可以用于调用函数。函数示例如下:

def parrot(voltage, state='a stiff', action='voom', type='Norwegian Blue'):
    print("-- This parrot wouldn't", action, end=' ')
    print("if you put", voltage, "volts through it.")
    print("-- Lovely plumage, the", type)
    print("-- It's", state, "!")
该函数接受一个必选参数(voltage)和三个可选参数(state, action 和 type)。该函数可用下列方式调用:

parrot(1000)                                          # 1 positional argument
parrot(voltage=1000)                                  # 1 keyword argument
parrot(voltage=1000000, action='VOOOOOM')             # 2 keyword arguments
parrot(action='VOOOOOM', voltage=1000000)             # 2 keyword arguments
parrot('a million', 'bereft of life', 'jump')         # 3 positional arguments
parrot('a thousand', state='pushing up the daisies')  # 1 positional, 1 keyword
以下调用函数的方式都无效:

parrot()                     # required argument missing
parrot(voltage=5.0, 'dead')  # non-keyword argument after a keyword argument
parrot(110, voltage=220)     # duplicate value for the same argument
parrot(actor='John Cleese')  # unknown keyword argument
函数调用时,关键字参数必须跟在位置参数后面。所有传递的关键字参数都必须匹配一个函数接受的参数(比如,actor 不是函数 parrot 的有效参数),关键字参数的顺序并不重要。这也包括必选参数,(比如,parrot(voltage=1000) 也有效)。不能对同一个参数多次赋值,下面就是一个因此**而失败的例子:

>>>
>>> def function(a):
...     pass
...
>>> function(0, a=0)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: function() got multiple values for keyword argument 'a'
最后一个形参为 **name 形式时,接收一个字典(详见 映射类型 --- dict),该字典包含与函数中已定义形参对应之外的所有关键字参数。**name 形参可以与 *name 形参(下一小节介绍)组合使用(*name 必须在 **name 前面), *name 形参接收一个 元组,该元组包含形参列表之外的位置参数。例如,可以定义下面这样的函数:

def cheeseshop(kind, *arguments, **keywords):
    print("-- Do you have any", kind, "?")
    print("-- I'm sorry, we're all out of", kind)
    for arg in arguments:
        print(arg)
    print("-" * 40)
    for kw in keywords:
        print(kw, ":", keywords[kw])
该函数可以用如下方式调用:

cheeseshop("Limburger", "It's very runny, sir.",
           "It's really very, VERY runny, sir.",
           shopkeeper="Michael Palin",
           client="John Cleese",
           sketch="Cheese Shop Sketch")

标签: 函数 形参 参数 可以 语句 定义 关键字 print 对象 位置

推荐

文明发言,请先登录

文明上网理性发言,请遵守国家法律法规。

最新评论

©2003- 黑基网 黑名单存档手机版网站地图免责条款法律声明隐私保护