Python作为入门门槛较低的编程语言,凭借简洁的语法吸引了大量初学者,但很多新手在编写代码时还是会频繁遇到各种奇怪的问题,这些问题往往不是复杂的逻辑错误,而是对Python底层特性不够了解导致的。下面我们就来梳理这些常见的坑点,帮助大家避开学习路上的障碍。

缩进相关的错误
Python使用缩进来表示代码块,这和很多其他语言用大括号的方式完全不同,也是新手最容易出错的地方之一。
混用空格和制表符
有些编辑器默认用制表符缩进,有些用4个空格,如果同一份代码里同时出现两种缩进方式,Python解释器就会报错。比如下面的代码:
# 这里用空格缩进
def test():
print("hello")
# 这里用制表符缩进,运行时会报IndentationError
print("world")
test()
解决方法很简单,统一使用4个空格作为缩进,大部分编辑器都可以设置把制表符自动转换为空格。
缩进层级不对
忘记缩进或者缩进层级不对也会导致语法错误,比如条件判断后的代码没有缩进:
a = 10
if a > 5:
print("a大于5") # 这里没有缩进,会报IndentationError
变量作用域的误区
Python的变量作用域规则经常让新手困惑,尤其是在函数内部修改外部变量的时候。
函数内修改全局变量未声明
如果在函数内部想要修改全局变量,需要用global关键字声明,否则会被认为是局部变量:
count = 0
def add():
# 这里没有声明global,会报UnboundLocalError
count = count + 1
return count
print(add())
正确的写法是在函数内部先声明全局变量:
count = 0
def add():
global count
count = count + 1
return count
print(add()) # 输出1
闭包中的变量绑定问题
很多新手在写闭包的时候会遇到变量值不符合预期的情况,比如下面的例子:
funcs = []
for i in range(3):
def inner():
return i
funcs.append(inner)
for f in funcs:
print(f()) # 输出3 3 3,而不是预期的0 1 2
这是因为闭包绑定的是变量的引用,循环结束后i的值变成了2,所有函数调用的时候拿到的都是最终的i值。解决方法可以用默认参数的方式绑定当前值:
funcs = []
for i in range(3):
def inner(i=i):
return i
funcs.append(inner)
for f in funcs:
print(f()) # 输出0 1 2
可变对象作为默认参数的坑
Python中函数的默认参数是在函数定义的时候计算的,而不是每次调用的时候计算,如果默认参数是可变对象(比如列表、字典),就会出现共享同一个对象的问题。
def add_item(item, lst=[]):
lst.append(item)
return lst
print(add_item(1)) # 输出[1]
print(add_item(2)) # 输出[1, 2],而不是预期的[2]
正确的做法是将默认参数设为None,在函数内部再初始化可变对象:
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
print(add_item(1)) # 输出[1]
print(add_item(2)) # 输出[2]
比较操作的常见错误
新手经常会混淆==和is的用法,也会在链式比较的时候写出不符合预期的逻辑。
==和is的区别
==比较的是两个对象的值是否相等,is比较的是两个对象是否是同一个对象(即内存地址是否相同):
a = [1, 2, 3] b = [1, 2, 3] print(a == b) # 输出True,值相等 print(a is b) # 输出False,不是同一个对象 c = 10 d = 10 print(c is d) # 输出True,小整数有缓存机制
链式比较的误区
Python支持链式比较,但是新手可能会写出错误的逻辑,比如判断一个数是否在某个区间之外:
x = 5 # 错误写法,本意是x小于1或者x大于3,实际等价于 (x < 1) and (1 > x > 3) print(x < 1 > x > 3) # 输出False,逻辑不符合预期 # 正确写法 print(x < 1 or x > 3) # 输出True
字符串和编码的相关问题
Python3中字符串默认是Unicode编码,新手在处理字符串拼接、编码转换的时候也容易出错。
字符串和数值直接拼接
新手经常会尝试把字符串和数值直接拼接,导致类型错误:
age = 18
# 错误写法,会报TypeError
print("我今年" + age + "岁")
# 正确写法1:转成字符串
print("我今年" + str(age) + "岁")
# 正确写法2:使用格式化
print(f"我今年{age}岁")
其他常见小错误
- 忘记给变量赋值就直接使用,会报
NameError - 用
input()获取输入的时候,得到的是字符串类型,直接做数值运算会报错,需要先转类型 - 遍历列表的时候同时修改列表,会导致遍历结果不符合预期,比如删除元素的时候索引错位
- 导入模块的时候,模块名和变量名冲突,比如自己写了个
json.py,再导入标准库的json就会出错
这些坑点都是Python初学者经常会遇到的问题,只要多留意Python的语言特性,写代码的时候多思考变量的作用范围和对象的特性,就能有效避开这些问题,减少不必要的调试时间。