Python 基础真的扎实吗?15 个容易踩坑的知识点复盘

2026-05-03 29 预计阅读时间:1 分钟
来源:realpython.com AI 摘要 原文链接

免责声明:本文为 AI 摘要整理,建议结合原文阅读。摘要可能省略上下文、版本差异或边界条件,不作为官方说明。

预计阅读时间:8 分钟

日常写 Python,importdeffor 用得飞起,但一旦遇到边界情况——整数除法、变量作用域、异常捕获顺序——就容易翻车。这篇文章围绕变量、数据类型、运算符、表达式、关键字和异常这六大板块,把高频踩坑点逐一拆开,并附上可直接运行的验证脚本。

变量与赋值:不是"贴标签"那么简单

Python 变量是引用,不是容器。同一个对象可以被多个变量指向:

a = [1, 2, 3]
b = a
b.append(4)
print(a)  # [1, 2, 3, 4] — a 也变了

要避免意外共享,用拷贝:

b = a.copy()       # 浅拷贝,够用就行
b = a[:]           # 切片拷贝,等价写法

另一个经典陷阱——小整数缓存:-5256 的整数在 CPython 中被预创建,x == yx is y 都为 True;超出范围就未必了:

x = 300
y = 300
print(x == y)  # True
print(x is y)  # False(大部分场景)

面试或调试时,搞清 ==(值相等)和 is(身份相同)的区别,能省不少时间。

数据类型:隐式转换与边界行为

整数除法

Python 3 里 / 总是浮点结果,// 才是整除:

print(7 / 2)   # 3.5
print(7 // 2)  # 3
print(-7 // 2) # -4 — 向下取整,不是截断

负数整除向负无穷方向靠,这和 C/Java 的截断行为不同,写索引计算时要格外小心。

浮点精度

print(0.1 + 0.2 == 0.3)  # False
print(0.1 + 0.2)         # 0.30000000000000004

需要精确比较时,用 math.isclosedecimal.Decimal

from decimal import Decimal
print(Decimal('0.1') + Decimal('0.2') == Decimal('0.3'))  # True

布尔值是 int 的子类

True 就是 1False 就是 0

print(True + True)       # 2
print(isinstance(True, int))  # True

所以 if xx0""[]None 时都走 False 分支——记住完整的"假值表"比逐个猜更靠谱。

运算符与表达式:优先级与短路

优先级坑点

not 的优先级高于 and,高于 or

not a and b or c
# 等价于 ((not a) and b) or c,而不是 not (a and (b or c))

拿不准就加括号,可读性也更好。

短路求值

and / or 会短路,且返回的是决定结果的那个值,不一定是 True/False

print(3 or 0)    # 3
print(0 or 3)    # 3
print(3 and 0)   # 0
print(0 and 3)   # 0

利用这个特性可以写简洁的默认值逻辑:name = input_name or "anonymous"

关键字:几个容易混淆的

关键字 常见误用
global 在函数内声明后才能修改全局变量,只读不需要
nonlocal 嵌套函数中修改外层局部变量,不是全局
yield 让函数变成生成器,return 仍然可用但会终止生成
assert 可被 python -O 关闭,不要用它做业务校验

一个 nonlocal 的正确场景:

def counter():
    n = 0
    def inc():
        nonlocal n
        n += 1
        return n
    return inc

c = counter()
print(c())  # 1
print(c())  # 2

如果漏写 nonlocaln += 1 会报 UnboundLocalError——Python 看到赋值就把 n 当成局部变量,但赋值前又读了它,矛盾了。

异常处理:顺序、类型与 finally

捕获顺序从窄到宽

try:
    int("abc")
except ValueError:
    print("值错误")
except Exception:          # 必须在更窄的异常之后
    print("其他错误")

如果先写 except ExceptionValueError 永远不会被单独捕获。

elsefinally 的语义

  • elsetry 块没有抛异常时执行,适合放"成功后的逻辑",避免意外捕获不属于 try 的异常。
  • finally:无论如何都执行,常用于资源释放。
try:
    f = open("data.txt")
    data = f.read()
except FileNotFoundError:
    print("文件不存在")
else:
    print(f"读到 {len(data)} 字节")
finally:
    f.close()  # 注意:如果 open 就失败了,f 未定义,这里会报错

更安全的写法是用 with,让上下文管理器替你关文件。

实战验证脚本

把上面提到的坑点集中到一个脚本里,逐条运行、逐条确认:

#!/usr/bin/env python3
"""Python 基础踩坑验证脚本 — 直接运行即可"""

# 1. 变量共享 vs 拷贝
a = [1, 2, 3]
b = a
b.append(4)
print("1. 共享引用:", a)          # 预期 [1, 2, 3, 4]

c = a.copy()
c.append(5)
print("1. 拷贝后互不影响:", a)     # 预期 [1, 2, 3, 4],不含 5

# 2. 小整数缓存
x, y = 256, 256
print("2. 256 is:", x is y)       # 预期 True
x, y = 257, 257
print("2. 257 is:", x is y)       # 预期 False(多数环境)

# 3. 整除方向
print("3. -7//2 =", -7 // 2)      # 预期 -4

# 4. 浮点精度
print("4. 0.1+0.2 =", 0.1 + 0.2)  # 预期 0.30000000000000004

# 5. 布尔是 int 子类
print("5. True+True =", True + True)  # 预期 2

# 6. 短路返回值
print("6. 3 or 0 =", 3 or 0)      # 预期 3
print("6. 0 or 3 =", 0 or 3)      # 预期 3

# 7. nonlocal
def counter():
    n = 0
    def inc():
        nonlocal n
        n += 1
        return n
    return inc

c = counter()
print("7. counter:", c(), c())    # 预期 1 2

# 8. 异常捕获顺序
try:
    int("abc")
except ValueError:
    print("8. 捕获 ValueError")   # 预期走到这里
except Exception:
    print("8. 捕获 Exception")

# 9. try-else-finally
try:
    result = 10 / 2
except ZeroDivisionError:
    print("9. 除零")
else:
    print("9. 成功, result =", result)  # 预期走到这里
finally:
    print("9. finally 总会执行")

print("--- 全部验证完成 ---")

运行方式:

python3 python_fundamentals_check.py

如果某条输出和预期注释不一致,说明你的 Python 环境(版本或实现)有差异,正好值得深挖原因。

复盘清单

每次觉得自己"Python 基础没问题"时,可以用这张清单快速自测:

  • 变量:赋值是引用还是拷贝?is== 分别比较什么?
  • 类型:整除对负数怎么取?浮点比较用什么方法?哪些值在 if 中为假?
  • 运算符not/and/or 优先级顺序?短路返回的是布尔值还是原值?
  • 关键字global vs nonlocal 区别?assert 能被关闭吗?
  • 异常:捕获顺序从窄到宽?elsefinally 各在什么时候执行?

基础不是"入门后就不用再看"的知识,而是写代码时每天都在做的小决策。把这些细节吃透,调试时间会明显缩短,代码意图也更干净。


相关推荐