{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "fe5f0fb1",
   "metadata": {},
   "source": [
    "# 第 6 讲｜Python 函数与模块：参数、返回值与代码复用\n",
    "\n",
    "函数是一段有名字、可以重复调用的代码。本课按照“概念 → 示例代码 → 代码解读 →\n",
    "动手练习”学习函数，并使用销售、商品和订单数据作为练习背景。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5cad22bf",
   "metadata": {},
   "source": [
    "## 训练路线\n",
    "\n",
    "| 阶段 | 学习内容 | 目标 |\n",
    "|---|---|---|\n",
    "| 一 | 定义、调用、参数 | 会把一段操作封装成函数 |\n",
    "| 二 | 默认参数与返回值 | 会向函数传入数据并接收结果 |\n",
    "| 三 | 作用域与函数协作 | 会把较长任务拆成多个小函数 |\n",
    "| 四 | 可变参数、lambda、递归 | 能阅读教材和竞赛代码中的特殊函数 |\n",
    "| 五 | 综合实训 | 使用多个函数完成订单金额计算 |\n",
    "\n",
    "本课的重点是“一个函数只负责一件清楚的事”。先保证函数名、参数和返回值容易理解，\n",
    "再追求代码简短。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c94f26c5",
   "metadata": {},
   "source": [
    "## 教材内容取舍\n",
    "\n",
    "依据 6f 教材，本课完整覆盖定义与调用、参数、默认参数、返回值、局部变量和全局变量，\n",
    "并安排可变参数、匿名函数和递归函数的入门示例。\n",
    "\n",
    "仅限位置参数符号 /、复杂混合参数顺序、嵌套函数定义以及使用 global、nonlocal 修改变量，\n",
    "暂列为阅读拓展。初学阶段优先通过“参数传入、return 返回”交换数据，程序更容易检查。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5de9fb51",
   "metadata": {},
   "source": [
    "## 1. 定义函数与调用函数\n",
    "\n",
    "**学习目标：**会使用 def 定义函数，并使用“函数名加小括号”调用函数。\n",
    "\n",
    "函数定义的基本结构包括：def、函数名、小括号、冒号和缩进的函数体。\n",
    "定义函数时只是在说明“这段代码以后怎样执行”；真正调用时，函数体才会运行。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "29ff8685",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "48bc2ef3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.046055Z",
     "iopub.status.busy": "2026-07-29T17:37:06.045707Z",
     "iopub.status.idle": "2026-07-29T17:37:06.057159Z",
     "shell.execute_reply": "2026-07-29T17:37:06.056634Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "函数已经定义，下面开始调用：\n",
      "欢迎进入 Python 函数训练\n",
      "本函数负责显示两行固定信息\n",
      "再次调用：\n",
      "欢迎进入 Python 函数训练\n",
      "本函数负责显示两行固定信息\n"
     ]
    }
   ],
   "source": [
    "def show_welcome():\n",
    "    print(\"欢迎进入 Python 函数训练\")\n",
    "    print(\"本函数负责显示两行固定信息\")\n",
    "\n",
    "\n",
    "print(\"函数已经定义，下面开始调用：\")\n",
    "show_welcome()\n",
    "print(\"再次调用：\")\n",
    "show_welcome()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a6b638c7",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "show_welcome 是函数名，小括号中暂时没有参数，因此它是无参函数。\n",
    "两条 print 语句属于函数体，必须保持缩进。代码调用了两次 show_welcome，\n",
    "所以相同的两行信息被执行了两次。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c9dcfa8c",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "68c373ee",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.060563Z",
     "iopub.status.busy": "2026-07-29T17:37:06.060332Z",
     "iopub.status.idle": "2026-07-29T17:37:06.062794Z",
     "shell.execute_reply": "2026-07-29T17:37:06.062344Z"
    }
   },
   "outputs": [],
   "source": [
    "# 目标：定义并调用一个显示课程名称的无参函数。\n",
    "# def show_course():\n",
    "#     print(                       )    # 填写课程名称\n",
    "#\n",
    "# show_course()\n",
    "# show_course()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c7c644d2",
   "metadata": {},
   "source": [
    "## 2. 形参与实参：让函数处理不同数据\n",
    "\n",
    "**学习目标：**理解形参和实参，并定义带参数的函数。\n",
    "\n",
    "定义函数时，小括号中的变量称为形参；调用函数时传入的具体数据称为实参。\n",
    "参数让同一个函数可以处理不同输入，而不必复制函数体。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "302ac94c",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "c67484bb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.064822Z",
     "iopub.status.busy": "2026-07-29T17:37:06.064651Z",
     "iopub.status.idle": "2026-07-29T17:37:06.067927Z",
     "shell.execute_reply": "2026-07-29T17:37:06.067486Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "销量： 125\n",
      "退单量： 8\n",
      "实际销量： 117\n",
      "\n",
      "销量： 80\n",
      "退单量： 5\n",
      "实际销量： 75\n"
     ]
    }
   ],
   "source": [
    "def show_actual_sales(sales, returns):\n",
    "    actual_sales = sales - returns\n",
    "    print(\"销量：\", sales)\n",
    "    print(\"退单量：\", returns)\n",
    "    print(\"实际销量：\", actual_sales)\n",
    "\n",
    "\n",
    "show_actual_sales(125, 8)\n",
    "print()\n",
    "show_actual_sales(80, 5)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a276516",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "sales 和 returns 是形参；第一次调用时，125 和 8 是实参。\n",
    "调用发生后，实参按位置交给对应形参，函数使用这两个值计算实际销量。\n",
    "第二次调用不需要修改函数定义，只需传入新的实参。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e7ce443b",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "8e840dce",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.069900Z",
     "iopub.status.busy": "2026-07-29T17:37:06.069757Z",
     "iopub.status.idle": "2026-07-29T17:37:06.072102Z",
     "shell.execute_reply": "2026-07-29T17:37:06.071761Z"
    }
   },
   "outputs": [],
   "source": [
    "# 目标：定义函数，接收单价和数量并输出金额。\n",
    "# def show_amount(price, quantity):\n",
    "#     amount =                         # 单价乘数量\n",
    "#     print(\"金额：\", amount)\n",
    "#\n",
    "# show_amount(12.5, 6)                 # 预期：75.0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b4cb542a",
   "metadata": {},
   "source": [
    "## 3. 位置参数与关键字参数\n",
    "\n",
    "**学习目标：**会使用两种常见的参数传递方式。\n",
    "\n",
    "位置参数按照先后顺序匹配形参；关键字参数写成“参数名=值”，按照名称匹配。\n",
    "参数含义较多时，关键字参数更容易阅读，也可以调整传入顺序。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c2cd1c56",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "2c0a9363",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.073973Z",
     "iopub.status.busy": "2026-07-29T17:37:06.073848Z",
     "iopub.status.idle": "2026-07-29T17:37:06.076780Z",
     "shell.execute_reply": "2026-07-29T17:37:06.076428Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "位置参数：\n",
      "商品： 双肩包\n",
      "价格： 199.0\n",
      "库存： 30\n",
      "关键字参数：\n",
      "商品： 双肩包\n",
      "价格： 199.0\n",
      "库存： 30\n"
     ]
    }
   ],
   "source": [
    "def show_product(name, price, stock):\n",
    "    print(\"商品：\", name)\n",
    "    print(\"价格：\", price)\n",
    "    print(\"库存：\", stock)\n",
    "\n",
    "\n",
    "print(\"位置参数：\")\n",
    "show_product(\"双肩包\", 199.0, 30)\n",
    "\n",
    "print(\"关键字参数：\")\n",
    "show_product(stock=30, name=\"双肩包\", price=199.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b3fecfa5",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "第一次调用按 name、price、stock 的位置依次传值。\n",
    "第二次调用明确写出参数名，因此即使顺序变成 stock、name、price，函数仍能正确匹配。\n",
    "同一次调用中，每个形参只能接收一个值。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "876044c1",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "cd1e4871",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.078664Z",
     "iopub.status.busy": "2026-07-29T17:37:06.078483Z",
     "iopub.status.idle": "2026-07-29T17:37:06.080566Z",
     "shell.execute_reply": "2026-07-29T17:37:06.080202Z"
    }
   },
   "outputs": [],
   "source": [
    "# def show_order(order_id, product, quantity):\n",
    "#     print(order_id, product, quantity)\n",
    "#\n",
    "# show_order(                         )       # 使用位置参数\n",
    "# show_order(                         )       # 使用关键字参数，并调整顺序"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a316975e",
   "metadata": {},
   "source": [
    "## 4. 默认参数：为常用情况准备默认值\n",
    "\n",
    "**学习目标：**为参数设置默认值，并在需要时覆盖默认值。\n",
    "\n",
    "定义函数时写“参数=默认值”，调用时可以省略这个参数。\n",
    "没有默认值的参数必须写在有默认值的参数之前。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "745d46b0",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "061d04e9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.082317Z",
     "iopub.status.busy": "2026-07-29T17:37:06.082176Z",
     "iopub.status.idle": "2026-07-29T17:37:06.084527Z",
     "shell.execute_reply": "2026-07-29T17:37:06.084216Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "双肩包 的计价单位是 元\n",
      "海外商品 的计价单位是 美元\n"
     ]
    }
   ],
   "source": [
    "def show_price(product, currency=\"元\"):\n",
    "    print(product, \"的计价单位是\", currency)\n",
    "\n",
    "\n",
    "show_price(\"双肩包\")\n",
    "show_price(\"海外商品\", currency=\"美元\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d528a439",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "currency 的默认值是“元”。第一次调用没有传入 currency，因此使用默认值；\n",
    "第二次调用传入“美元”，覆盖了默认值。product 没有默认值，所以每次调用都必须提供。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a478285f",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "aa3c9b65",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.086194Z",
     "iopub.status.busy": "2026-07-29T17:37:06.086036Z",
     "iopub.status.idle": "2026-07-29T17:37:06.087908Z",
     "shell.execute_reply": "2026-07-29T17:37:06.087600Z"
    }
   },
   "outputs": [],
   "source": [
    "# 目标：定义运费说明函数，默认地区为“本地”。\n",
    "# def show_shipping(product, region=                 ):\n",
    "#     print(product, \"配送地区：\", region)\n",
    "#\n",
    "# show_shipping(\"双肩包\")\n",
    "# show_shipping(\"旅行箱\", region=\"外地\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e14d63e",
   "metadata": {},
   "source": [
    "## 5. return：把计算结果交回调用处\n",
    "\n",
    "**学习目标：**使用 return 返回一个结果，并用变量接收。\n",
    "\n",
    "print 只负责显示内容；return 会把结果交给调用函数的位置。\n",
    "返回后的结果可以继续参与计算、保存到列表或写入表格。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0587d034",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "7486dc8e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.089576Z",
     "iopub.status.busy": "2026-07-29T17:37:06.089442Z",
     "iopub.status.idle": "2026-07-29T17:37:06.091992Z",
     "shell.execute_reply": "2026-07-29T17:37:06.091706Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "实际销量： 117\n",
      "实际销量的两倍： 234\n"
     ]
    }
   ],
   "source": [
    "def calculate_actual_sales(sales, returns):\n",
    "    actual_sales = sales - returns\n",
    "    return actual_sales\n",
    "\n",
    "\n",
    "result = calculate_actual_sales(125, 8)\n",
    "print(\"实际销量：\", result)\n",
    "\n",
    "doubled_result = result * 2\n",
    "print(\"实际销量的两倍：\", doubled_result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ede32dd4",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "函数内部先计算 actual_sales，再通过 return 把结果交回调用处。\n",
    "result 接收到 117，因此还可以继续进行乘法。若只在函数中 print，就无法方便地复用计算结果。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e4539784",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "f41a2883",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.093579Z",
     "iopub.status.busy": "2026-07-29T17:37:06.093452Z",
     "iopub.status.idle": "2026-07-29T17:37:06.095230Z",
     "shell.execute_reply": "2026-07-29T17:37:06.094936Z"
    }
   },
   "outputs": [],
   "source": [
    "# 目标：返回单价与数量的乘积。\n",
    "# def calculate_amount(price, quantity):\n",
    "#     amount =                         # 请计算金额\n",
    "#     return                           # 请返回金额\n",
    "#\n",
    "# result = calculate_amount(12.5, 6)\n",
    "# print(result)                        # 预期：75.0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "25f0c9d9",
   "metadata": {},
   "source": [
    "## 6. return 提前结束函数\n",
    "\n",
    "**学习目标：**理解 return 不仅返回结果，也会立即结束本次函数调用。\n",
    "\n",
    "先处理不合法或特殊情况并提前 return，可以减少多层嵌套，让函数主线更清楚。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d75b4fe4",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "3e44bad6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.096860Z",
     "iopub.status.busy": "2026-07-29T17:37:06.096735Z",
     "iopub.status.idle": "2026-07-29T17:37:06.099343Z",
     "shell.execute_reply": "2026-07-29T17:37:06.099021Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0 kg： 重量必须大于 0\n",
      "1.5 kg： 12\n",
      "4 kg： 18\n"
     ]
    }
   ],
   "source": [
    "def shipping_fee(weight):\n",
    "    if weight <= 0:\n",
    "        return \"重量必须大于 0\"\n",
    "    if weight <= 2:\n",
    "        return 12\n",
    "\n",
    "    extra_weight = weight - 2\n",
    "    return 12 + extra_weight * 3\n",
    "\n",
    "\n",
    "print(\"0 kg：\", shipping_fee(0))\n",
    "print(\"1.5 kg：\", shipping_fee(1.5))\n",
    "print(\"4 kg：\", shipping_fee(4))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "86da8014",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "weight 不合法时，函数返回提示文本并立即结束；重量不超过 2 kg 时直接返回首重价。\n",
    "只有前两个条件都不满足，程序才继续计算续重费用。每次调用只会执行一条 return 路径。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "150186f0",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "faf76757",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.100974Z",
     "iopub.status.busy": "2026-07-29T17:37:06.100837Z",
     "iopub.status.idle": "2026-07-29T17:37:06.102514Z",
     "shell.execute_reply": "2026-07-29T17:37:06.102252Z"
    }
   },
   "outputs": [],
   "source": [
    "# 目标：负数返回提示，其他数返回它的平方。\n",
    "# def safe_square(number):\n",
    "#     if number < 0:\n",
    "#         return\n",
    "#     return\n",
    "#\n",
    "# print(safe_square(-2))\n",
    "# print(safe_square(5))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "71f3b67d",
   "metadata": {},
   "source": [
    "## 7. 一次返回多个值\n",
    "\n",
    "**学习目标：**从一个函数返回多个相关结果。\n",
    "\n",
    "return 后写多个值时，Python 会把它们组成元组。调用处可以先接收整个元组，\n",
    "也可以使用与返回值数量相同的变量进行解包。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60766f29",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "f82d120c",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.103978Z",
     "iopub.status.busy": "2026-07-29T17:37:06.103855Z",
     "iopub.status.idle": "2026-07-29T17:37:06.106491Z",
     "shell.execute_reply": "2026-07-29T17:37:06.106222Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "完整返回值： (117, 23283.0)\n",
      "实际销量： 117\n",
      "销售额： 23283.0\n"
     ]
    }
   ],
   "source": [
    "def sales_summary(sales, returns, price):\n",
    "    actual_sales = sales - returns\n",
    "    sales_amount = actual_sales * price\n",
    "    return actual_sales, sales_amount\n",
    "\n",
    "\n",
    "summary = sales_summary(125, 8, 199.0)\n",
    "print(\"完整返回值：\", summary)\n",
    "\n",
    "actual_sales, sales_amount = sales_summary(125, 8, 199.0)\n",
    "print(\"实际销量：\", actual_sales)\n",
    "print(\"销售额：\", sales_amount)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "392ba0b5",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "函数返回 actual_sales 和 sales_amount 两个值，完整结果是一个二元素元组。\n",
    "第二次调用使用两个变量按位置解包。左侧变量数量必须与返回值数量一致。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e9252566",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "32477986",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.108063Z",
     "iopub.status.busy": "2026-07-29T17:37:06.107939Z",
     "iopub.status.idle": "2026-07-29T17:37:06.109532Z",
     "shell.execute_reply": "2026-07-29T17:37:06.109253Z"
    }
   },
   "outputs": [],
   "source": [
    "# 目标：同时返回总分和平均分。\n",
    "# def score_summary(score1, score2):\n",
    "#     total =                         # 两项之和\n",
    "#     average =                       # 总分除以 2\n",
    "#     return\n",
    "#\n",
    "# total, average = score_summary(80, 90)\n",
    "# print(total, average)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "75abd4eb",
   "metadata": {},
   "source": [
    "## 8. 局部变量与全局变量\n",
    "\n",
    "**学习目标：**区分函数内部和函数外部的变量。\n",
    "\n",
    "函数内部创建的变量是局部变量，只在该函数中使用；函数外部创建的是全局变量，\n",
    "函数内部可以读取它。不同函数中的同名局部变量互不影响。\n",
    "\n",
    "初学阶段不直接修改全局变量，优先用参数传入、return 返回。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "967ca890",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "848e0bc6",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.111024Z",
     "iopub.status.busy": "2026-07-29T17:37:06.110924Z",
     "iopub.status.idle": "2026-07-29T17:37:06.113100Z",
     "shell.execute_reply": "2026-07-29T17:37:06.112842Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Python 数据分析｜双肩包\n",
      "函数外仍可使用全局变量： Python 数据分析\n"
     ]
    }
   ],
   "source": [
    "course_name = \"Python 数据分析\"\n",
    "\n",
    "\n",
    "def build_label(product):\n",
    "    local_label = course_name + \"｜\" + product\n",
    "    return local_label\n",
    "\n",
    "\n",
    "label = build_label(\"双肩包\")\n",
    "print(label)\n",
    "print(\"函数外仍可使用全局变量：\", course_name)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f52e6638",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "course_name 定义在函数外，是全局变量；build_label 可以读取它。\n",
    "local_label 定义在函数内，是局部变量，函数使用 return 把它的值交给外部的 label。\n",
    "这种写法不需要 global，数据流向更容易追踪。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b1a6f541",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "f7754d6f",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.114474Z",
     "iopub.status.busy": "2026-07-29T17:37:06.114368Z",
     "iopub.status.idle": "2026-07-29T17:37:06.115951Z",
     "shell.execute_reply": "2026-07-29T17:37:06.115705Z"
    }
   },
   "outputs": [],
   "source": [
    "# tax_rate = 0.06\n",
    "#\n",
    "# def calculate_tax(amount):\n",
    "#     tax =                          # 使用全局 tax_rate\n",
    "#     return\n",
    "#\n",
    "# result = calculate_tax(100)\n",
    "# print(result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9355976a",
   "metadata": {},
   "source": [
    "## 9. 函数调用函数：把任务拆成小步骤\n",
    "\n",
    "**学习目标：**让一个函数复用另一个函数的结果。\n",
    "\n",
    "较长任务可以拆成多个单一职责函数。上层函数负责组织步骤，下层函数负责具体计算。\n",
    "这样修改某个计算规则时，只需改动对应的小函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f2c8b057",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "2f053e65",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.117318Z",
     "iopub.status.busy": "2026-07-29T17:37:06.117230Z",
     "iopub.status.idle": "2026-07-29T17:37:06.119541Z",
     "shell.execute_reply": "2026-07-29T17:37:06.119295Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "销售额： 23283.0\n"
     ]
    }
   ],
   "source": [
    "def calculate_actual_sales(sales, returns):\n",
    "    return sales - returns\n",
    "\n",
    "\n",
    "def calculate_sales_amount(sales, returns, price):\n",
    "    actual_sales = calculate_actual_sales(sales, returns)\n",
    "    return actual_sales * price\n",
    "\n",
    "\n",
    "result = calculate_sales_amount(125, 8, 199.0)\n",
    "print(\"销售额：\", result)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8abc7671",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "calculate_sales_amount 没有重复书写“销量减退单量”，而是调用\n",
    "calculate_actual_sales 得到实际销量，再计算销售额。函数定义应先于调用，\n",
    "被调用函数的返回值可以直接保存到局部变量。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "883e8cd9",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "ae927e56",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.120941Z",
     "iopub.status.busy": "2026-07-29T17:37:06.120851Z",
     "iopub.status.idle": "2026-07-29T17:37:06.122630Z",
     "shell.execute_reply": "2026-07-29T17:37:06.122350Z"
    }
   },
   "outputs": [],
   "source": [
    "# def calculate_subtotal(price, quantity):\n",
    "#     return\n",
    "#\n",
    "# def calculate_total(price, quantity, shipping):\n",
    "#     subtotal =                         # 调用 calculate_subtotal\n",
    "#     return\n",
    "#\n",
    "# print(calculate_total(12.5, 6, 5))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bd0fed5e",
   "metadata": {},
   "source": [
    "## 10. 函数处理列表和字典\n",
    "\n",
    "**学习目标：**把一条字典记录交给函数处理，并返回新的结果字典。\n",
    "\n",
    "真题中的一行商品数据通常表示为字典，多行记录组成列表。\n",
    "函数接收一条记录后，可以通过键读取字段，再返回整理后的字典。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c1d54ce",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "430bf3e0",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.124392Z",
     "iopub.status.busy": "2026-07-29T17:37:06.124267Z",
     "iopub.status.idle": "2026-07-29T17:37:06.127036Z",
     "shell.execute_reply": "2026-07-29T17:37:06.126774Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'商品': '双肩包', '实际销量': 117, '销售额': 23283.0}\n",
      "{'商品': '旅行箱', '实际销量': 75, '销售额': 22425.0}\n"
     ]
    }
   ],
   "source": [
    "def summarize_product(record):\n",
    "    actual_sales = record[\"销量\"] - record.get(\"退单量\", 0)\n",
    "    sales_amount = actual_sales * record[\"售价\"]\n",
    "    return {\n",
    "        \"商品\": record[\"商品\"],\n",
    "        \"实际销量\": actual_sales,\n",
    "        \"销售额\": sales_amount,\n",
    "    }\n",
    "\n",
    "\n",
    "records = [\n",
    "    {\"商品\": \"双肩包\", \"销量\": 125, \"退单量\": 8, \"售价\": 199.0},\n",
    "    {\"商品\": \"旅行箱\", \"销量\": 80, \"退单量\": 5, \"售价\": 299.0},\n",
    "]\n",
    "\n",
    "for record in records:\n",
    "    print(summarize_product(record))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aaf81c13",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "summarize_product 的参数 record 是一条商品字典。函数读取销量、退单量和售价，\n",
    "计算后返回只包含交付字段的新字典。for 循环逐条调用同一个函数，避免复制计算代码。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2fb7cc2f",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "423aac94",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.128523Z",
     "iopub.status.busy": "2026-07-29T17:37:06.128408Z",
     "iopub.status.idle": "2026-07-29T17:37:06.129925Z",
     "shell.execute_reply": "2026-07-29T17:37:06.129671Z"
    }
   },
   "outputs": [],
   "source": [
    "# def summarize_order(record):\n",
    "#     amount = record[\"单价\"] * record[\"数量\"]\n",
    "#     return {\n",
    "#         \"订单编号\":                         ,\n",
    "#         \"金额\":                             ,\n",
    "#     }\n",
    "#\n",
    "# order = {\"订单编号\": \"A001\", \"单价\": 12.5, \"数量\": 6}\n",
    "# print(summarize_order(order))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2bc1b313",
   "metadata": {},
   "source": [
    "## 11. 拓展：可变参数 args 与 kwargs\n",
    "\n",
    "**学习目标：**读懂参数数量不固定的函数。\n",
    "\n",
    "形参前写一个星号时，多余的位置实参会收集成元组，惯例命名为 args；\n",
    "形参前写两个星号时，关键字实参会收集成字典，惯例命名为 kwargs。\n",
    "\n",
    "这是阅读型拓展；参数数量明确时，优先使用普通形参。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f84c7a95",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "d52737bd",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.131304Z",
     "iopub.status.busy": "2026-07-29T17:37:06.131212Z",
     "iopub.status.idle": "2026-07-29T17:37:06.135109Z",
     "shell.execute_reply": "2026-07-29T17:37:06.134750Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "总销量： 265\n",
      "商品 -> 双肩包\n",
      "销量 -> 125\n",
      "售价 -> 199.0\n"
     ]
    }
   ],
   "source": [
    "def total_sales(*sales_values):\n",
    "    total = 0\n",
    "    for value in sales_values:\n",
    "        total += value\n",
    "    return total\n",
    "\n",
    "\n",
    "def show_fields(**fields):\n",
    "    for key, value in fields.items():\n",
    "        print(key, \"->\", value)\n",
    "\n",
    "\n",
    "print(\"总销量：\", total_sales(125, 80, 60))\n",
    "show_fields(商品=\"双肩包\", 销量=125, 售价=199.0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "01e7ecbe",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "调用 total_sales 时的三个实参被收集到元组 sales_values 中。\n",
    "调用 show_fields 时写出的“名称=值”被收集到字典 fields 中，\n",
    "因此可以使用 items() 同时遍历键和值。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "320428e0",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "61f2ab4e",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.136781Z",
     "iopub.status.busy": "2026-07-29T17:37:06.136653Z",
     "iopub.status.idle": "2026-07-29T17:37:06.138230Z",
     "shell.execute_reply": "2026-07-29T17:37:06.137951Z"
    }
   },
   "outputs": [],
   "source": [
    "# def total_amounts(*amounts):\n",
    "#     total = 0\n",
    "#     for amount in amounts:\n",
    "#         total +=\n",
    "#     return\n",
    "#\n",
    "# print(total_amounts(20, 35, 45))           # 预期：100"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "609433a6",
   "metadata": {},
   "source": [
    "## 12. 拓展：lambda 匿名函数\n",
    "\n",
    "**学习目标：**读懂只包含一个表达式的匿名函数。\n",
    "\n",
    "lambda 参数: 表达式 会创建一个没有正式名称的简单函数。\n",
    "它常作为其他函数的参数，例如指定排序依据。复杂逻辑仍应使用 def。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "41a54260",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "1ff18e04",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.139577Z",
     "iopub.status.busy": "2026-07-29T17:37:06.139484Z",
     "iopub.status.idle": "2026-07-29T17:37:06.142191Z",
     "shell.execute_reply": "2026-07-29T17:37:06.141843Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'商品': '钱包', '销量': 160}\n",
      "{'商品': '双肩包', '销量': 125}\n",
      "{'商品': '旅行箱', '销量': 80}\n"
     ]
    }
   ],
   "source": [
    "products = [\n",
    "    {\"商品\": \"双肩包\", \"销量\": 125},\n",
    "    {\"商品\": \"旅行箱\", \"销量\": 80},\n",
    "    {\"商品\": \"钱包\", \"销量\": 160},\n",
    "]\n",
    "\n",
    "ordered_products = sorted(\n",
    "    products,\n",
    "    key=lambda item: item[\"销量\"],\n",
    "    reverse=True,\n",
    ")\n",
    "\n",
    "for product in ordered_products:\n",
    "    print(product)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "68bcd023",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "sorted 的 key 参数需要一个函数，用于说明“按什么值排序”。\n",
    "lambda item: item[\"销量\"] 接收一条商品字典，并返回它的销量；\n",
    "reverse=True 表示按销量降序。lambda 这里只有一个表达式，没有多行函数体。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "566b2c05",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "2ffc6385",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.143721Z",
     "iopub.status.busy": "2026-07-29T17:37:06.143596Z",
     "iopub.status.idle": "2026-07-29T17:37:06.145355Z",
     "shell.execute_reply": "2026-07-29T17:37:06.145080Z"
    }
   },
   "outputs": [],
   "source": [
    "# products = [\n",
    "#     {\"商品\": \"A\", \"价格\": 20},\n",
    "#     {\"商品\": \"B\", \"价格\": 15},\n",
    "# ]\n",
    "# ordered = sorted(\n",
    "#     products,\n",
    "#     key=lambda item:                         ,\n",
    "# )\n",
    "# print(ordered)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "26815261",
   "metadata": {},
   "source": [
    "## 13. 拓展：递归函数\n",
    "\n",
    "**学习目标：**理解函数调用自身时必须有结束条件。\n",
    "\n",
    "递归把大问题缩小成结构相同的小问题。一个递归函数必须包含：\n",
    "结束条件，以及让问题逐步接近结束条件的递归调用。\n",
    "\n",
    "递归便于理解某些数学或树状问题，但普通循环更适合多数基础数据处理任务。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b0bf582e",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "5988dbf9",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.146756Z",
     "iopub.status.busy": "2026-07-29T17:37:06.146647Z",
     "iopub.status.idle": "2026-07-29T17:37:06.148819Z",
     "shell.execute_reply": "2026-07-29T17:37:06.148533Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "1! = 1\n",
      "5! = 120\n"
     ]
    }
   ],
   "source": [
    "def factorial(number):\n",
    "    if number == 1:\n",
    "        return 1\n",
    "    return number * factorial(number - 1)\n",
    "\n",
    "\n",
    "print(\"1! =\", factorial(1))\n",
    "print(\"5! =\", factorial(5))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bad6fc3e",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "factorial(1) 是结束条件，直接返回 1。number 大于 1 时，\n",
    "函数调用 factorial(number - 1)，使问题规模不断缩小。\n",
    "如果没有结束条件或 number 没有逐步减小，递归将无法正常结束。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fee82439",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "a5baaf37",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.150339Z",
     "iopub.status.busy": "2026-07-29T17:37:06.150225Z",
     "iopub.status.idle": "2026-07-29T17:37:06.151703Z",
     "shell.execute_reply": "2026-07-29T17:37:06.151460Z"
    }
   },
   "outputs": [],
   "source": [
    "# 目标：递归计算 1 + 2 + ... + number。\n",
    "# def recursive_sum(number):\n",
    "#     if number == 1:\n",
    "#         return\n",
    "#     return\n",
    "#\n",
    "# print(recursive_sum(5))               # 预期：15"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5a77f4e4",
   "metadata": {},
   "source": [
    "## 14. 综合实训：用多个函数完成订单计算\n",
    "\n",
    "**任务目标：**把“查价格、验证数量、计算金额”拆成职责清楚的小函数。\n",
    "\n",
    "本例使用固定字典模拟饮品价格表，不使用 input，便于重复运行和修改测试数据。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "815e2cc2",
   "metadata": {},
   "source": [
    "### 示例代码\n",
    "\n",
    "运行代码并观察输出。修改一个输入值后再次运行，比较结果。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "7012f2bb",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.153068Z",
     "iopub.status.busy": "2026-07-29T17:37:06.152979Z",
     "iopub.status.idle": "2026-07-29T17:37:06.155811Z",
     "shell.execute_reply": "2026-07-29T17:37:06.155541Z"
    }
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "可口可乐 × 3： 7.5\n",
      "未知饮品 × 2： 商品不存在\n",
      "脉动 × 0： 数量必须大于 0\n"
     ]
    }
   ],
   "source": [
    "price_table = {\n",
    "    \"可口可乐\": 2.5,\n",
    "    \"冰红茶\": 3.0,\n",
    "    \"脉动\": 3.5,\n",
    "}\n",
    "\n",
    "\n",
    "def get_price(product):\n",
    "    return price_table.get(product, 0)\n",
    "\n",
    "\n",
    "def calculate_order(product, quantity):\n",
    "    price = get_price(product)\n",
    "    if price == 0:\n",
    "        return \"商品不存在\"\n",
    "    if quantity <= 0:\n",
    "        return \"数量必须大于 0\"\n",
    "    return price * quantity\n",
    "\n",
    "\n",
    "print(\"可口可乐 × 3：\", calculate_order(\"可口可乐\", 3))\n",
    "print(\"未知饮品 × 2：\", calculate_order(\"未知饮品\", 2))\n",
    "print(\"脉动 × 0：\", calculate_order(\"脉动\", 0))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "80f50ff4",
   "metadata": {},
   "source": [
    "### 代码解读（对应上方示例）\n",
    "\n",
    "price_table 保存饮品和价格的映射；get_price 只负责查价格；\n",
    "calculate_order 先调用 get_price，再验证商品和数量，最后返回金额。\n",
    "每个函数只承担一个清楚职责，因此更容易单独测试和修改。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "aae96997",
   "metadata": {},
   "source": [
    "### 动手练习\n",
    "\n",
    "根据上方示例补全空位；先预测结果，再取消注释运行。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "9bee1114",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2026-07-29T17:37:06.157303Z",
     "iopub.status.busy": "2026-07-29T17:37:06.157208Z",
     "iopub.status.idle": "2026-07-29T17:37:06.158925Z",
     "shell.execute_reply": "2026-07-29T17:37:06.158692Z"
    }
   },
   "outputs": [],
   "source": [
    "# 目标：补全商品金额函数。\n",
    "# price_table = {\"数据线\": 12.5, \"鼠标\": 59.0}\n",
    "#\n",
    "# def get_price(product):\n",
    "#     return\n",
    "#\n",
    "# def calculate_order(product, quantity):\n",
    "#     price =\n",
    "#     if price == 0:\n",
    "#         return \"商品不存在\"\n",
    "#     if quantity <= 0:\n",
    "#         return \"数量必须大于 0\"\n",
    "#     return\n",
    "#\n",
    "# print(calculate_order(\"数据线\", 6))       # 预期：75.0"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35ff26eb",
   "metadata": {},
   "source": [
    "## 教材中的阅读拓展\n",
    "\n",
    "- **仅限位置参数 /**：限制部分参数只能按位置传入，基础训练暂不要求；\n",
    "- **复杂混合参数**：普通参数、默认参数、args、kwargs 同时出现时规则较多，暂不作为编写要求；\n",
    "- **嵌套函数定义**：函数内部还可以定义函数，当前实训使用多个并列小函数更清楚；\n",
    "- **global 与 nonlocal**：可修改外层变量，但会增加数据流追踪难度，初学阶段优先参数和 return。\n",
    "\n",
    "遇到这些语法时，先判断“输入从哪里来、结果到哪里去”，不要求立即模仿复杂写法。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c63eaf3",
   "metadata": {},
   "source": [
    "## 离场检验\n",
    "\n",
    "1. 定义函数和调用函数分别使用什么语法？\n",
    "2. 形参和实参有什么区别？\n",
    "3. 位置参数和关键字参数怎样匹配形参？\n",
    "4. 默认参数什么时候使用默认值，什么时候被覆盖？\n",
    "5. print 与 return 的作用有什么不同？\n",
    "6. 为什么 return 之后的本次函数调用会结束？\n",
    "7. 函数返回多个值时，完整结果是什么类型？\n",
    "8. 局部变量和全局变量的使用范围有什么不同？\n",
    "9. 为什么较长任务适合拆成多个单一职责函数？\n",
    "10. args 和 kwargs 分别收集成什么数据类型？\n",
    "11. lambda 更适合简单表达式还是复杂多行逻辑？\n",
    "12. 递归函数为什么必须有结束条件？"
   ]
  }
 ],
 "metadata": {
  "course_source": "6f.pdf",
  "course_style": "培训课件：示例代码、对应解读、动手练习",
  "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.9.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
