python 如何快速复制序列


1 基本用法

把序列乘以一个整数,就会产生一个新序列。这个新序列是原始序列复制了整数份,然后再拼接起来的结果。

l=[1,2,3]
l2=l * 3
logging.info('l2 -> %s',l2)
l3=5 * 'deniro'
logging.info('l3 -> %s',l3)

运行结果:

INFO - l2 -> [1, 2, 3, 1, 2, 3, 1, 2, 3]
INFO - l3 -> denirodenirodenirodenirodeniro

* 复制语法不会修改原有的操作对象,而是构建出一个全新的序列。

2 列表陷阱

a * n 语法中,a 为列表,n 为需要复制的列表数。如果 a 列表中的元素是基本类型的话,没什么问题。但如果 a 列表中的元素是对象的引用的话,那么这些复制出来的列表中的引用其实指向的是同一个引用。

Luciano Ramalho 举了一个井字棋示例。

井字棋,英文名叫Tic-Tac-Toe,是一种在3*3格子上进行的连珠游戏,和五子棋类似,由于棋盘一般不画边框,格线排成井字故得名。游戏需要的工具仅为纸和笔,然后由分别代表O和X的两个游戏者轮流在格子里留下标记(一般来说先手者为X),任意三个标记形成一条直线,则为获胜。

(1)错误示例 1

weird_board = [['_'] * 3] * 3
logging.info('weird_board -> %s', weird_board)
weird_board[1][2] = 'X'
logging.info('weird_board -> %s', weird_board)

运行结果:
INFO - weird_board -> [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
INFO - weird_board -> [['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']]

可以看到虽然代码中只修改了 [1][2] 位置的值,但却影响到了三处地方。这就说明这三处其实指向的是同一个引用。

(2)错误示例 2

这个示例犯的错与前一个示例相同,都是把同一个对象追加到同一块游戏板中(board)。

row = ['_'] * 3
board = []
for i in range(3):
  board.append(row)
logging.info('board -> %s', board)
board[1][2] = 'X'
logging.info('board -> %s', board)

运行结果:

INFO - board -> [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
INFO - board -> [['_', '_', 'X'], ['_', '_', 'X'], ['_', '_', 'X']]

(3)正确示例

对示例 2 进行改造,就可以避免上述问题。

board = []
for i in range(3):
  row = ['_'] * 3
  board.append(row)
logging.info('board -> %s', board)
board[1][2] = 'X'
logging.info('board -> %s', board)

运行结果:

INFO - board -> [['_', '_', '_'], ['_', '_', '_'], ['_', '_', '_']]
INFO - board -> [['_', '_', '_'], ['_', '_', 'X'], ['_', '_', '_']]

这里把 row = ['_'] * 3 放入 for 循环中,这样每一次循环都会新建一个 row,然后再放入游戏板中。这样游戏板中的每一个单元格都是独立的,互不影响。

利用列表推导方法,还可以简化示例代码:

board = [['_'] * 3 for i in range(3)]
logging.info('board -> %s', board)

board[1][2] = 'X'
logging.info('board -> %s', board)



以上就是python 如何快速复制序列的详细内容,更多关于python 复制序列的资料请关注来客网其它相关文章!


相关链接