PyCourse/流程控制.ipynb

653 lines
17 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# 流程控制"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"无论多么复杂的流程,归根到底就两点:`分支`与`循环`\n",
"```python\n",
"for n in range(2, 100):\n",
" if n == 2:\n",
" print(n)\n",
" continue\n",
" for i in range(2, n):\n",
" if (n % i) == 0:\n",
" break\n",
" else:\n",
" print(n) \n",
"```"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## if 语句"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`if` 语句的最简单构成是这样 —— 注意第 1 行末尾的冒号 `:` 和第 2 行的缩进:\n",
"\n",
"```python\n",
"if expression:\n",
" statements\n",
"```\n",
"\n",
"如果表达式 `expression` 返回值为真,执行 `if` 语句块内部的 `statements`,否则,什么都不做,执行 `if` 之后的下一个语句。"
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"import random\n",
"r = random.randrange(1, 1000)\n",
"\n",
"if r % 2 == 0:\n",
" print(f'{r} is even.')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"如果,表达式 `expression` 返回值无论真假,我们都需要做一点相应的事情,那么我们这么写:\n",
"\n",
"```python\n",
"if expression:\n",
" statements_for_True\n",
"else:\n",
" statements_for_False\n",
"```\n",
"\n",
"如果表达式 `expression` 返回值为真,执行 `if` 语句块内部的 `statements_for_True`,否则,就执行 `else` 语句块内部的 `statements_for_False`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"945 is odd.\n"
]
}
],
"source": [
"import random\n",
"r = random.randrange(1, 1000)\n",
"\n",
"if r % 2 == 0:\n",
" print(f'{r} is even.')\n",
"else:\n",
" print(f'{r} is odd.')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**但是,可以简化!**"
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"even\n"
]
}
],
"source": [
"import random\n",
"r = random.randrange(1, 1000)\n",
"\n",
"def EvenOdd(n):\n",
" if n % 2 == 0:\n",
" return(\"even\")\n",
" return(\"odd\")\n",
"\n",
"print(EvenOdd(r))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"有时,表达式 `<expression>` 返回的值有多种情况,并且针对不同的情况我们都要做相应的事情,那么可以这么写:\n",
"\n",
"```python\n",
"if expression_1:\n",
" statements_for_expression_1_True\n",
" \n",
"elif expression_2:\n",
" statements_for_expression_2_True\n",
"\n",
"elif expression_3:\n",
" statements_for_expression_3_True\n",
"\n",
"elif expression_...:\n",
" statements_for_expression_..._True\n",
"```\n",
"\n",
"`elif` 是 `else if` 的缩写,作用相同。\n",
"\n",
"以下程序模拟投两个骰子的结果 —— 两个骰子数字加起来,等于 `7` 算平,大于 `7` 算大,小于 `7` 算小:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Big!\n"
]
}
],
"source": [
"import random\n",
"r = random.randrange(2, 13)\n",
"\n",
"if r == 7:\n",
" print('Draw!')\n",
"elif r < 7:\n",
" print('Small!')\n",
"elif r > 7:\n",
" print('Big!')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"当然你还可以模拟投飞了的情况,即,最终的骰子数是 `0` 或者 `1`,即,`< 2`"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Small!\n"
]
}
],
"source": [
"import random\n",
"r = random.randrange(0, 13) # 生成的随机数应该从 0 开始了;\n",
"\n",
"if r == 7:\n",
" print('Draw!')\n",
"elif r >= 2 and r < 7: # 如果这里直接写 elif r < 7:那么else: 那一部分永远不会被执行……\n",
" print('Small!')\n",
"elif r > 7:\n",
" print('Big!')\n",
"else:\n",
" print('Not valid!')"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## for 循环"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"value of a: 0\n",
"value of a: 1\n",
"value of a: 2\n",
"value of a: 3\n",
"value of a: 4\n",
"value of a: 5\n",
"value of a: 6\n",
"value of a: 7\n",
"value of a: 8\n",
"value of a: 9\n"
]
}
],
"source": [
"for a in range(10):\n",
" print(f'value of a: {a}') #每次 a 的值都不同,从 0 递增至 9"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### range() 函数"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`range()` 是个内建函数,[它的文档](https://docs.python.org/3/library/functions.html#func-range)是这样写的:\n",
"\n",
"> **range**(_stop_) \n",
">\n",
"> **range**(_start, stop[, step]_)\n",
"\n",
"只有一个参数的时候,这个参数被理解为 `stop`,生成一个从 `0` 开始,到 `stop - 1` 的整数数列。\n"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]"
]
},
"execution_count": 6,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"from IPython.core.interactiveshell import InteractiveShell\n",
"InteractiveShell.ast_node_interactivity = \"all\"\n",
"\n",
"range(10)\n",
"list(range(10)) # 将 range(10) 转换成 list以便清楚看到其内容。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`start` 参数的默认值是 `0`。如需指定起点,那么得给 `range()` 传递两个参数,比如,`range(2, 13)`……"
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]"
]
},
"execution_count": 7,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(range(2, 13))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"第三个参数可选;`step`,步长,就相当于是 “等差数列” 当中的 “差”,默认值是 `1`。例如,`range(1, 10, 2)` 生成的是这样一个数列 `[1, 3, 5, 7, 9]`。所以,打印 `0 10` 之间的所有奇数,可以这样写:"
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"1\n",
"3\n",
"5\n",
"7\n",
"9\n"
]
}
],
"source": [
"for i in range(1, 10, 2):\n",
" print(i)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"我们也可以生成负数的数列:"
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"[0, -1, -2, -3, -4, -5, -6, -7, -8, -9]"
]
},
"execution_count": 9,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"list(range(0, -10, -1))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Continue、Break 和 Pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"在循环的过程中,还可以用 `continue` 和 `break` 控制流程走向,通常是在某条件判断发生的情况下 —— 正如你早就见过的那样:\n",
"\n",
"```python\n",
"for n in range(2, 100):\n",
" if n == 2:\n",
" print(n)\n",
" continue\n",
" for i in range(2, n):\n",
" if (n % i) == 0:\n",
" break\n",
" else:\n",
" print(n) \n",
"```\n",
"\n",
"`continue` 语句将忽略其后的语句开始下次循环,而 `break` 语句将从此结束当前循环.\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`pass` 语句什么都不干:\n",
"\n",
"再比如,\n",
"```python\n",
"def someFunction():\n",
" pass\n",
"```\n",
"\n",
"又或者:\n",
"\n",
"```python\n",
"for i in range(100):\n",
" pass\n",
" if i % 2 == 0:\n",
" pass\n",
"```\n",
"\n",
"`pass` 这个语句更多是给写程序的人用的。当你写程序的时候,你可以用 `pass` 占位,而后先写别的部分,过后再回来补充本来应该写在 `pass` 所在位置的那一段代码。\n",
"\n",
"写嵌套的判断语句或循环语句的时候,最常用 `pass`,因为写嵌套挺费脑子的,一不小心就弄乱了。所以,经常需要先用 `pass` 占位,而后逐一突破。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## while 循环"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"今天,在绝大多数编程语言中,都提供两种循环结构:\n",
"\n",
"> * Collection-controlled loops以集合为基础的循环\n",
"> * Condition-controlled loops以条件为基础的循环\n",
"\n",
"之前的 `for ... in ...` 就是 Collection-controlled loops而在 Python 中提供的 Condition-controlled loops 是 `while` 循环。\n",
"\n",
"`while` 循环的格式如下:\n",
"\n",
"```python\n",
"while expression:\n",
" statements\n",
"```\n",
"\n",
"输出 1000 以内的斐波那契数列的程序如下:"
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"0 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 \n"
]
}
],
"source": [
"n = 1000\n",
"a, b = 0, 1\n",
"while a < n:\n",
" print(a, end=' ')\n",
" a, b = b, a+b\n",
"print()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"`for` 和 `while` 的区别在哪里?什么时候应该用哪个?\n",
"\n",
"`for` 更适合处理序列类型的数据Sequence Type的迭代比如处理字符串中的每一个字符比如把 `range()` 返回的数列当作某种序列类型的索引。\n",
"\n",
"`while` 更为灵活,因为它后面只需要接上一个逻辑表达式即可。"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 一个投骰子赌大小的游戏"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"以下是一个让用户和程序玩掷骰子赌大小的程序。规则如下:\n",
"\n",
">* 每次计算机随机生成一个 `2... 12` 之间的整数,用来模拟机器人投两个骰子的情况;\n",
"* 机器人和用户的起始资金都是 10 个硬币\n",
"* 要求用户猜大小:\n",
" * 用户输入 `b` 代表 “大”;\n",
" * 用户输入 `s` 代表 “小”;\n",
" * 用户输入 `q` 代表 “退出”;\n",
"* 用户的输入和随机产生的数字比较有以下几种情况:\n",
" * 随机数小于 `7`,用户猜小,用户赢;\n",
" * 随机数小于 `7`,用户猜大,用户输;\n",
" * 随机数等于 `7`,用户无论猜大还是猜小,结局平,不输不赢;\n",
" * 随机数大于 `7`,用户猜小,用户输;\n",
" * 随机数大于 `7`,用户猜大,用户赢;\n",
"* 游戏结束条件:\n",
" * 机器人和用户,若任意一方硬币数量为 `0`,则游戏结束;\n",
" * 用户输入了 `q` 主动终止游戏。\n",
"\n"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"You: 10\t Bot: 10\n",
"The dice is 12;\n",
"You WIN!\n",
"\n",
"You: 11\t Bot: 9\n",
"The dice is 9;\n",
"You WIN!\n",
"\n",
"You: 12\t Bot: 8\n",
"The dice is 9;\n",
"You WIN!\n",
"\n",
"You: 13\t Bot: 7\n",
"The dice is 8;\n",
"You WIN!\n",
"\n",
"You: 14\t Bot: 6\n",
"The dice is 8;\n",
"You WIN!\n",
"\n",
"You: 15\t Bot: 5\n",
"The dice is 8;\n",
"You WIN!\n",
"\n",
"You: 16\t Bot: 4\n"
]
}
],
"source": [
"from random import randrange\n",
"\n",
"coin_user, coin_bot = 10, 10 # 可以用一个赋值符号分别为多个变量赋值\n",
"rounds_of_game = 0\n",
"\n",
"def bet(dice, wager): # 接收两个参数,一个是骰子点数,另一个用户的输入\n",
" if dice == 7:\n",
" print(f'The dice is {dice};\\nDRAW!\\n') # \\n 是换行符号\n",
" return 0\n",
" elif dice < 7:\n",
" if wager == 's':\n",
" print(f'The dice is {dice};\\nYou WIN!\\n')\n",
" return 1\n",
" else:\n",
" print(f'The dice is {dice};\\nYou LOST!\\n')\n",
" return -1\n",
" elif dice > 7:\n",
" if wager == 's':\n",
" print(f'The dice is {dice};\\nYou LOST!\\n')\n",
" return -1\n",
" else:\n",
" print(f'The dice is {dice};\\nYou WIN!\\n')\n",
" return 1\n",
"\n",
"while True: # 除 for 之外的另外一个循环语句\n",
" print(f'You: {coin_user}\\t Bot: {coin_bot}')\n",
" dice = randrange(2, 13) # 生成一个 2 到 12 的随机数\n",
" wager = input(\"What's your bet? \")\n",
" if wager == 'q':\n",
" break \n",
" elif wager in 'bs': # 只有当用户输入的是 b 或者 s 得时候,才 “掷骰子”……\n",
" result = bet(dice, wager)\n",
" coin_user += result # coin_user += result 相当于 coin_user = coin_user + result\n",
" coin_bot -= result\n",
" rounds_of_game += 1\n",
" if coin_user == 0:\n",
" print(\"Woops, you've LOST ALL, and game over!\")\n",
" break\n",
" elif coin_bot == 0:\n",
" print(\"Woops, the robot's LOST ALL, and game over!\")\n",
" break\n",
" \n",
"print(f\"You've played {rounds_of_game} rounds.\\n\")\n",
"print(f\"You have {coin_user} coins now.\\nBye!\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## 总结"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"有控制流,才能算得上是程序。\n",
"\n",
"> * 只处理一种情况,用 `if ... `\n",
"> * 处理 `True`/`False` 两种情况,用 `if ... else ...`\n",
"> * 处理多种情况,用 `if ... elif ... elif ... else ...`\n",
"> * 迭代有序数据类型,用 `for ... in ...`,如果需要处理没有 `break` 发生的情况,用 `for ... else ...`\n",
"> * 其它循环,用 `while ...`\n",
"> * 与循环相关的语句还有 `continue`、`break`、`pass`\n",
"> * 函数从控制流角度去看其实就是子程序"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.4"
}
},
"nbformat": 4,
"nbformat_minor": 2
}