Python 新手最容易踩的 10 个语法坑

Python 新手最容易踩的 10 个语法坑

很多人觉得 Python 语法简洁,上手快。但正是这种"简洁",藏了不少让人掉坑的细节。以下 10 个坑,几乎每个新手都踩过至少一半。


1. 可变默认参数

python 复制代码
python
def add(item, lst=[]):
    lst.append(item)
    return lst

print(add(1))  # [1]
print(add(2))  # [1, 2] ← 意外!

默认参数只在函数定义时求值一次,lst=[] 是同一个对象。正确写法:

python 复制代码
python
def add(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

2. 闭包延迟绑定

ini 复制代码
python
funcs = [lambda: i for i in range(5)]
print([f() for f in funcs])  # [4, 4, 4, 4, 4]

lambda 里的 i 不是"捕获值",而是"引用变量"。循环结束后 i=4,所以全返回 4。

修复lambda i=i: i,用默认参数锁住当前值。


3. is vs ==

ini 复制代码
python
a = 256
b = 256
print(a is b)  # True(小整数池)

a = 257
b = 257
print(a is b)  # False!

is 比较的是内存地址== 才比较值。判断相等,永远用 ==is 只该用于和 None 比较(if x is None)。


4. 缩进导致的逻辑错误

python 复制代码
python
def foo(x):
    if x > 0:
        print("正数")
    return "完成"  # 这个 return 不在 if 里

新手常以为缩进只是"格式",其实它是语法本身。Tab 和空格混用会直接报错,PEP 8 规定统一用 4 个空格。


5. 修改正在遍历的列表

ini 复制代码
python
nums = [1, 2, 3, 4]
for n in nums:
    if n % 2 == 0:
        nums.remove(n)
print(nums)  # [1, 3] → 但如果是 [2,4,6,8] 会出问题

遍历中删除元素会导致索引错乱。正确做法:

ini 复制代码
python
nums = [n for n in nums if n % 2 != 0]
# 或
for n in nums[:]:  # 遍历副本

6. 字符串不可变,但变量名可以"变"

ini 复制代码
python
s = "hello"
s = s + " world"  # 不是在原字符串上改,而是创建了新对象

很多新手以为字符串拼接是"修改",其实每次都生成新对象。大量拼接时,用 ''.join(list) 或 f-string 性能好得多。


7. 浅拷贝 vs 深拷贝

css 复制代码
python
import copy

a = [[1, 2], [3, 4]]
b = a.copy()        # 浅拷贝
b[0][0] = 999
print(a)  # [[999, 2], [3, 4]] ← 原列表也被改了!

c = copy.deepcopy(a)  # 深拷贝才真正独立

列表的 .copy()list()、切片 [:] 都是浅拷贝。嵌套结构必须用 copy.deepcopy()


8. except 捕获范围太大

python 复制代码
python
try:
    result = 10 / 0
except:  # 什么都捕获,包括系统退出信号
    print("出错了")

except 会捕获 KeyboardInterrupt,导致你按 Ctrl+C 都关不掉程序。始终写具体异常:

python 复制代码
python
except ZeroDivisionError:
    print("除零了")

9. 字典键必须可哈希

ini 复制代码
python
d = {[1, 2]: "value"}  # TypeError: unhashable type: 'list'

列表、字典、集合都不能当字典的 key,因为它们可变。元组可以。


10. for...elsewhile...else

python 复制代码
python
for i in range(5):
    if i == 10:
        break
else:
    print("循环正常结束")  # 会执行!

else 在循环没有被 break 打断 时才执行。这个设计是故意的(用于搜索场景),但 90% 的新手第一次见到都会困惑。反过来说:else 跟着 for,不是跟着 if


总结

本质原因
默认参数 对象在定义时创建,不是调用时
闭包延迟绑定 引用变量,不是捕获值
is vs == 混淆了"身份"和"值"
缩进错误 把 Python 当纯文本语言
遍历中修改 索引在变,迭代器跟不上
字符串拼接 误以为字符串可变
浅拷贝 不理解引用传递
裸 except 不知道异常体系
字典 key 不了解可哈希规则
for-else 不知道 else 的真实语义

Python 的"简单"是给老手的,新手恰恰要在这些"简单"里保持警惕。踩过这些坑,才算真正入门。

相关推荐
杨充14 分钟前
1.面向对象设计思想
后端
IT_陈寒28 分钟前
Java的Date类又坑了我一次,改用时间戳真香
前端·人工智能·后端
systemPro1 小时前
2.6亿条设备数据,历史查询从超时到50ms,我做了什么
后端
要阿尔卑斯吗1 小时前
提示词优化启示:为什么“按顺序输出“比“关键度评分“更有效
后端
她的男孩2 小时前
后台接口加密别只会 HTTPS,ForgeAdmin 的 RSA + SM4/AES 源码拆解
后端·面试·开源
极光技术熊2 小时前
Spring AI 从入门到精通:构建你的 AI 开发知识体系
后端·github
程序员cxuan2 小时前
一句话,让你用上 GPT-5.6
人工智能·后端·程序员
远航_2 小时前
OpenSpec 完整详细介绍
前端·后端
AskHarries2 小时前
不用公网 IP,把 Windows 和 Linux 服务器放进同一个局域网:Tailscale 组网实战
后端
神奇小汤圆2 小时前
Java 的1 亿次对象创建:JVM 开启 / 关闭逃逸分析,GC 性能差距巨大
后端