4.其他流程控制工具

4.1 if 语句

4.2 for 语句

在遍历collection的同时修改该collection的内容,最好遍历该collection的副本,或创建新的collection

1
2
3
4
5
6
7
8
9
users = {'Lucy': 'active', 'Bob': 'active', 'Cathy': 'inactive', 
'Candy': 'active', 'Charlie': 'inactive'}

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

print(users)
{'Lucy': 'active', 'Bob': 'active', 'Candy': 'active'}
1
2
3
4
5
6
7
8
9
10
users = {'Lucy': 'active', 'Bob': 'active', 'Cathy': 'inactive', 
'Candy': 'active', 'Charlie': 'inactive'}

# Strategy:: Create a new collection
active_users = {}
for user, status in users.items():
if status == 'active':
active_users[user] = status

print(active_users)
{'Lucy': 'active', 'Bob': 'active', 'Candy': 'active'}

4.3 range() 函数

1
2
3
4
5
# range()会在你迭代它时基于所希望的序列返回连续的项,但它没有真正生成列表,这样就能节省空间。
range(5, 10) # 5, 6, 7, 8, 9
range(0, 10, 3) # 0, 3, 6, 9
range(-10, -100, -30) # -10, -40, -70
sum(range(4)) # 0 + 1 + 2 + 3 = 6
6

4.4 break 和 continue 语句,以及循环中的 else 子句

‘’’ 循环语句可能带有else 子句;它会在循环耗尽了可迭代对象(使用for) 或
循环条件变为假值(使用while) 时被执行,但不会在循环被break 语句终止时被执行。 ‘’’

1
2
3
4
5
6
7
8
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

4.5 pass 语句

pass 语句什么也不做。当语法上需要一个语句,当程序需要什么动作也不做时,可以使用它。

1
2
#   while True:
# pass # Busy-wait for keyboard interrupt (Ctrl+C)
1
2
3
# 通常用于创建最小的类
class MyEmptyClass:
pass
1
2
3
# 编写函数时作为占位符,允许你保持在更抽象的层次上进行思考
def initlog(*args):
pass # Remember to implement this!

4.6 定义函数

1
2
3
4
5
6
7
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()
1
2
# 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 

4.7 函数定义的更多形式

4.7.1 参数默认值

1
2
3
4
5
6
7
8
9
10
11
""" 注意:默认值是在定义过程中在函数定义处计算的 """
i = 5


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


i = 6

f() # 打印值为5
5
1
2
3
4
5
6
7
8
9
10
11
""" 重要警告:默认值只会执行一次。这条规则在默认值为
可变对象(列表、字典以及大多数类实例)时很重要。 """
# 比如,下面的函数会存储在后续调用中传递给它的参数:
def f(a, L=[]):
L.append(a)
return L


print(f(1)) # [1]
print(f(2)) # [1, 2]
print(f(3)) # [1, 2, 3]
[1]
[1, 2]
[1, 2, 3]

4.7.2 关键字参数

1
2
3
4
5
6
""" 也可以使用形如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, "!")
1
2
# 函数调用中,关键字参数必须跟在位置参数的后面,如
parrot(1000000, action='VOOOOOM')
-- This parrot wouldn't VOOOOOM if you put 1000000 volts through it.
-- Lovely plumage, the Norwegian Blue
-- It's a stiff !
1
2
# 但不可以在关键字参数后面跟位置参数,如 
parrot(voltage=5.0, 'dead')
  File "<ipython-input-20-2b2f01aa4584>", line 2
    parrot(voltage=5.0, 'dead')
                       ^
SyntaxError: positional argument follows keyword argument
1
2
3
4
5
6
7
8
9
10
11
12
13
""" 形为 *args 的形参表示任何多个无名参数,它本质是一个 tuple;
形为 **kwargs 的形参表示关键字参数,它本质上是一个 dict;
如果同时使用 *args 和 **kwargs 时,必须 *args 参数列要在 **kwargs 之前。"""


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])
1
2
3
4
5
cheeseshop("Limburger", "It's very runny, sir.",
"It's really very, VERY runny, sir.",
shopkeeper="Michael Palin",
client="John Cleese",
sketch="Cheese Shop Sketch")
-- Do you have any Limburger ?
-- I'm sorry, we're all out of Limburger
It's very runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch
It's really very, VERY runny, sir.
----------------------------------------
shopkeeper : Michael Palin
client : John Cleese
sketch : Cheese Shop Sketch

4.7.3 特殊参数

如果函数定义中未使用 / 和 * ,则参数可以按位置或按关键字传递给函数。

4.7.4 任意的参数列表

最不常用的选项是可以使用任意数量的参数调用函数。这些参数会被包含在一个元组里(参见元组和序列)。在可变数量的参数之前,可能会出现零个或多个普通参数。

1
2
def write_multiple_items(file, separator, *args):
file.write(separator.join(args))

4.7.5 解包参数列表

使用*或**可以将元组/列表或字典解包作为函数的参数

1
2
args = [3, 6]
list(range(*args)) # [3, 4, 5]
[3, 4, 5]
1
2
3
4
def parrot(voltage, state='a stiff', action='voom'):
print("-- This parrot wouldn't", action, end=' ')
print("if you put", voltage, "volts through it.", end=' ')
print("E's", state, "!")
1
2
d = {"voltage": "four million", "state": "bleedin' demised", "action": "VOOM"}
parrot(**d)
-- This parrot wouldn't VOOM if you put four million volts through it. E's bleedin' demised !

4.7.6 Lambda 表达式

1
2
3
""" 可以用lambda 关键字来创建一个小的匿名函数。 """
def make_incrementor(n):
return lambda x: x + n
1
f = make_incrementor(42)
1
f(0)
42
1
f(1)
43

上面的例子使用一个lambda 表达式来返回一个函数。另一个用法是传递一个小函数作为参数:

1
2
pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
pairs.sort(key=lambda pair: pair[1])
1
pairs
[(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]

4.7.7 文档字符串

以下是有关文档字符串的内容和格式的一些约定。

第一行应该是对象目的的简要概述。为简洁起见,它不应显式声明对象的名称或类型,因为这些可通过其他
方式获得(除非名称恰好是描述函数操作的动词)。这一行应以大写字母开头,以句点结尾。

如果文档字符串中有更多行,则第二行应为空白,从而在视觉上将摘要与其余描述分开。后面几行应该是一
个或多个段落,描述对象的调用约定,它的副作用等。

1
2
3
4
5
6
def my_function():
"""Do nothing, but document it.

No, really, it doesn't do anything.
"""
pass
1
print(my_function.__doc__)
Do nothing, but document it.

    No, really, it doesn't do anything.

4.7.8 函数标注

函数标注是关于用户自定义函数中使用的类型的完全可选元数据信息。
函数标注以字典的形式存放在函数的annotations 属性中,并且不会影响函数的任何其他部分。形
参标注的定义方式是在形参名称后加上冒号,后面跟一个表达式,该表达式会被求值为标注的值。返回值标
注的定义方式是加上一个组合符号->,后面跟一个表达式,该标注位于形参列表和表示def 语句结束的冒
号之间。

1
2
3
4
def f(ham: str, eggs: str = 'eggs') -> str:
print("Annotations:", f.__annotations__)
print("Arguments:", ham, eggs)
return ham + ' and ' + eggs
1
f('spam')
Annotations: {'ham': <class 'str'>, 'eggs': <class 'str'>, 'return': <class 'str'>}
Arguments: spam eggs





'spam and eggs'

4.7.8 小插曲:编码风格

对于Python,PEP 8 已经成为大多数项目所遵循的风格指南;它促进了一种非常易读且令人赏心悦目的编码
风格。每个Python 开发人员都应该在某个时候阅读它;以下是提取的最重要的几个要点:

  • 使用4 个空格缩进,不要使用制表符。4 个空格是一个在小缩进(允许更大的嵌套深度)和大缩进(更容易阅读)的一种很好的折中方案。制表符会引入混乱,最好不要使用它。
  • 换行,使一行不超过79 个字符。这有助于使用小型显示器的用户,并且可以在较大的显示器上并排放置多个代码文件。
  • 使用空行分隔函数和类,以及函数内的较大的代码块。
  • 如果可能,把注释放到单独的一行。
  • 使用docstring(文档字符串)。(即__doc__)
  • 在运算符前后和逗号后使用空格,但不能直接在括号内使用:a = f(1, 2) + g(3, 4)。
  • 以一致的规则为你的类和函数命名; 按照惯例应使用UpperCamelCase 来命名类, 而以lowercase_with_underscores 来命名函数和方法。始终应使用self 来命名第一个方法参数(有关类和方法的更多信息请参阅初探类)。
  • 如果你的代码旨在用于国际环境,请不要使用花哨的编码。Python 默认的UTF-8 或者纯ASCII在任何情况下都能有最好的表现。
  • 同样,哪怕只有很小的可能,遇到说不同语言的人阅读或维护代码,也不要在标识符中使用非ASCII字符。
1