跳到主要内容

写得更像 Python:让代码一下子变地道的 7 个习惯

· 阅读需 4 分钟
村长
不好奇编程站长 · B站「村长不好奇」

村长

有学员问我:「村长,我代码能跑,怎么一眼看就是新手写的?」

通常不是语法问题,而是思路还带着别的语言的口音。今天聊 7 个习惯,改完不用多加一行功能,代码味道立刻不一样。

1. EAFP:先做,出错再说​

Python 圈有个说法叫 EAFP(Easier to Ask Forgiveness than Permission),相对的是 LBYL(Look Before You Leap)。

data = {"name": "村长"}

# LBYL:先检查再动手
if "age" in data:
age = data["age"]
else:
age = 0

# EAFP:村长写法
try:
age = data["age"]
except KeyError:
age = 0

# 更地道的写法
age = data.get("age", 0)

Python 的异常处理很便宜,先试再兜底通常比层层判断更清爽,也避开「检查完状态又变了」的竞争问题。

2. with:打开的东西让它自己关​

# 容易漏
f = open("data.txt", encoding="utf-8")
text = f.read()
f.close()

# 村长写法
with open("data.txt", encoding="utf-8") as f:
text = f.read()

离开 with 块会自动清理,哪怕中间抛了异常也照样关。文件、锁、数据库连接、临时目录都适用。

村长划重点:判断标准很简单——只要这个对象有 __enter__ / __exit__(或你手动写了 try/finally 去关它),就交给 with。

3. 能用生成器就别先造整个列表​

# 一次性把一百万个数全存进内存
total = sum([n * n for n in range(1_000_000)])

# 一个个来,内存几乎不涨
total = sum(n * n for n in range(1_000_000))

把方括号去掉,列表推导式就变成生成器表达式。数据量一大,差别就是「跑得动」和「内存炸了」。

4. 绝对别用可变对象当默认参数​

这是新手最经典的坑:

# 错的:默认列表在函数定义时创建一次,所有调用共用
def add(item, bucket=[]):
bucket.append(item)
return bucket

print(add("a")) # -> ['a']
print(add("b")) # -> ['a', 'b'] 咦?

# 对的
def add(item, bucket=None):
if bucket is None:
bucket = []
bucket.append(item)
return bucket

列表、字典、集合当默认值都会中招,一律用 None 占位再在函数里创建。

5. 判断 None 用 is,不用 ==​

value = None

if value is None: # 推荐
...

if not value: # 危险:0、空字符串、空列表也会进来
...

is 比较的是「是不是同一个对象」,None 是单例,用它最准确。同理,判断布尔值时先想清楚「空列表」算不算 False。

6. 拼字符串用 join,别在循环里加​

words = ["Python", "小技巧", "真好用"]

# 循环里反复创建新字符串
s = ""
for w in words:
s += w

# 村长写法
s = "".join(words)
s = " · ".join(words) # 还能带分隔符

字符串不可变,循环里 += 会不断产生新对象;join 一次算好长度、一次分配。

7. 用下划线告诉别人「我故意不要」​

# 只要值,不要下标
for _ in range(3):
print("再来一次")

# 只要第一个和最后一个
first, *_, last = [10, 20, 30, 40, 50]

# 解包时忽略中间字段
name, _, _, score = ("小明", "男", "杭州", 95)

_ 是约定俗成的「占位变量」,读代码的人一眼知道这个值被有意丢掉了,比起名 temp2 清楚得多。

村长划重点:在交互解释器里 _ 还有另一层含义——保存上一次表达式的结果。写脚本时没有这个副作用,可以放心当占位符。

小结​

习惯一句话
EAFP先做,出错再兜底
with资源让它自己关
生成器别急着造整个列表
默认参数用 None,别用 []
is None别把 0 和空列表误判成 None
join拼字符串一次到位
_明确告诉别人「我不要」

这些不是死规矩,是 Python 社区多年攒下来的共识。想看完整版,官方的 PEP 8 编码风格指南 值得读一遍;我们教程第 4 章末尾也有中文摘要。

我是村长,不好奇编程的站长。写代码这件事,能跑只是起点,好读才是本事。