{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "3df7a28a",
   "metadata": {},
   "source": [
    "# 第 3 天｜变量、数据类型、比较与逻辑\n",
    "\n",
    "**日期：** 2026 年 7 月 22 日  \n",
    "**核心内容：** 变量与赋值、命名规则、`str/int/float/bool/None`、类型检查、比较、逻辑、边界值\n",
    "\n",
    "Python 中“看起来一样”的值可能具有不同类型。真题中的销量、退单量和售价如果是文本，\n",
    "就不能可靠地做减法、乘法、排序和均值；筛选条件如果不是正确的布尔表达式，也会得到错误样本。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b403080b",
   "metadata": {},
   "source": [
    "## 一、变量、值与赋值\n",
    "\n",
    "```python\n",
    "quantity = 125\n",
    "```\n",
    "\n",
    "执行过程：\n",
    "\n",
    "1. 右边产生整数 `125`；\n",
    "2. Python 建立名称 `quantity`；\n",
    "3. `=` 让名称 `quantity` 指向这个整数对象。\n",
    "\n",
    "可以先把变量理解为“贴在值上的标签”。变量不是固定的盒子，同一个名称可以重新指向新值：\n",
    "\n",
    "```python\n",
    "quantity = 125\n",
    "quantity = 130\n",
    "```\n",
    "\n",
    "第二次赋值后，`quantity` 的当前值是 `130`。Python 按从上到下的顺序执行，\n",
    "后一次赋值会覆盖这个名称之前指向的值。\n",
    "\n",
    "`=` 表示赋值；判断两个值是否相等使用 `==`。不要把数学中的等号含义直接套到赋值语句上。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "213b0def",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "第一次赋值： 125 <class 'int'>\n",
      "重新赋值后： 130 <class 'int'>\n",
      "再次赋值后： 130 <class 'str'>\n"
     ]
    }
   ],
   "source": [
    "quantity = 125\n",
    "print(\"第一次赋值：\", quantity, type(quantity))\n",
    "\n",
    "quantity = 130\n",
    "print(\"重新赋值后：\", quantity, type(quantity))\n",
    "\n",
    "quantity = \"130\"\n",
    "print(\"再次赋值后：\", quantity, type(quantity))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "39d23c4f",
   "metadata": {},
   "source": [
    "## 二、Python 是动态类型语言\n",
    "\n",
    "变量名称本身没有永久固定的类型，类型属于当前指向的值：\n",
    "\n",
    "```python\n",
    "quantity = 125      # 当前指向 int\n",
    "quantity = \"125\"    # 当前改为指向 str\n",
    "```\n",
    "\n",
    "Python 允许这样做，但业务代码中不建议让同一变量在不同位置随意改变类型。\n",
    "稳定做法是使用能提示阶段的变量名：\n",
    "\n",
    "```python\n",
    "quantity_text = \"125\"\n",
    "quantity = int(quantity_text)\n",
    "```\n",
    "\n",
    "类型标注可以表达预期，但不会在运行时自动强制：\n",
    "\n",
    "```python\n",
    "quantity: int = 125\n",
    "quantity = \"125\"    # Python 仍能运行；编辑器或类型检查器可能警告\n",
    "```\n",
    "\n",
    "竞赛代码首先保证运行时类型正确，不能把类型标注当作自动转换或自动验证。\n",
    "\n",
    "已经存在的数值变量可以使用复合赋值：\n",
    "\n",
    "```python\n",
    "quantity += 5    # 等价于 quantity = quantity + 5\n",
    "quantity -= 2\n",
    "total *= 1.1\n",
    "```\n",
    "\n",
    "复合赋值前变量必须已经存在。注意 `/=` 通常会产生浮点数，即使原变量是整数。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4bc64e6f",
   "metadata": {},
   "source": [
    "## 三、变量命名规则\n",
    "\n",
    "合法变量名可以包含英文字母、数字和下划线，但不能以数字开头，也不能使用 Python 关键字。\n",
    "\n",
    "| 名称 | 是否推荐 | 原因 |\n",
    "|---|---|---|\n",
    "| `sales_quantity` | 推荐 | 小写加下划线，业务含义明确 |\n",
    "| `return_rate` | 推荐 | 能看出保存的是退单率 |\n",
    "| `x` | 只适合短小临时计算 | 无法看出业务含义 |\n",
    "| `2price` | 非法 | 不能以数字开头 |\n",
    "| `sales quantity` | 非法 | 变量名中不能有空格 |\n",
    "| `class` | 非法 | `class` 是 Python 关键字 |\n",
    "| `Sales` 与 `sales` | 都合法但不同 | Python 严格区分大小写 |\n",
    "| `销售数量` | 合法但不建议作为竞赛主变量 | 跨工具、协作和输入不方便 |\n",
    "\n",
    "推荐使用 `snake_case`：\n",
    "\n",
    "```python\n",
    "product_name\n",
    "sales_quantity\n",
    "return_quantity\n",
    "unit_price\n",
    "total_sales\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "559d2bb3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "sales_quantity 基本格式合法： True 是否关键字： False\n",
      "2price 基本格式合法： False 是否关键字： False\n",
      "class 基本格式合法： True 是否关键字： True\n",
      "销售数量 基本格式合法： True 是否关键字： False\n"
     ]
    }
   ],
   "source": [
    "import keyword\n",
    "\n",
    "names = [\"sales_quantity\", \"2price\", \"class\", \"销售数量\"]\n",
    "\n",
    "for name in names:\n",
    "    print(\n",
    "        name,\n",
    "        \"基本格式合法：\", name.isidentifier(),\n",
    "        \"是否关键字：\", keyword.iskeyword(name),\n",
    "    )"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4adcab4",
   "metadata": {},
   "source": [
    "## 四、不要覆盖 Python 内置名称\n",
    "\n",
    "以下名称虽然可以用作变量，但会覆盖常用内置工具：\n",
    "\n",
    "```python\n",
    "str = \"文本\"\n",
    "list = [1, 2, 3]\n",
    "sum = 100\n",
    "type = \"VIP\"\n",
    "input = \"完成\"\n",
    "```\n",
    "\n",
    "例如执行 `str = \"文本\"` 后，再写 `str(125)` 会报\n",
    "`TypeError: 'str' object is not callable`。\n",
    "\n",
    "如果在 Notebook 中误覆盖了内置名称：\n",
    "\n",
    "1. 可以执行 `del str` 删除当前变量；\n",
    "2. 更稳妥的是修正变量名并重启内核；\n",
    "3. 建议改用 `text_value`、`numbers`、`total`、`customer_type` 等名称。\n",
    "\n",
    "pandas 常用别名 `pd`、NumPy 常用别名 `np` 也不要再用于保存其他值。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2d0e3e36",
   "metadata": {},
   "source": [
    "## 五、本阶段需要认识的五种值\n",
    "\n",
    "| 类型/值 | 含义 | 示例 | 真题字段 |\n",
    "|---|---|---|---|\n",
    "| `str` | 文本 | `\"双肩包\"` | 店铺名、商品名、付款方式 |\n",
    "| `int` | 整数 | `125` | 销量、退单量、年龄 |\n",
    "| `float` | 浮点数 | `199.0` | 售价、金额、占比 |\n",
    "| `bool` | 逻辑真或假 | `True` | 是否下一页、筛选条件 |\n",
    "| `None` | 暂无值、没有结果 | `None` | 接口缺失值的初步表示 |\n",
    "\n",
    "文本需要引号；数值、`True`、`False` 和 `None` 不加引号，并且大小写固定。\n",
    "`\"True\"`、`\"None\"` 都只是普通字符串。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "99b45aef",
   "metadata": {},
   "source": [
    "## 六、检查类型：`type()` 与 `isinstance()`\n",
    "\n",
    "`type(value)` 返回对象的具体类型：\n",
    "\n",
    "```python\n",
    "type(125)       # int\n",
    "type(\"125\")     # str\n",
    "```\n",
    "\n",
    "`isinstance(value, type_name)` 返回布尔值，更适合程序判断：\n",
    "\n",
    "```python\n",
    "isinstance(125, int)            # True\n",
    "isinstance(125, (int, float))   # True\n",
    "```\n",
    "\n",
    "`type()` 和 `isinstance()` 只检查，不会修改原值。需要改变类型要明确调用\n",
    "`int()`、`float()`、`str()` 等转换函数。\n",
    "\n",
    "一个容易忽略的细节：`bool` 是 `int` 的子类，所以 `isinstance(True, int)` 为 `True`。\n",
    "如果业务字段只允许普通整数而不允许布尔值，可以写：\n",
    "\n",
    "```python\n",
    "type(value) is int\n",
    "```\n",
    "\n",
    "或同时排除 `bool`：\n",
    "\n",
    "```python\n",
    "isinstance(value, int) and not isinstance(value, bool)\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "be9b37ad",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "双肩包 <class 'str'>\n",
      "125 <class 'int'>\n",
      "199.0 <class 'float'>\n",
      "True <class 'bool'>\n",
      "None <class 'NoneType'>\n",
      "quantity 是数值： True\n"
     ]
    }
   ],
   "source": [
    "product_name = \"双肩包\"\n",
    "quantity = 125\n",
    "mall_price = 199.0\n",
    "is_over_100 = quantity > 100\n",
    "coupon_code = None\n",
    "\n",
    "print(product_name, type(product_name))\n",
    "print(quantity, type(quantity))\n",
    "print(mall_price, type(mall_price))\n",
    "print(is_over_100, type(is_over_100))\n",
    "print(coupon_code, type(coupon_code))\n",
    "print(\"quantity 是数值：\", isinstance(quantity, (int, float)))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "522e5151",
   "metadata": {},
   "source": [
    "## 代码解读\n",
    "\n",
    "| 表达式 | 结果 |\n",
    "|---|---|\n",
    "| `product_name = \"双肩包\"` | 保存文本 |\n",
    "| `quantity = 125` | 保存整数 |\n",
    "| `mall_price = 199.0` | 保存浮点数 |\n",
    "| `quantity > 100` | 产生 `True` 或 `False` |\n",
    "| `coupon_code = None` | 明确表示当前没有优惠码 |\n",
    "| `type(quantity)` | 查询变量类型，不修改变量 |\n",
    "| `isinstance(quantity, (int, float))` | 判断是否为整数或浮点数 |\n",
    "\n",
    "`print(product_name)` 输出变量值；`print(\"product_name\")` 输出英文文字本身。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e57dc713",
   "metadata": {},
   "source": [
    "## 七、字符串 `str`\n",
    "\n",
    "字符串是字符序列，可使用单引号或双引号：\n",
    "\n",
    "```python\n",
    "product_name = \"双肩包\"\n",
    "payment_method = '支付宝'\n",
    "```\n",
    "\n",
    "常用基础操作：\n",
    "\n",
    "| 表达式 | 结果 | 含义 |\n",
    "|---|---|---|\n",
    "| `\"商\" + \"品\"` | `\"商品\"` | 拼接文本 |\n",
    "| `\"A\" * 3` | `\"AAA\"` | 重复文本 |\n",
    "| `len(\"双肩包\")` | `3` | 字符数量 |\n",
    "| `\" 包 \".strip()` | `\"包\"` | 删除两端空白 |\n",
    "| `\"VIP\".lower()` | `\"vip\"` | 转为小写 |\n",
    "\n",
    "字符串中的数字仍然是文本：\n",
    "\n",
    "```python\n",
    "\"12\" + \"3\"   # \"123\"\n",
    "12 + 3       # 15\n",
    "```\n",
    "\n",
    "`str` 和 `int` 不能直接相加：`\"销量：\" + 125` 会触发 `TypeError`。\n",
    "可使用 `str(125)` 或下一天学习的 f-string。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d0e1ef73",
   "metadata": {},
   "source": [
    "## 八、整数 `int`\n",
    "\n",
    "整数没有小数部分，可以为正数、负数或零：\n",
    "\n",
    "```python\n",
    "sales_quantity = 125\n",
    "return_quantity = 8\n",
    "stock_change = -3\n",
    "zero_sales = 0\n",
    "```\n",
    "\n",
    "Python 整数可以很大，不受常见 32 位整数范围限制；但进入 pandas、Excel 或数据库后，\n",
    "可能转换成有固定范围的 `int64` 等类型。\n",
    "\n",
    "大整数可用下划线提高可读性：\n",
    "\n",
    "```python\n",
    "annual_sales = 1_250_000\n",
    "```\n",
    "\n",
    "下划线不改变数值，`1_250_000 == 1250000` 为 `True`。\n",
    "\n",
    "业务阈值如果希望按“常量”管理，通常使用全大写名称：\n",
    "\n",
    "```python\n",
    "MIN_SALES_QUANTITY = 100\n",
    "MAX_RETURN_RATE = 0.10\n",
    "```\n",
    "\n",
    "全大写只是团队约定，Python 不会禁止后续重新赋值。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cff2a92a",
   "metadata": {},
   "source": [
    "## 九、浮点数 `float` 与精度\n",
    "\n",
    "`float` 用于带小数的数值，但计算机以二进制近似保存许多十进制小数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "eb3b0d37",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0.30000000000000004\n",
      "False\n",
      "0.3\n"
     ]
    }
   ],
   "source": [
    "result = 0.1 + 0.2\n",
    "\n",
    "print(result)\n",
    "print(result == 0.3)\n",
    "print(round(result, 2))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "181ca389",
   "metadata": {},
   "source": [
    "处理浮点数时：\n",
    "\n",
    "- 展示金额可以使用 `round(value, 2)` 或格式化为两位小数；\n",
    "- 判断两个计算结果是否接近，可使用 `math.isclose()`；\n",
    "- `round()` 改变的是返回结果，不会自动修改原变量；\n",
    "- 对必须精确到分的财务结算，可使用整数“分”或 `decimal.Decimal`；\n",
    "- pandas 中的浮点列也会受到相同的二进制精度影响。\n",
    "\n",
    "```python\n",
    "from math import isclose\n",
    "\n",
    "isclose(0.1 + 0.2, 0.3)   # True\n",
    "```\n",
    "\n",
    "精确十进制示例：\n",
    "\n",
    "```python\n",
    "from decimal import Decimal\n",
    "\n",
    "amount = Decimal(\"0.1\") + Decimal(\"0.2\")\n",
    "print(amount)              # 0.3\n",
    "```\n",
    "\n",
    "创建 `Decimal` 时优先传入字符串，不要先写成已经近似的浮点数。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "228e30f5",
   "metadata": {},
   "source": [
    "## 十、数值运算后的类型\n",
    "\n",
    "| 表达式 | 结果 | 类型 |\n",
    "|---|---:|---|\n",
    "| `5 + 2` | `7` | `int` |\n",
    "| `5 + 2.0` | `7.0` | `float` |\n",
    "| `5 / 2` | `2.5` | `float` |\n",
    "| `4 / 2` | `2.0` | `float` |\n",
    "| `5 // 2` | `2` | `int` |\n",
    "| `5 % 2` | `1` | `int` |\n",
    "| `2 ** 3` | `8` | `int` |\n",
    "\n",
    "`/` 是普通除法，结果通常为 `float`；`//` 是向下取整除法；`%` 取余数；`**` 表示幂。\n",
    "\n",
    "运算优先级与数学类似：括号 → 幂 → 乘除 → 加减。业务公式建议主动加括号：\n",
    "\n",
    "```python\n",
    "net_sales = (sales_quantity - return_quantity) * unit_price\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5d138c5b",
   "metadata": {},
   "source": [
    "## 十一、比较运算与边界值\n",
    "\n",
    "| 运算符 | 含义 | 示例 |\n",
    "|---|---|---|\n",
    "| `>` | 大于 | `quantity > 100` |\n",
    "| `>=` | 大于等于 | `quantity >= 100` |\n",
    "| `<` | 小于 | `price < 50` |\n",
    "| `<=` | 小于等于 | `age <= 30` |\n",
    "| `==` | 等于 | `gender == \"女\"` |\n",
    "| `!=` | 不等于 | `returns != 0` |\n",
    "\n",
    "科图题干中的“销售数量在 100 以上”需要特别确认评分口径：\n",
    "\n",
    "- 严格大于 100：`> 100`\n",
    "- 包含 100：`>= 100`\n",
    "\n",
    "测试 99、100、101 可以检查边界是否写对。\n",
    "\n",
    "Python 支持连续比较：\n",
    "\n",
    "```python\n",
    "60 <= age <= 69\n",
    "```\n",
    "\n",
    "等价于“年龄大于等于 60，并且小于等于 69”。\n",
    "\n",
    "比较值是否相等使用 `==`；`is` 检查是否为同一个对象，初学阶段主要把 `is` 用于\n",
    "`value is None`，不要用 `is` 代替普通数值或字符串的 `==`。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "af0c167c",
   "metadata": {},
   "source": [
    "## 十二、数字与数字文本不能混用"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "993ed032",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "<class 'int'>\n",
      "<class 'str'>\n"
     ]
    }
   ],
   "source": [
    "quantity_number = 125\n",
    "quantity_text = \"125\"\n",
    "\n",
    "print(type(quantity_number))\n",
    "print(type(quantity_text))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6c4f6969",
   "metadata": {},
   "source": [
    "屏幕上都能看到 125，但类型不同：\n",
    "\n",
    "- `125` 可以直接参与数值运算；\n",
    "- `\"125\"` 是文本，需要先转换；\n",
    "- 网页和 CSV 中的数值字段经常被读取成字符串；\n",
    "- pandas 阶段会使用 `astype()` 或 `pd.to_numeric()`。\n",
    "\n",
    "数字文本按字符顺序比较，而不是按数值大小比较：\n",
    "\n",
    "```python\n",
    "\"9\" > \"100\"     # True，因为先比较字符 \"9\" 和 \"1\"\n",
    "9 > 100         # False\n",
    "```\n",
    "\n",
    "Python 3 不允许直接比较文本和数值的大小：`\"9\" > 100` 会触发 `TypeError`。\n",
    "排序、筛选和统计前必须先确认类型。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fc47899f",
   "metadata": {},
   "source": [
    "## 十三、布尔值 `bool`\n",
    "\n",
    "布尔值只有 `True` 和 `False`。最常见来源是比较表达式：\n",
    "\n",
    "```python\n",
    "quantity > 100\n",
    "gender == \"女\"\n",
    "return_quantity != 0\n",
    "```\n",
    "\n",
    "不要把布尔值写成字符串：\n",
    "\n",
    "```python\n",
    "is_valid = True       # 布尔值\n",
    "is_valid = \"True\"     # 普通文本\n",
    "```\n",
    "\n",
    "`True`、`False` 首字母必须大写；`true` 和 `false` 会被当成未定义变量。\n",
    "\n",
    "### 真题中的布尔值\n",
    "\n",
    "- 名仕：`hasNextPage` 控制分页循环；\n",
    "- 科图：`x == \"女\"` 生成布尔序列，布尔均值可以计算女性占比；\n",
    "- 青娅：`df[\"项目\"].isin([...])` 生成布尔筛选条件；\n",
    "- 通用：多个条件可以组合成最终筛选结果。\n",
    "\n",
    "布尔值不是文字 `\"True\"`，也不是随意填写的标签，而是比较或逻辑运算的结果。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "36f3ccda",
   "metadata": {},
   "source": [
    "## 十四、逻辑运算：`and`、`or`、`not`\n",
    "\n",
    "| 运算 | 含义 | 示例 |\n",
    "|---|---|---|\n",
    "| `and` | 两个条件都成立 | `quantity >= 100 and price < 200` |\n",
    "| `or` | 至少一个条件成立 | `city == \"北京\" or city == \"上海\"` |\n",
    "| `not` | 对结果取反 | `not has_next_page` |\n",
    "\n",
    "示例：\n",
    "\n",
    "```python\n",
    "quantity = 125\n",
    "price = 199.0\n",
    "\n",
    "is_target = (quantity >= 100) and (price < 200)\n",
    "print(is_target)   # True\n",
    "```\n",
    "\n",
    "优先级大致为：算术运算 → 比较运算 → `not` → `and` → `or`。\n",
    "多条件业务规则应主动使用括号，让评分者和自己都能看清条件分组。\n",
    "\n",
    "Python 使用短路计算：\n",
    "\n",
    "- `A and B` 中，如果 A 已经为假，B 不再执行；\n",
    "- `A or B` 中，如果 A 已经为真，B 不再执行。\n",
    "\n",
    "可以先检查分母不为零，再计算比例：\n",
    "\n",
    "```python\n",
    "has_valid_rate = (sales_quantity != 0) and (\n",
    "    return_quantity / sales_quantity < 0.10\n",
    ")\n",
    "```\n",
    "\n",
    "注意 pandas 布尔筛选使用 `&`、`|`、`~`，并要求每个条件加括号；不能直接照搬普通 Python 的\n",
    "`and`、`or`。这一点会在 pandas 专题中详细学习。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ef154736",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "数量达标： True\n",
      "价格达标： True\n",
      "最终筛选结果： True\n"
     ]
    }
   ],
   "source": [
    "quantity = 125\n",
    "price = 199.0\n",
    "has_stock = True\n",
    "\n",
    "condition_a = quantity >= 100\n",
    "condition_b = price < 200\n",
    "is_target = condition_a and condition_b and has_stock\n",
    "\n",
    "print(\"数量达标：\", condition_a)\n",
    "print(\"价格达标：\", condition_b)\n",
    "print(\"最终筛选结果：\", is_target)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f450214d",
   "metadata": {},
   "source": [
    "## 十五、真值与 `bool()` 的易错点\n",
    "\n",
    "在需要逻辑判断的位置，以下值通常视为 `False`：\n",
    "\n",
    "- 数值零：`0`、`0.0`\n",
    "- 空字符串：`\"\"`\n",
    "- 空列表、空字典：`[]`、`{}`\n",
    "- `None`\n",
    "- 布尔值 `False`\n",
    "\n",
    "其他大多数非空值视为 `True`。尤其注意：\n",
    "\n",
    "```python\n",
    "bool(\"False\")   # True，因为它是非空字符串\n",
    "bool(\"0\")       # True，因为它是非空字符串\n",
    "bool(0)         # False\n",
    "```\n",
    "\n",
    "因此网页或 CSV 中的 `\"False\"` 不能直接通过 `bool(text)` 转成正确布尔值，\n",
    "应先清洗文本并明确映射。\n",
    "\n",
    "`and`、`or` 作用于原始值时可能返回某个原始操作数，而不一定返回严格的 `True/False`。\n",
    "初学和竞赛筛选代码应优先让两侧都是清晰的比较表达式。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "da978a0a",
   "metadata": {},
   "source": [
    "## 十六、`None` 表示“没有值”\n",
    "\n",
    "```python\n",
    "coupon_code = None\n",
    "```\n",
    "\n",
    "`None` 不等于：\n",
    "\n",
    "- 数字 `0`\n",
    "- 空字符串 `\"\"`\n",
    "- 布尔值 `False`\n",
    "- 字符串 `\"None\"`\n",
    "\n",
    "推荐判断方法：\n",
    "\n",
    "```python\n",
    "if coupon_code is None:\n",
    "    print(\"没有优惠码\")\n",
    "```\n",
    "\n",
    "`None` 常见于函数没有返回有效结果、字典字段不存在或接口返回空值。\n",
    "pandas 中还会遇到 `NaN`、`NaT`、`pd.NA`；它们与 `None` 有联系但并不完全相同，\n",
    "后续应使用 `isna()`/`notna()` 统一检查缺失值。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c55ac09e",
   "metadata": {},
   "source": [
    "## 十七、Python 类型与 pandas 列类型\n",
    "\n",
    "Python 单个值常见类型：\n",
    "\n",
    "```text\n",
    "str / int / float / bool / NoneType\n",
    "```\n",
    "\n",
    "pandas 一整列常见类型：\n",
    "\n",
    "```text\n",
    "object 或 string / int64 / float64 / bool / datetime64\n",
    "```\n",
    "\n",
    "读取 CSV 后要先检查：\n",
    "\n",
    "```python\n",
    "print(df.dtypes)\n",
    "df.info()\n",
    "```\n",
    "\n",
    "需要注意：\n",
    "\n",
    "- 某列混有数字和文字时，可能被推断为 `object`；\n",
    "- 整数列出现普通缺失值后，可能变成 `float64`；\n",
    "- `\"1,299\"`、`\"￥199\"`、`\"25%\"` 都不是可直接计算的纯数值；\n",
    "- `\"2026-07-22\"` 默认可能仍是字符串，而不是日期；\n",
    "- 布尔筛选前必须确认条件结果和索引对齐。\n",
    "\n",
    "真题中不能只看表格显示内容，要同时检查列类型和缺失情况。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bb9a214f",
   "metadata": {},
   "source": [
    "## 十八、常见报错与原因\n",
    "\n",
    "| 错误或现象 | 原因 | 修复方向 |\n",
    "|---|---|---|\n",
    "| `NameError` | 文本漏引号、名称拼错、变量尚未赋值 | 检查报错名称和执行顺序 |\n",
    "| `SyntaxError` | 非法变量名、比较中误写 `=`、中文符号 | 检查当前行及上一行 |\n",
    "| `TypeError` | 不兼容类型参与运算 | 使用 `type()` 检查两侧 |\n",
    "| `ZeroDivisionError` | 比率计算时分母为零 | 除法前检查分母或使用短路条件 |\n",
    "| `\"12\" + \"3\"` 得到 `\"123\"` | 两侧都是字符串 | 转为数值后再计算 |\n",
    "| `0.1 + 0.2 != 0.3` | 二进制浮点近似 | 使用 `isclose`、舍入或 Decimal |\n",
    "| `bool(\"False\")` 得到 `True` | 非空字符串真值为真 | 显式映射文本 |\n",
    "| `type(...)` 突然不能调用 | 覆盖了内置名称 `type` | 重命名并重启内核 |\n",
    "| 边界样本少一行 | `>` 与 `>=` 口径错误 | 用边界前、边界、边界后测试 |\n",
    "\n",
    "报错时先打印值和类型：\n",
    "\n",
    "```python\n",
    "print(\"quantity =\", repr(quantity))\n",
    "print(\"type =\", type(quantity))\n",
    "```\n",
    "\n",
    "`repr()` 会把字符串引号、换行符等细节显示出来，比普通 `print()` 更适合排查脏数据。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c3bbd737",
   "metadata": {},
   "source": [
    "## 十九、真题中的类型检查清单\n",
    "\n",
    "每个关键字段至少确认：\n",
    "\n",
    "| 问题 | 示例 |\n",
    "|---|---|\n",
    "| 当前值是什么 | `repr(value)` |\n",
    "| Python 类型是什么 | `type(value)` |\n",
    "| 是否缺失 | `value is None` 或 pandas `isna()` |\n",
    "| 数字是否仍是文本 | `\"125\"`、`\"1,299\"`、`\"25%\"` |\n",
    "| 边界是否包含等号 | `> 100` 还是 `>= 100` |\n",
    "| 多条件如何组合 | `and/or` 或 pandas `&/|` |\n",
    "| 浮点结果如何比较 | `isclose()` 或业务舍入规则 |\n",
    "| 是否覆盖内置名称 | `str`、`list`、`sum`、`type` |\n",
    "\n",
    "## 针对性练习\n",
    "\n",
    "使用 `学生练习.py` 完成变量命名、五类值、类型检查、数值与数字文本、浮点精度、\n",
    "边界值、逻辑组合、`None` 和错误诊断练习。每个实验先预测，再运行并解释结果。"
   ]
  }
 ],
 "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"
  },
  "title": "第 3 天｜变量、数据类型、比较与逻辑"
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
