1

I have a question that spawned from writing my own class to manage a two-dimension table.

I started by creating a simple class as follows, creating an empty_line object that was copied as much as needed to create the number of lines:

class Table(object):
"""Table class, allows the creation of new lines and columns to the table"""
def __init__(self, col = 1, lines = 1, defaultcontent=''):
    self.columns = col
    self.lines = lines
    self.empty_line = [defaultcontent for i in range(self.columns)]
    self.table = [self.empty_line for j in range(self.lines)]

def add_line(self):
    self.table.append(self.empty_line)
    self.lines += 1

def add_column(self):
    self.empty_line.append('')
    for i in range(self.lines):
        self.table[i].append('')

However, after I created a table, for example with table = Table(5,3), and do an assignment with table.table[1][2] = 'something', I realised the 'something' found itself in every line, and that I couldn't change a single line without having the others changed. Also, self.empty_line was changed.

After a little while, I wrapped my head around the problem being in the self.empty_line usage. I rewrote my class, this time taking out the self.empty_line and replacing it with the primitive ['' for i in range(self.columns)] (and of course also correcting the bug in the add_column() method that would add two columns instead of just one!).

My problem went away, but a question still lingers: Shouldn't the self.table = [self.empty_line for j in range(self.lines)] create a copy of the self.empty_line object for every new line, instead of somehow 'linking' the same self.empty_line instance (that gets changed).

So what am I doing wrong, and where is the hole in my knowledge about python objects?

gromain
  • 222
  • 3
  • 11

1 Answers1

1

In your code:

self.empty_line = [defaultcontent for i in range(self.columns)]
self.table = [self.empty_line for j in range(self.lines)]

The empty_line is copied in every line of the table using swallow copy. You copied only references, not the default content.

To fix that:

self.table = [[default_content] * self.columns for _ in range(self.lines)]

Same problem with add_line. Don't store empty_line but use default_content instead.

self.table.append([self.default_content] * self.columns)
...

See: Python copy a list of lists

Community
  • 1
  • 1
Laurent LAPORTE
  • 21,958
  • 6
  • 58
  • 103
  • This is what I needed to get around this concept, the shallow/deep copy difference! Thanks a lot! – gromain Sep 06 '16 at 07:09