第一章 计算环境与语言基础:从可运行到可理解
本章的目标不是“背会语法”,而是建立两套可持续复用的认知支架:其一是让代码稳定跑起来的可运行基座(环境、命令、文件与编码);其二是让你能解释“它为什么这样跑”的语义基座(对象、绑定、类型与运算规则)。当这两套基座搭好之后,后续学习函数、模块、面向对象与库生态时,你将始终拥有可验证、可推导的起点。
学习目标
- 理解编程语言、解释器与源代码的分工,能用自己的话解释 CPython 的基本执行路径。
- 独立完成 Python 安装与版本确认,掌握命令行、REPL 与脚本运行的核心命令。
- 认识 Python 的最小语法要素:标识符、缩进代码块、注释与文档字符串。
- 建立“变量绑定”与“动态类型”的正确直觉模型,避免把变量误解为“存储盒子”。
- 熟练使用 `int`、`float`、`bool`、`str`、`None` 与常见运算符,严格区分 `==` 与 `is`。
- 能编写一个“输入—计算—输出”的小程序,并用 f-string 或 `format()` 输出结构化结果。
先修知识
- 会使用键盘输入英文与常见符号,能在操作系统中创建与保存文本文件。
- 了解“文件/文件夹”的概念;不要求提前理解编译原理或数据结构。
本章结构
1. 编程语言、解释器与源代码的关系(#env) 2. 环境搭建与运行方式:命令行、REPL、脚本与编码(#env) 3. 语法最小单元:标识符、缩进与注释(#syntax) 4. 基础数据类型与运算:`==` vs `is`(#types) 5. 输入输出与字符串格式化:形成完整闭环(#io) 6. 练习:温度换算、BMI、成绩单(#practice)
> 【术语索引】解释器(Interpreter):执行源代码或其中间形式的程序。 > 【术语索引】字节码(Bytecode):介于源代码与机器码之间的中间指令表示。
---
编程语言、解释器与源代码 #env
源代码并不会“自己运行”
Python 程序首先以源代码(通常是 `.py` 文件)存在。源代码是给人读的文本;计算机硬件并不能直接理解它。使源代码产生行为(例如打印文本、读写文件)的关键角色,是解释器。在主流实现中,你日常安装并运行的“Python”,通常指的是 CPython 解释器:用 C 语言实现的 Python 官方参考实现。
从工作分工上看,可以把 Python 的执行理解为三层: 1. 你编写:源代码(可读、可编辑) 2. 解释器处理:分析、转换与执行 3. 操作系统/硬件完成:真正的输入输出与资源管理(文件、网络、内存等)
CPython 的基本执行流程:源代码→字节码→虚拟机
CPython 并不是逐字符“硬解释”源代码;它会先把源代码转换成一种更便于执行的中间形式——字节码,再由 Python 虚拟机逐条执行字节码指令。
```mermaid graph TD A[源代码 .py] --> B[词法/语法分析] B --> C[字节码 .pyc] C --> D[Python虚拟机执行] D --> E[输出/副作用] ```
- 词法/语法分析阶段负责确认代码是否符合语言规则(例如缩进是否正确、括号是否匹配)。
- 字节码通常会缓存为 `.pyc` 文件,位于 `__pycache__` 目录中,以加速下次启动(不是每次都从零开始)。
<!-- example:id=1-1 topic=bytecode --> ```python import dis
def add(a, b): return a + b
dis.dis(add) ```
例 1-1 展示了用标准库 `dis` 把函数的字节码“反汇编”为可读形式。初学阶段你不必记住每条指令,但要形成关键认识:同一段源代码能跨平台运行,本质上依赖“同一种语言规范 + 对应平台上的解释器实现”。你不是把 `.py` 直接交给 CPU,而是交给“Python 解释器 + 虚拟机”。
> 【术语索引】虚拟机(Virtual Machine):以软件方式模拟一套指令执行环境,此处指 CPython 的字节码执行器。
---
环境搭建与运行方式 #env
安装与版本确认:先把“可运行”钉牢
Python 的主版本以 `3.x` 为主流。学习阶段建议选择较新的稳定版(例如 3.11、3.12),因为语法与性能更一致,资料也更集中。安装完成后,你至少要能在命令行确认版本:
- macOS / Linux 常见:`python3 --version`
- Windows 常见:`py --version` 或 `python --version`
(视频链接占位符:Windows 安装 Python 与勾选 PATH) (视频链接占位符:macOS 使用 Homebrew 安装 Python) (视频链接占位符:Linux 发行版安装与 `python3` 命令说明)
若你需要在同一台机器上管理多个版本,可以了解:
- `pyenv`(偏向 macOS/Linux):按项目切换版本
- `conda`(偏向数据科学环境):按环境隔离依赖与版本
学习本章时的最低要求是:确定你正在使用的解释器版本,并能稳定调用它。
命令行与 REPL:把“即时反馈”用起来
REPL 是 “Read–Eval–Print Loop” 的缩写,即“读入—求值—输出—循环”。它提供即时反馈,适合验证语法与表达式含义。
<!-- example:id=1-2 topic=repl --> ```python >>> 1 + 2 * 3 7 >>> "Py" + "thon" 'Python' >>> type(3.14) <class 'float'> ```
例 1-2 中,`type()` 让你直接观察表达式结果的类型。REPL 的价值在于:当你不确定某个运算规则、某个函数行为时,先用最小例子在 REPL 里验证,再写进脚本。
> 可展开释义[^repl]
脚本执行方式:把“可复现”用起来
当代码变得更长、更需要复用时,应把它写入 `.py` 文件形成脚本。例如 `main.py`,通过命令行运行:
- `python main.py`(或 `python3 main.py`)
- 作为模块运行:`python -m package.module`(更适合项目结构化后使用)
脚本相对 REPL 的优势是:可复现、可版本管理、可分享。从学习路径上看,建议你在 REPL 做快速实验,在脚本里沉淀稳定结论。
编码与文本文件:让“能运行”不被字符问题打断
Python 源文件本质是文本文件。现代工程默认使用 UTF-8 编码,这是跨平台协作最稳妥的选择之一。若你在运行时遇到类似错误:
- `SyntaxError: Non-UTF-8 code starting with ...`
- `UnicodeDecodeError: 'gbk' codec can't decode byte ...`
通常意味着:解释器读取源文件或输入文本时,使用的编码与文件真实编码不一致。
> 常见错误提示侧栏:编码错误排查步骤 > 1)确认编辑器文件编码为 UTF-8(优先无 BOM)。 > 2)确认终端编码设置(Windows 终端可能默认非 UTF-8)。 > 3)如需显式声明源文件编码,可在文件头部添加:`# -*- coding: utf-8 -*-`(PEP 263)。 > 4)读写文件时使用 `open(path, encoding="utf-8")` 明确编码。
---
语法最小单元:标识符、缩进与注释 #syntax
标识符与关键字:名字的规则与边界
标识符用于命名变量、函数、类等。基本规则包括:由字母、数字、下划线组成;不能以数字开头;大小写敏感。Python 还保留了一组关键字(如 `if`、`for`、`class`、`True`、`None`),它们具有固定语义,不可用作普通标识符。
良好的命名并非“形式主义”,而是可理解性的第一层结构:对初学者而言,一个清晰的名字往往比一段注释更可靠。
缩进与代码块:Python 用空间表达结构
Python 使用缩进表示代码块,而不是花括号。缩进不仅影响可读性,还直接决定语义。常见约定是每级缩进使用 4 个空格,不混用 Tab 与空格。
<!-- example:id=1-3 topic=indentation --> ```python score = 82
if score >= 60: result = "pass" else: result = "fail"
print(result) ```
例 1-3 中,`if` 与 `else` 的从属关系完全由缩进表达。若缩进错误,解释器会报 `IndentationError` 或 `SyntaxError`。这类错误不是“细节问题”,而是 Python 语法结构本身。
> 常见错误提示侧栏:缩进错误排查步骤 > 1)统一使用空格缩进(建议 4 空格)。 > 2)打开编辑器“显示不可见字符”,检查是否混入 Tab。 > 3)对齐同一代码块内的所有语句;不要在块中突然改变缩进层级。
注释与文档字符串:给人读,也给工具读
- **注释**以 `#` 开始,解释器会忽略其内容,主要服务于阅读者。
- **文档字符串(docstring)**是出现在模块、类或函数体开头的字符串字面量,能够被工具提取,用于生成文档与交互式帮助(例如 `help()`)。
<!-- example:id=1-4 topic=docstring --> ```python def bmi(weight_kg, height_m): """计算 BMI = weight_kg / height_m**2,并返回浮点数。""" return weight_kg / (height_m ** 2) ```
例 1-4 中的 docstring 不是“注释的替代品”,而是可被 Python 运行时访问的结构化说明。
---
变量绑定与动态类型:从“盒子模型”到“指向关系” #types
初学者最常见的误解,是把变量看成“盒子”,认为赋值是把值放进盒子。更准确的模型是:变量名是标识符,运行时它会绑定(bind)到某个对象[^object]。这一关系可抽象写为: $$name \mapsto object$$
当你写 `x = 3`,更贴近事实的表述是:“名字 `x` 现在指向(绑定到)整数对象 `3`”。这也解释了 Python 的动态类型:类型属于对象,而不是属于名字。名字可以在不同时间绑定到不同类型的对象,但这并不意味着“随便写也没问题”;相反,你需要更依赖运行时验证与清晰的程序结构。
> 可展开释义[^binding]
---
基础数据类型与运算规则 #types
五类核心值:`int`、`float`、`bool`、`str`、`None`
- `int`:整数,支持任意精度(不易溢出,但计算成本会增加)。
- `float`:浮点数,遵循 IEEE 754 近似表示,可能出现 `0.1 + 0.2 != 0.3` 的现象。
- `bool`:布尔值,仅有 `True` 与 `False`,参与逻辑运算。
- `str`:字符串,表示文本;在 Python 中字符串是不可变对象[^immutable]。
- `None`(类型为 `NoneType`):表示“空值/缺失/尚未有结果”,常用于函数返回或占位。
运算符速览:算术、比较、逻辑、成员与身份
- 算术:`+ - * / // % **`
- 比较:`== != < <= > >=`(结果是 `bool`)
- 逻辑:`and or not`(短路求值)
- 成员:`in` / `not in`(判断元素是否属于容器)
- 身份:`is` / `is not`(判断是否为同一对象)
其中最需要刻意训练的是:`==` 与 `is` 的区别。
- `==` 比较的是“值是否相等”(由对象的相等性规则决定)。
- `is` 比较的是“是否为同一对象”(同一内存中的同一对象身份)。
<!-- example:id=1-5 topic=eq_vs_is --> ```python a = [1, 2, 3] b = [1, 2, 3] c = a
print(a == b) # True:值相等 print(a is b) # False:不是同一对象 print(a is c) # True:同一对象 ```
例 1-5 给出最稳定、最不依赖实现细节的演示:列表是可变对象,两个内容相同的列表通常是不同对象,因此 `==` 与 `is` 在此会明显分化。经验法则是:除非你明确要判断对象身份(例如判断是否为 `None`),否则优先用 `==`。例如:
- 正确:`x is None`(判断缺失值)
- 常规:`x == 0`(判断数值)
---
输入输出与字符串格式化:形成闭环 #io
从 `input()` 到类型转换:文本进入程序的第一站
`input()` 返回的是字符串。若你期望用户输入数字,需要显式转换:
<!-- example:id=1-6 topic=io --> ```python name = input("请输入姓名:") score = float(input("请输入分数:")) print("你好,", name, "你的分数是", score) ```
将输入直接用于计算而不转换,是初学者最常见的类型错误来源之一。
f-string 与 `format()`:把输出写得“可读且可检验”
f-string(格式化字符串字面量)是 Python 3.6+ 的推荐方式,语法紧凑、可读性高:
<!-- example:id=1-7 topic=formatting --> ```python weight = 70 height = 1.75 bmi_value = weight / (height ** 2)
print(f"BMI={bmi_value:.2f}") # 保留两位小数 print(f"{'结果':<6}{bmi_value:>8.2f}") # 左右对齐 ```
同样的格式化也可用 `format()` 完成,适合在字符串模板需要复用时使用。无论哪种方式,目标都是:输出不是随意拼接,而是结构化呈现,便于人读、也便于后续程序解析与测试。
---
本章小结
本章首先澄清了“代码如何被执行”的链路:源代码经过分析生成字节码,再由虚拟机执行,解释了 Python 跨平台的前提条件。随后你完成了从安装、命令行、REPL 到脚本运行的最小闭环,并理解了编码为何是“可运行基座”的一部分。最后,你建立了 Python 语义的核心模型:名字到对象的绑定关系、动态类型的边界,以及 `==` 与 `is` 的严格区分,并用输入输出与格式化把知识闭环为可运行的小程序。
---
练习 #practice
1. 温度换算器:读取摄氏温度 `C`,输出华氏温度 `F = C * 9/5 + 32`,要求输出保留 1 位小数,并附单位说明。 2. BMI 计算器:读取体重(kg)与身高(m),计算 BMI,按区间输出分类(你可自行查表或先只输出 BMI 数值)。 3. `==` 与 `is` 对比:分别用整数、字符串、列表做实验,记录 `==` 与 `is` 的结果,并用“值相等/对象同一性”解释每个结论。 4. 简易成绩单:输入姓名与三科分数,输出总分、均分,并用对齐格式生成表格样式的文本输出(建议使用 f-string 的宽度控制)。
---
[^object]: 对象(Object):运行时可被引用的一切实体,包含值与行为(方法)。在 Python 中,整数、字符串、列表、函数等都是对象。 [^binding]: 绑定(Binding):标识符与对象之间的关联关系。赋值语句会创建或更新绑定;对象本身并不会因为“换了名字”而改变。 [^immutable]: 可变性(Mutability):可变对象可在原地改变其内容(如 `list`);不可变对象一旦创建其值不可变(如 `str`、`int`)。 [^repl]: REPL:交互式执行环境,适合快速实验表达式与语句,获取即时反馈。