Skip to main content

编程中常见错误的例子 (Part 4)

大家好,继续讲几个编程中的常见错误的例子。

示例 1:在循环中使用 'append' 错误构建列表的列表

  • 问题:代码在循环中尝试构建一个matrix,但每次都将同一个 'row' 对象添加到 'matrix' 中。 由于 'row' 是同一个对象,每次修改都会影响之前添加的行,导致所有行相同。
  • 正确方法:在每次循环迭代中创建新的 'row' 列表,或者使用列表推导式来构建matrix,确保每行是独立的列表。

示例 2:误解列表推导式中的作用域和延迟绑定闭包

  • 问题:代码在列表推导式中创建 lambda 函数,但由于 Python 的延迟绑定闭包特性, lambda 函数中的变量 'i' 绑定的是循环结束后的最终值,而不是每次迭代的值。 这导致所有函数返回相同的结果,而不是预期的不同倍数。
  • 原因:在 Python 中,当一个变量被用在闭包中时,变量不会立即绑定到闭包创建时的值。 相反,变量在闭包执行时才会被查找。在这个例子中,lambda 函数 lambda x: x * i 捕获了变量 i, 但是它并没有存储 i 在创建时的值,而是存储了对变量 i 的引用。 循环 for i in range(3) 迭代了三次,每次都创建了一个新的 lambda 函数。 但是,所有这些 lambda 函数都捕获了 同一个 变量 i。 当 result 列表推导式执行时,循环 for i in range(3) 已经完成,变量 i 的值为 2 (循环中最后一次赋值)。 因此,当每个 lambda 函数执行时,它查找变量 i 的值,此时 i 的值为 2。 这就是为什么所有的 lambda 函数都相当于 lambda x: x * 2,结果为 [4, 4, 4]
  • 正确方法:使用工厂函数或在列表推导式中捕获当前迭代的值, 例如通过 'lambda x, i=i: x * i' 来确保每个 lambda 函数绑定的是当前循环的值。

示例 3:使用 'sorted' 而不理解它返回新列表

  • 问题:代码使用 'sorted' 函数对列表进行排序,但没有意识到 'sorted' 返回一个新的排序列表, 而不修改原始列表。这可能导致开发者误以为原始列表已被排序。
  • 正确方法:如果需要修改原始列表,使用 'list.sort()' 方法; 如果需要新列表,使用 'sorted()' 并将结果赋值给新变量。

示例 4:使用可变对象作为字典键

  • 问题:代码尝试使用列表作为字典键,但列表是可变的,因此不可哈希,会引发 TypeError 异常。 这是因为字典键必须是不可变的类型。
  • 正确方法:使用不可变类型(如字符串、元组)作为字典键。如果需要使用列表作为键,可以先将其转换为元组。

示例 5:未处理类属性中的可变状态

  • 问题:代码在类中定义了一个列表作为类属性 'count',这意味着所有实例共享同一个列表。 修改一个实例的 'count' 会影响所有实例,这可能导致意外的状态共享。
  • 正确方法:将可变状态定义为实例属性(在 'init' 方法中初始化), 确保每个实例有自己的独立状态,而不是共享类属性。

代码示例

# Example 1: Incorrectly using 'append' 
# in a loop to build a list of lists
matrix = []
row = []
for i in range(3):
row.append(i)
matrix.append(row)
print(matrix)
# print [[0, 1, 2], [0, 1, 2], [0, 1, 2]]

# Example 2: Misunderstanding scope and late
# binding closures in list comprehensions
values = [lambda x: x * i for i in range(3)]
result = [f(2) for f in values]
print(result)
# print [4, 4, 4]

# Example 3: Using 'sorted' without
# understanding it returns a new list
original_list = [3, 1, 2]
sorted(original_list)
print(original_list)
# print [3, 1, 2]

# Example 4: Using mutable objects
# as dictionary keys
my_dict = {[1, 2, 3]: "value"}
print(my_dict)

# Example 5: Not handling mutable state
# in class attributes
class Counter:
count = []

def add(self, value):
self.count.append(value)

counter1 = Counter()
counter2 = Counter()
counter1.add(1)
counter2.add(2)
print(counter1.count)