第3章 基础语法:注释与变量
本章介绍编写 Python 代码时的基础规则,包括注释与文档字符串的写法与作用,变量的创建、重新赋值、多变量赋值与解包,以及标识符的命名规则与常量约定;最后梳理 PEP 8 代码规范中缩进、空格、行长与空行等常见要求。这些书写与命名习惯会贯穿后续所有章节。
3.1 代码注释与文档字符串
3.1.1 注释的作用
注释是写给代码阅读者的说明,Python 解释器不会执行注释中的内容。合理使用注释可以:
- 说明代码的目的、业务规则或实现原因;
- 记录参数、边界条件和注意事项;
- 暂时屏蔽一小段代码,辅助调试;
- 帮助自己和其他开发者快速理解程序。
注释应重点解释"为什么这样做",而不是机械复述代码已经清楚表达的内容。
3.1.2 单行注释的两种写法
Python 使用 # 表示注释。从 # 开始到当前物理行末尾的内容都不会执行,常见写法分为以下两种。
方式一:使用独占一行的单行注释
注释单独占一行,通常放在相关代码的上方,用于说明接下来一段代码的目的、原因或注意事项;独占一行的注释应与所说明的代码保持相同缩进,并在 # 后留一个空格:
# 计算圆的面积
radius = 3
area = 3.14159 * radius**2
print(area)
方式二:使用行尾注释
行尾注释放在代码右侧,适合补充简短且与当前语句直接相关的信息;按照 PEP 8 的常见写法,代码与行尾注释之间至少留两个空格,# 后留一个空格。行尾注释应尽量简短,说明较长时应改用独占一行的注释:
MAX_RETRY_COUNT = 3 # 外部服务偶尔超时,最多重试 3 次
print("程序结束", end="") # 输出结束后不换行
无论采用哪种方式,都不要为每条简单语句添加无意义的注释。注释应提供代码本身没有直接表达的信息:
# 推荐:说明代码背后的业务原因
retry_count = 3 # 外部服务偶尔超时,最多重试 3 次
# 不推荐:只是重复代码含义
nickname = "阿明" # 把阿明赋值给 nickname
3.1.3 多行说明与文档字符串
Python 没有专门的"多行注释"语法。需要编写多行说明时,可以根据用途选择以下两种方式。
方式一:使用连续的单行注释
普通的多行代码说明应让每一行分别以 # 开头;这种方式创建的才是真正的注释,适合解释业务规则、实现原因和注意事项。编辑器通常提供批量添加或取消行注释的快捷操作:
# 用户名必须由字母、数字或下划线组成,
# 长度应在 3~20 个字符之间,
# 并且不能与已有用户名重复。
username = "python_user"
方式二:使用三引号字符串或文档字符串
三引号用于创建多行字符串;位于模块、类或函数开头时,这个字符串称为文档字符串(docstring),用于说明代码用途。三引号不是真正的多行注释,不建议用它屏蔽代码:
# 普通多行字符串
text_block = """第一行
第二行
第三行"""
print(text_block)
# 函数文档字符串
def join_tags(tag_list):
"""把标签列表拼接成顿号分隔的文本。"""
return "、".join(tag_list)
print(join_tags(["Python", "入门", "笔记"]))
print(join_tags.__doc__)
3.2 变量、赋值与命名规则
3.2.1 变量与对象的关系
在 Python 中,变量是绑定到对象的名称。可以把变量理解为对象的"标签",而不是只能存放某一种数据的固定盒子。
赋值过程
以 name = "Python" 为例,Python 先计算赋值符号右侧的表达式,得到字符串对象 "Python",再将变量名 name 绑定到该对象:
name = "Python"
name ─────> "Python"
变量名 字符串对象
此后,程序便可以通过变量名访问对应对象。
动态类型
变量本身不需要声明类型,类型属于变量当前引用的对象。同一个变量可以在程序运行过程中重新绑定到不同类型的对象:
item_count = 10
print(f"item_count 的类型:{type(item_count)}") # <class 'int'>
item_count = "十"
print(f"item_count 的类型:{type(item_count)}") # <class 'str'>
这种特性称为动态类型。不过在实际项目中,频繁改变同一变量表示的数据类型会降低代码可读性,应尽量让变量的含义保持稳定。
3.2.2 变量的创建、使用与重新赋值
变量的创建、使用和修改遵循以下规则:
- 变量必须先赋值,才能在表达式中使用;
- 赋值符号
=表示将右侧表达式的结果绑定到左侧变量名,并不表示数学中的相等关系; - 变量可以重新赋值,重新赋值后,变量名将引用新的对象;
- 读取尚未定义的变量会触发
NameError。
下面的代码依次演示变量的创建、使用和修改:
# 创建变量
unit_price = 12.5
quantity = 4
# 使用变量计算并输出结果
total_price = unit_price * quantity
print(total_price) # 50.0
# 修改变量并重新计算
unit_price = 15.0
total_price = unit_price * quantity
print(total_price) # 60.0
# print(undefined_name) # NameError: name 'undefined_name' is not defined
3.2.3 多变量赋值与解包
Python 支持在一条语句中为多个变量赋值,常见用法如下:
- 使用链式赋值,可以让多个变量绑定到同一个对象;
- 使用解包赋值,可以将多个值依次绑定到对应的变量;
- 解包时左右两侧的元素数量通常必须一致,否则会触发
ValueError; - 解包可以直接交换变量,不需要额外的临时变量;
- 不需要使用某个值时,通常用
_接收;_仍是普通变量名,只是在编码习惯上表示忽略该值。
下面的代码依次演示这些用法:
# 多个变量绑定到同一个对象
x = y = z = 0
print(x, y, z) # 0 0 0
# 解包赋值
name, age, city = "林晓", 21, "杭州"
print(name, age, city) # 林晓 21 杭州
# 交换变量
left = 10
right = 20
left, right = right, left
print(left, right) # 20 10
# 忽略不需要的值
name, _, city = ("李华", 20, "上海")
print(name, city) # 李华 上海
# 左右两侧数量不一致会触发 ValueError
# first, second = (1, 2, 3)
3.2.4 标识符的语法规则
变量名、函数名、类名和模块名等由开发者命名的名称统称为标识符。Python 标识符需要遵守以下规则:
- 可以包含 Unicode 字母、数字和下划线;
- 不能以数字开头;
- 大小写敏感:
name、Name和NAME会被当作三个互不相同的名称; - 不能与 Python 关键字相同;
- 可以先使用
isidentifier()检查名称形式,再使用keyword.iskeyword()排除关键字; - 软关键字只在特定语法位置具有特殊含义,可以通过
keyword.softkwlist查看。
下面的代码依次演示合法与非法标识符、名称检查以及关键字查询:
import keyword
# 合法标识符
user_name = "Alice" # 合法
用户名称 = "张三" # 合法,但跨团队项目通常优先使用英文名称
name2 = "Bob" # 合法
# 非法标识符,取消注释后会触发 SyntaxError
# 2name = "Bob" # 非法:不能以数字开头
# class = "一班" # 非法:class 是关键字
# 检查候选名称
names = ["user_name", "2name", "class", "用户名称"]
for name in names:
valid = name.isidentifier() and not keyword.iskeyword(name)
print(f"{name!r}: {valid}")
# 查看当前版本的关键字和软关键字
print(keyword.kwlist)
print(keyword.softkwlist)
3.2.5 标识符的命名规范
名称除了满足语法规则,还应准确表达用途。PEP 8 中常见的命名约定如下:
| 对象 | 推荐风格 | 示例 |
|---|---|---|
| 变量、函数、方法 | 小写蛇形命名法 | total_price、get_user() |
| 类 | 大驼峰命名法 | UserAccount |
| 常量 | 全大写蛇形命名法 | MAX_RETRY_COUNT |
| 内部使用的名称 | 单下划线开头 | _cache |
| 特殊方法 | 两侧双下划线,由 Python 预定义 | __init__() |
命名时还应注意:
-
选择有含义的名称,避免大量使用
a、b、data1; -
不要覆盖
list、str、sum等内置名称; -
单字母
l、大写O和大写I容易与数字混淆,通常不单独使用; -
布尔变量可以使用
is_、has_、can_等前缀表达判断含义。is_logged_in = True
has_permission = False
max_retry_count = 3
3.2.6 常量的命名约定
常量是程序运行期间不希望被修改的值。Python 中的常量主要遵循以下约定:
- Python 不提供让自定义变量无法重新赋值的语言机制;
- 通常使用全大写蛇形命名法表示常量,提醒开发者不要修改;
Final类型注解可以向类型检查器表达常量意图,但运行时仍然允许重新赋值;True、False和None是 Python 语言定义的常量,不能作为赋值目标。
下面的代码演示普通常量和带有 Final 类型注解的常量:
from typing import Final
# 使用命名约定表示常量
PI = 3.1415926
MAX_CONNECTIONS = 100
DEFAULT_ENCODING = "utf-8"
# 使用 Final 进一步表达常量意图
SECONDS_PER_MINUTE: Final = 60
# 运行时可以重新赋值,但类型检查器会报告问题
# SECONDS_PER_MINUTE = 30
# Python 语言定义的常量不能作为赋值目标
# True = 1 # SyntaxError
3.3 Python 代码规范
代码规范用于统一代码的书写方式,使程序更容易阅读、修改和协作维护。PEP 8 是 Python 官方代码风格指南;实际开发中应优先保持项目内部一致,项目规范与 PEP 8 不同时,以项目规范为准。注释和命名规范已分别在 3.1 节和 3.2 节介绍,本节不再重复。
3.3.1 缩进与代码块
Python 使用缩进划分代码块,缩进不仅影响代码格式,还会直接影响程序结构。主要规则如下:
| 规则 | 说明 |
|---|---|
| 每级缩进使用 4 个空格 | 适用于函数、条件语句、循环语句等代码块 |
| 优先使用空格缩进 | 可以将编辑器的 Tab 键设置为插入 4 个空格 |
| 不要混用制表符和空格 | 混用可能触发 TabError 或 IndentationError |
| 同一代码块保持相同缩进 | 缩进层级不同表示代码所属的结构不同 |
下面的代码演示如何使用统一缩进表示嵌套的代码块:
"""演示使用统一缩进表示代码块。"""
temperature = 30
is_outdoor = True
if temperature >= 30:
print("天气炎热")
if is_outdoor:
print("外出时注意防晒")
print("天气检查完成")
3.3.2 空格与换行
适当的空格和换行可以突出表达式结构,但多余空格会降低可读性。常见规则如下:
| 使用位置 | 推荐写法 | 说明 |
|---|---|---|
| 二元运算符两侧 | total = price * quantity |
通常在运算符两侧各留一个空格 |
| 逗号之后 | [1, 2, 3] |
逗号前不留空格,逗号后留一个空格 |
| 括号内部 | sum(numbers) |
紧邻括号的内容两侧不添加空格 |
| 函数调用之前 | print(total) |
函数名与左括号之间不添加空格 |
| 关键字参数的等号两侧 | round(number, ndigits=2) |
未使用类型注解时,等号两侧不添加空格 |
| 较长的表达式 | 使用 ()、[] 或 {} 换行 |
优先使用隐式续行,避免使用反斜杠续行 |
下面的代码演示常用的空格规则,以及在括号内拆分较长的表达式:
"""演示空格和换行的规范写法。"""
unit_price = 20
quantity = 3
shipping_fee = 10
discount_amount = 5
numbers = [1, 2, 3, 4]
total_price = (
unit_price * quantity
+ shipping_fee
- discount_amount
)
print(f"数字总和:{sum(numbers)}")
print(f"应付金额:{round(total_price, ndigits=2)}")
3.3.3 行长与空行
合理控制行长可以减少横向滚动,适当使用空行可以划分代码的逻辑层次。PEP 8 的建议如下:
| 项目 | 建议 |
|---|---|
| 代码行 | 每行最多 79 个字符 |
| 注释和文档字符串 | 连续文本每行最多 72 个字符 |
| 顶层函数和类 | 定义之间空两行 |
| 类中的方法 | 定义之间空一行 |
| 函数内部 | 可以使用少量空行划分不同的处理阶段 |
| 项目约定 | 团队可以统一采用其他行长,但应在整个项目中保持一致 |
下面的代码使用两个空行分隔顶层函数,并使用一个空行划分函数内部的处理阶段:
"""演示使用空行划分代码结构。"""
def calculate_total(unit_price, quantity, discount_rate):
subtotal = unit_price * quantity
discount_amount = subtotal * discount_rate
total = subtotal - discount_amount
return total
def display_total(total):
print(f"商品总价:{total:.2f} 元")
order_total = calculate_total(19.9, 3, 0.1)
display_total(order_total)
3.3.4 分号与一行多条语句
在 Python 中,也允许把若干条简单语句写在同一行并用分号分隔,但这种写法不利于阅读和调试。常见写法的建议如下:
| 写法 | 示例 | 建议 |
|---|---|---|
| 一行一条语句 | x = 1 |
推荐,代码结构清晰 |
| 分号分隔多条语句 | x = 1; y = 2 |
可以运行,但通常不推荐 |
| 复合语句写在一行 | if ready: start() |
通常应拆分为缩进代码块 |
下面的代码将赋值、计算和输出分别写在不同的行中:
"""演示一行只书写一条主要语句。"""
x = 1
y = 2
total = x + y
print(f"计算结果:{total}")