小白学 Python
AI 编程指南GitHub
© 2026 小白学 Python · 基于 walter201230/Python 教程
课程目录关于本站联系方式隐私政策GitHub

代码可读性

完整讲解 · 5 段教学·配 4 道练习题·预计 40 分钟

本页是本章的通读版,可直接读完全部讲解。想动手写代码、跑判分,去 闯关模式。

教学 01 / 05

第十七节:代码可读性

学到这里,你已经能写出能跑的 Python 代码了。但「能跑」和「好读」是两回事。

看这段代码:

python到闯关页运行这段 →
def calc(x, y, op):
    if op == 'add':
        return x + y
    elif op == 'sub':
        return x - y

读到这个函数,你的第一反应是什么?

  • x 和 y 是数字还是字符串?
  • op 还能传啥?
  • 返回值是啥类型?返回 None 怎么办?

只能去翻调用方的代码——或者直接去问写代码的人。

「能跑」 ≠ 「好代码」

代码不是只写给电脑看的——更多时候是写给:

  • 半年后的自己(你会忘)
  • 接手项目的同事(他不知道你当时怎么想)
  • Code Review 的 reviewer(他要在 5 分钟内看懂你的意图)

所以「好读」是一项必须练的能力。

这一节要学什么

主题解决什么问题
好命名一眼看懂这个变量/函数是干嘛的
早返回把 6 层嵌套的 if 摊平
推导式把 4 行 for 循环压成 1 行
类型注解让函数签名自带文档

学完这一节,你写出来的 Python 代码会专业一大截。

教学 02 / 05

一、好命名

写代码 80% 的时间在「读」,只有 20% 在「写」。所以命名好不好,直接决定代码读起来累不累。

1、变量用名词,函数用动词

变量装的是「东西」——用名词:

python到闯关页运行这段 →
user_name = '张三'
total_price = 100
order_list = []

函数做的是「动作」——用动词或动词短语:

python到闯关页运行这段 →
def get_user(uid): ...
def calculate_total(items): ...
def send_email(to, body): ...

反例(让读者皱眉):

python到闯关页运行这段 →
def user(uid): ...        # 这是函数还是属性?
def data(items): ...       # 处理 data?还是返回 data?

2、布尔值用 is_ / has_ / can_ 开头

python到闯关页运行这段 →
is_active = True       # 一眼看出是布尔
has_permission = False
can_edit = True

反例:

python到闯关页运行这段 →
active = True          # active 是状态值还是布尔?要去看赋值才知道
permission = False     # 这是权限对象还是 True/False?

3、避免无意义的缩写

python到闯关页运行这段 →
# 不好
def calc(u, p):
    return u * p

# 好
def calculate_total(unit_price, quantity):
    return unit_price * quantity

注意:通用缩写(比如 i 当循环变量、url、id、db)大家都懂,可以用。但 usr、prc、amt 这种「省两个字母」的缩写就别写了,省的那点字符根本不值得读者去猜。

4、长度跟作用域成正比

python到闯关页运行这段 →
for i in range(10):       # i 作用域很小,用一个字母没问题
    print(i)

# 但模块级的全局变量就要起得清楚
USER_ROLE_ADMIN = 'admin'
DEFAULT_TIMEOUT_SECONDS = 30

一句话总结

看到这个名字,读者还要不要去翻定义才能懂?要——名字没起好。

教学 03 / 05

二、早返回(Early Return)

来看下面这段「校验登录」的代码:

python到闯关页运行这段 →
def login(user, password):
    if user is not None:
        if user.is_active:
            if user.check_password(password):
                if not user.is_locked:
                    return '登录成功'
                else:
                    return '账户已锁定'
            else:
                return '密码错误'
        else:
            return '账户未激活'
    else:
        return '用户不存在'

四层嵌套——读到第三层 if 时,你已经记不清第一层的条件是什么了。

早返回:把异常情况先送走

「先处理边界情况,主流程才能放在最外层」——这就是早返回的核心思想。

python到闯关页运行这段 →
def login(user, password):
    if user is None:
        return '用户不存在'
    if not user.is_active:
        return '账户未激活'
    if not user.check_password(password):
        return '密码错误'
    if user.is_locked:
        return '账户已锁定'
    return '登录成功'

变化看出来了吗?

  • 没有 else
  • 没有嵌套
  • 每个失败条件只占一行
  • 最后一行是「成功路径」——一眼就能找到

通用模式

凡是看到这种结构:

python到闯关页运行这段 →
if 条件成立:
    # 主流程一大段
    ...
else:
    return 错误

都可以改写成:

python到闯关页运行这段 →
if not 条件成立:
    return 错误
# 主流程一大段(无缩进)
...

主流程从 1 层缩进退回到 0 层。多个条件叠加时效果尤为明显。

什么时候不用早返回

不是所有 if 都该早返回。如果两个分支地位平等——比如「奇数返回 X、偶数返回 Y」——那就老老实实写 if/else,没必要硬塞进早返回。

python到闯关页运行这段 →
def parity(n):
    if n % 2 == 0:
        return '偶数'
    else:
        return '奇数'

这样反而清楚。早返回是为了摊平错误处理,不是为了消灭所有 else。

练习 1 / 4用早返回重写嵌套 if去闯关页做这题 →
教学 04 / 05

三、推导式(Comprehension)

Python 写「从一组数据生成另一组数据」这件事,有专门的优雅写法——推导式。

1、列表推导式

写一个「把 nums 里所有正数挑出来」的需求。老写法:

python到闯关页运行这段 →
nums = [-2, 1, -3, 4, 0, -5, 6]
positives = []
for x in nums:
    if x > 0:
        positives.append(x)
print(positives)

输出:

[1, 4, 6]

四行——其实就是说一句话:「把 nums 里 x > 0 的 x 收集成一个列表」。

列表推导式直接把这句话翻译成代码:

python到闯关页运行这段 →
nums = [-2, 1, -3, 4, 0, -5, 6]
positives = [x for x in nums if x > 0]
print(positives)

输出一样:

[1, 4, 6]

读法:「把 x 收集起来,对每个 x 来自 nums,且 x > 0」。

2、推导式的通用结构

[表达式 for 变量 in 可迭代对象 if 条件]
  • 表达式:每个元素被收集前要做什么变换(不变换就直接写变量名)
  • for ... in:遍历哪个序列
  • if:可选过滤条件,不需要就省掉

举几个例子:

python到闯关页运行这段 →
# 把每个数字平方
[x * x for x in [1, 2, 3, 4]]   # [1, 4, 9, 16]

# 全部转大写
[s.upper() for s in ['ab', 'cd']]  # ['AB', 'CD']

# 偶数的平方
[x * x for x in range(10) if x % 2 == 0]  # [0, 4, 16, 36, 64]

3、字典推导式

把一个字典的所有值翻倍,老写法:

python到闯关页运行这段 →
prices = {'apple': 5, 'banana': 3, 'cherry': 10}
doubled = {}
for k, v in prices.items():
    doubled[k] = v * 2
print(doubled)

字典推导式:

python到闯关页运行这段 →
prices = {'apple': 5, 'banana': 3, 'cherry': 10}
doubled = {k: v * 2 for k, v in prices.items()}
print(doubled)

结构:{键: 值 for 变量 in 可迭代对象}。

4、什么时候不要用推导式

推导式很爽,但不是越短越好。如果一行推导式塞了:

  • 多重 for 循环
  • 复杂的条件判断
  • 复杂的表达式

那就停下来——回到老老实实的 for 循环。一行写不下、要拐三个弯的推导式,比四行 for 循环难读多了。

记住这个标准:一眼能读懂——用推导式;要停下来翻译——用 for 循环。

练习 2 / 4列表推导式:挑出正数并平方去闯关页做这题 →练习 3 / 4字典推导式:把所有价格翻倍去闯关页做这题 →
教学 05 / 05

四、类型注解(Type Hints)

回到最开始那段「让人懵」的代码:

python到闯关页运行这段 →
def calc(x, y, op):
    ...

加上类型注解之后:

python到闯关页运行这段 →
def calc(x: int, y: int, op: str) -> int:
    ...

光看签名你就懂了:「两个 int、一个 str,返回 int」。

1、基本语法

记住这个口诀:「参数加冒号,返回加箭头」。

python到闯关页运行这段 →
def add(a: int, b: int) -> int:
    return a + b


def greet(name: str) -> str:
    return f'你好,{name}'


def log(message: str) -> None:    # 没有返回值就写 None
    print(message)

调用时:

python到闯关页运行这段 →
print(add(3, 5))
print(greet('张三'))
log('打卡成功')

输出:

8
你好,张三
打卡成功

2、Python 不强制检查类型

注意一个重要的事实:Python 解释器不会根据注解去校验类型。

python到闯关页运行这段 →
def add(a: int, b: int) -> int:
    return a + b

print(add('hello', 'world'))   # 居然能跑!输出 'helloworld'

注解只是「写给人看的契约」+「写给工具看的提示」。要真的校验类型,需要用 mypy、pyright 这类静态检查工具。

那加注解还有意义吗?有:

  • IDE 能给你精准的代码补全
  • 同事读代码时省下大把猜测
  • 静态检查器能在代码运行前揪出类型不匹配

3、常用基础类型

类型含义
int整数
float浮点数
str字符串
bool布尔值
list列表
dict字典
tuple元组
None空值(用作返回类型)

4、容器装的什么也能写出来

光写 list 不够——「列表里装的啥」还是不知道。Python 3.9+ 可以这么写:

python到闯关页运行这段 →
def total(nums: list[int]) -> int:
    return sum(nums)


def name_to_age(data: dict[str, int]) -> int:
    return len(data)
  • list[int] —— 装 int 的列表
  • dict[str, int] —— 键是 str、值是 int 的字典

5、可能返回 None 怎么办?

用 X | None(Python 3.10+):

python到闯关页运行这段 →
def find_user(uid: int) -> str | None:
    db = {1: '张三', 2: '李四'}
    return db.get(uid)    # 找不到时 .get() 返回 None

读起来就是「返回 str 或者 None」,调用方一看就知道要判空。

6、什么场景该写注解

优先级从高到低:

  1. 公共函数 / 类的方法——必加,这是接口契约
  2. 复杂的业务函数——必加,帮后期维护
  3. 简单的一次性脚本——随意

for i in range(10) 这种 i 显然是 int 的,硬塞 i: int 反而显得啰嗦。注解的价值是「消除歧义」,没歧义的地方加了反而碍眼。

练习 4 / 4写一个带类型注解的函数去闯关页做这题 →

读完了?动手练一遍才算真会。

去闯关模式练习 →