Python中两种初始化二维数组方式的比较

时间:2025-05-08 07:17:07

Python中两种初始化二维数组方式的比较

在Python中,dp = [[0] * n for _ in range(m)]dp = [[0 for _ in range(n)] for _ in range(m)] 确实能达到相同的效果——创建一个m行n列的二维数组,并将所有元素初始化为0。但它们内部实现机制有所不同,在某些特殊情况下会表现出差异。

两种写法的等价性

基本情况下(元素为不可变对象如0)

当数组元素是不可变对象(如整数0)时,两种写法完全等价:

m, n = 3, 4

# 写法1
dp1 = [[0] * n for _ in range(m)]

# 写法2
dp2 = [[0 for _ in range(n)] for _ in range(m)]

print(dp1 == dp2)  # 输出: True

内部机制差异

写法1:[[0] * n for _ in range(m)]

  1. 先创建包含n个0的列表[0, 0, ..., 0]
  2. 然后为每一行创建这个列表的独立副本

写法2:[[0 for _ in range(n)] for _ in range(m)]

  1. 为每一行的每个元素单独执行0的创建
  2. 每个元素都是独立的新对象

关键区别场景(当元素是可变对象时)

当初始化可变对象(如列表、字典等)时,两种写法会产生重大区别:

m, n = 3, 4

# 写法1 - 有潜在问题
dp_problem = [[[]] * n for _ in range(m)]
dp_problem[0][0].append(1)
print(dp_problem)
# 输出: [[[1], [1], [1], [1]], 
#      [[1], [1], [1], [1]], 
#      [[1], [1], [1], [1]]]
# 所有行的第一个元素都被修改了!

# 写法2 - 正确的做法
dp_correct = [[[] for _ in range(n)] for _ in range(m)]
dp_correct[0][0].append(1)
print(dp_correct)
# 输出: [[[1], [], [], []], 
#      [[], [], [], []], 
#      [[], [], [], []]]
# 只有指定的元素被修改

性能比较

对于简单不可变对象(如0):

  • 写法1稍快,因为[0]*n是C语言层面的优化操作
  • 写法2更通用,但稍慢

测试代码:

import timeit

m, n = 1000, 1000

def method1():
    return [[0] * n for _ in range(m)]

def method2():
    return [[0 for _ in range(n)] for _ in range(m)]

print(timeit.timeit(method1, number=10))  # 约0.5秒
print(timeit.timeit(method2, number=10))  # 约0.7秒

最佳实践建议

  1. 对于不可变对象(如0、None等)

    • 两种写法都可以,[[0]*n for _ in range(m)]性能稍好
  2. 对于可变对象(如[]、{}等)

    • 必须使用[[... for _ in range(n)] for _ in range(m)]写法
    • 避免使用[...]*n,否则会导致行间共享引用
  3. 代码可读性考虑

    • 如果团队不熟悉Python的这个特性,写法2更明确
    • 如果追求性能且确认元素不可变,写法1更简洁

结论

当元素是不可变对象(如0)时,两种初始化方式在功能上是等价的,但[[0]*n for _ in range(m)]性能稍好;当元素是可变对象时,必须使用[[0 for _ in range(n)] for _ in range(m)]写法,否则会导致意外的引用共享问题。

相关文章