Making a list copy over the contents through appending, rather than containing a reference

StackOverflow https://stackoverflow.com/questions/21588374

  •  07-10-2022
  •  | 
  •  

Вопрос

To start off, this is the code I wanted to use to present my problem in a simplified way, but turns out it actually works as I initially expected the thing to work:

list_a = []
list_b = []
for i in range(2):
    list_a = [i, i+1]
    list_b.append(list_a)

Now list_b is [[0, 1], [1, 2]], as I want it to be.

I'm trying to learn programming by making a simple Tetris clone with pygame, and I wanted to use a similar approach to parse a text file into a list containing rotations/frames of a single block (2d lists). I fill out a 2d frame, append it to frames which is the list of all frames, and then reuse frame. However, unlike in the above example, it seems that when frame is appended to frames, it's not the contents of frame, but a reference to frame (though that's probably not the correct term?). What is different about this that it behaves differently, and how do I make it work? Thanks in advance!

class Block:

    object = {}

    def __init__(self, block_type):      
        frame = [[0 for i in range(4)] for i in range(4)]
        frames = []
        frames_file = open('files\\%s.txt' % block_type, 'r')

        for i, line in enumerate(frames_file):
            if line.strip() == '----':
                frames.append(frame)
                print(frame)
                print(frames)
                print('Append!\n')

            else:
                for x, char in enumerate(line.strip()):
                    y = i % 5
                    if char == '#':
                        frame[x][y] = 1
                    elif char == '.':
                        frame[x][y] = 0

        self.frame = frames

Block.object['T'] = Block('T')

Now all frames contain the same thing:

>>> Block.object['T'].frame[0] == Block.object['T'].frame[1]
True

Just for the record, files\T.txt is:

....
###.
.#..
....
----
.#..
##..
.#..
....
----
.#..
###.
....
....
----
.#..
.##.
.#..
....
----
Это было полезно?

Решение

After some digging around and a helpful (although incomplete) hint from a user who already deleted his answer, this is essentially a duplicate of Copying 2D lists in python

The problem here was twofold:

  1. frames.append(frame) indeed only references frame in frames, I didn't attempt to copy it at any point
  2. frames.append(frame[:] and frames.append(list(frame)), which are the usual ways to copy a list, don't work for nested lists in that form

The proper code is: frames.append(list(list(i) for i in frame))

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top