{ "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": [ "有时,表达式 `` 返回的值有多种情况,并且针对不同的情况我们都要做相应的事情,那么可以这么写:\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 }