2

I am creating an extremely basic ASCII plotting module for Python. When I call my graph.plot() function, it ignores the Y and plots the icon for the X coordinate in all the lists within the main list.

class Plotsy():
    def __init__(self):
        self.config("#", [3, 3])
    def config(self, icon, size):
        #Choose the plotted icon
        self.icon = icon
        #Make "size" useable throughout the object for math
        self.size = size
        #Create the grid
        self.graph = [["@"] * self.size[0]] * self.size[1]
    def plot(self, coords):
        self.graph[coords[1]][coords[0]] = self.icon
    def draw(self):
        pass
#A very short example to plot things
graph = Plotsy()
graph.plot([1, 2])
#After this problem is resolved, this will be replaced with my draw() function to print it correctly
print graph.graph

The graph variable works like this - the lists within the outermost list is the Y (these lists will be printed on their own lines), and the values in those lists are for the X coordinate. plot() takes one parameter, which is a list of the X and Y coordinates.

Why does it do this, and how can I fix it?

Quojil
  • 107
  • 1
  • 8
  • What output are you expecting? – Adam Smith Feb 20 '14 at 00:41
  • Sorry, I was in a hurry. The icon appears on the X coord in all the sub-lists of graph.graph (the Y) when it shouldn't. Based on the code, I want the output to be like this: [['@', '@', '@'], ['@', '@', '@'], ['@', '#', '@']] – Quojil Feb 20 '14 at 00:43
  • 2
    basically `[["@"]*N]*Y` is not doing what you think it is – Joran Beasley Feb 20 '14 at 00:45
  • Ah, thanks. I couldn't think of a searchable way to find the problem - so I expected there would be dupes. – Quojil Feb 20 '14 at 00:48

2 Answers2

0

["@"]*N creates your list as expected

however [["@"]*N]*Y makes Y pointers to the SAME list ... that means any time you change any of the lists they all change

Joran Beasley
  • 110,522
  • 12
  • 160
  • 179
0

The problems arises from the initialization of your class' graph member in its config method:

self.graph = [["@"] * self.size[0]] * self.size[1]

As opposed to the behaviour you expect, this sets up a list which contains 3 (self.size[1]) times the same instance of a list ["@", "@", "@"]. So if you plot a dot into any row of the grid, it appears in all of them, since all rows are in fact aliases of the very same single list object. So instead of copying the same list reference over and over [or, 3x], instantiate a new list for every row in your grid. To do so, use iteration:

self.graph = [["@"] * self.size[0] for _ in range(self.size[1])]

This will do as desired.

>>> graph = Plotsy()
>>> graph.plot([1, 1])
>>> print '\n'.join([''.join([col for col in row]) for row in graph.graph])
@@@
@#@
@@@
J. Katzwinkel
  • 1,923
  • 16
  • 22