0

I have a class that has a list inside my constructor

class FCM:
def __init__(self, input_table, attributes, num_centroids, m, start_indep, pos_of_y):
    self.xs = # it's a list of lists

self.xs is a list of lists that gets passed to a function down below. I made a copy because I wanted to be certain that the xs did not change as a result of my function.

from copy import copy
    xs_copy=[]
    xs_copy=copy(self.xs)    
self.current_centroids=self.get_initial_centroids(xs_copy)   

And here is the function:

def get_initial_centroids(self, these_xs):

    print str(self.xs[0])               
    for i in range(len(these_xs)):
        these_xs[i].append(self.cluster_distance(these_xs[i][self.start_indep:], avg_centroid))

    print str(self.xs[0])    # Why is my class list affected???????

What I'd like to understand is why self.xs is affected at all by this function as I passed a copy of it to my function.

For those interested in more than just the gist:

from __future__ import division
import MySQLdb
class FCM:
    def __init__(self, input_table, attributes, num_centroids, m, start_indep, pos_of_y):

    self.input_table=input_table
    self.db=MySQLdb.connect()
    self.cursor=self.db.cursor()
    self.cursor.execute("select " + ",".join(attributes) + " from " + input_table)
    ys=[]
    for record in self.cursor.fetchall():
         ys.append([int(r) if type(r) is long else r for r in list(record)]) # some of the data is of type long and should be of type integer  
    self.xs=ys[:]
    self.num_centroids=num_centroids
    self.m=m        
    self.start_indep=start_indep
    self.pos_of_y=pos_of_y

    from copy import copy
    xs_copy=[]
    xs_copy=copy(self.xs)   
    self.current_centroids=self.get_initial_centroids(xs_copy)       

    print "Initial centroids are " + str(self.current_centroids)    

def get_initial_centroids(self, these_xs):
    running_total=these_xs[0][self.start_indep:]
    cnt=0
    for this_x in these_xs[1:]:
        running_total = self.vector_add(running_total, this_x[self.start_indep:])
        cnt += 1
    avg_centroid=self.scalar_mult(running_total, 1/cnt)   
    print str(self.xs[0]) # this is the same as in the constructor              
    for i in range(len(these_xs)):
        these_xs[i].append(self.cluster_distance(these_xs[i][self.start_indep:], avg_centroid))
    print str(self.xs[0])  # but now self.xs has changed
Matt Cremeens
  • 4,951
  • 7
  • 38
  • 67
  • 2
    Could you provide a [mcve]? The code fragments provided aren't actually runnable, and so aren't sufficient to let someone reproduce the issue. – Charles Duffy Sep 20 '17 at 00:43
  • 3
    Your list appears to be multi-dimensional (I see `these_xs[i][self.start...]`). Use `deepcopy` instead: `from copy import deepcopy` and `xs_copy = deepcopy(self.xs)`. –  Sep 20 '17 at 00:51
  • I have added more code per your request. – Matt Cremeens Sep 20 '17 at 00:51
  • 1
    Aside: since you're running Python 2, it's probably better to inherit from `object` to get extra goodies: `class FCM(object):`. –  Sep 20 '17 at 00:52
  • 1
    @Evert that did the trick. Would you mind putting that in an answer (if you so choose) so I can accept it. Thanks so much. – Matt Cremeens Sep 20 '17 at 00:53
  • Yeah it's a common enough quirk for people to encounter, I'm sure there are many questions of this nature on the site. I've marked it as a duplicate to point future readers in the right direction. – David Z Sep 20 '17 at 00:56
  • I am sorry to have posted a duplicate. Had I known that the issue was with how I copied the list, I would have known to search for that. Is there something I should do? Delete the question? – Matt Cremeens Sep 20 '17 at 00:57
  • So, the basic question is this: If you had your same bug today, and you were searching through StackOverflow's existing knowledgebase, would having this dupe present in the search results lead you to the existing answer, when you wouldn't have found it otherwise? If so, the dupe adds value and should stay; otherwise, deleting it may be appropriate. – Charles Duffy Sep 20 '17 at 01:26
  • (BTW, adding more details is appreciated, but it'd be nice in the future to also pay attention to the *minimal* part of the MCVE definition, cutting down to the shortest code that reproduces the problem). – Charles Duffy Sep 20 '17 at 01:27

0 Answers0