2021年3月7日星期日

Adding objects created by a @classmethod to a Python list using a for loop

I have the following list of values assigned to the variable homeTasks:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]  

I have a for loop to assign a list of objects of the class Task to the variable allTasks.

# create empty allTasks list  allTasks=[]    # create thisTask for every value of homeTasks and append to allTasks  for y in range(len(homeTasks)):          thisTask = Task.get_task(homeTasks[y])          allTasks.append(thisTask)          print(allTasks[y].taskName)    # print task names from allTasks for testing:  for z in range(len(allTasks)):          print(z)          print(allTasks[z].taskName)    

This gives me the following:

Do Dishes  Make Bed  Laundry  Study  Laundry  Elliptical  Elliptical  Laundry  Elliptical  Elliptical  Elliptical  test  0  test  1  test  2  test  3  test  4  test  5  test  6  test  7  test  8  test  9  test  10  test  11  test  

For some reason, the last object assigned to allTasks is assigned to every index in the list. This is true for all attributes of thisTask.

For reference, this is what my Task class and get_task classmethod look like:

class Task(object):      def __init__(self, taskID, taskName, points, active, complete, approved, assignedUserID, createdByUserID, dateCreated, dateCompleted, frequency):          self.taskID = taskID          self.taskName = taskName          self.points = points          self.complete = complete          self.approved = approved          self.assignedUserID = assignedUserID          self.createdByUserID = createdByUserID          self.dateCreated = dateCreated          self.dateCompleted = dateCompleted          self.frequency = frequency          self.homeID = homeID        @classmethod        def get_task(self, taskID):          t = (taskID,)          cur = mysql.connection.cursor()          cur.execute("SELECT * FROM tasks WHERE taskID=%s", t)          columns = [col[0] for col in cur.description]          task = [dict(zip(columns, row)) for row in cur.fetchall()]          self.taskID = taskID           self.taskName = task[0]['taskName']          self.points = task[0]['points']          self.aproved = task[0]['approved']          self.assignedUserID = task[0]['assignedUserID']          self.createdByUserID = task[0]['createdByUserID']          self.dateCreated = task[0]['dateCreated']          self.dateCompleted = task[0]['dateCompleted']          self.frequency = task[0]['frequency']          self.dueDate = task[0]['dueDate']          self.homeID = task[0]['homeID']          return self  

I know the method is working right because thisTask has the right values each time the loop iterates. It seems like .append is not working because as soon as I get out of the loop, the values in allTasks are wrong.

EDIT: per @barny I have created a minimal reproducible example for this below:

import copy    # initialize Task object    class Task(object):      def __init__(self, taskID, taskName, points, active, complete, approved, assignedUserID, createdByUserID, dateCreated, dateCompleted, frequency):          self.taskID = taskID          self.taskName = taskName    # define method to return values        @classmethod        def get_task(self, index):          taskIDList = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]          taskNames = ['Do Dishes', 'Make Bed', 'Laundry', 'Study', 'Laundry', 'Elliptical', 'Elliptical', 'Laundry', 'Elliptical', 'Elliptical', 'Elliptical', 'test']          self.taskID = taskIDList[index]          self.taskName = taskNames[index]          return self    # create empty allTasks list  allTasks=[]    homeTasks = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]    # create thisTask for every value of homeTasks and append to allTasks  for y in range(len(homeTasks)):          thisTask = Task.get_task(y)          allTasks.append(thisTask)          print(allTasks[y].taskName)    # print task names from allTasks for testing:  for z in range(len(allTasks)):          print(z)          print(allTasks[z].taskName)    

Also, based on feedback I now understand that thisTask is a reference to an object, not a fresh copy of the result of get_task. To that end I have tried using copy.copy() and copy.deepcopy() on both Task.get_task(homeTasks[y]) and thisTask to no avail. It seems like even the copy is a reference. Is there another way to go about this?

EDIT 2: Here are the ways I've tried to use copy and deepcopy:

for y in range(len(homeTasks)):          print(y)          thisTask = copy.copy(Task.get_task(y))          allTasks.append(thisTask)          print(allTasks[y].taskName)  
for y in range(len(homeTasks)):          print(y)          thisTask = copy.deepcopy(Task.get_task(y))          allTasks.append(thisTask)          print(allTasks[y].taskName)  
for y in range(len(homeTasks)):          print(y)          thisTask = Task.get_task(y)          allTasks.append(copy.copy(thisTask))          print(allTasks[y].taskName)  
for y in range(len(homeTasks)):          print(y)          thisTask = Task.get_task(y)          allTasks.append(copy.deepcopy(thisTask))          print(allTasks[y].taskName)  

All 4 of these produced the exact same result:

0  Do Dishes  1  Make Bed  2  Laundry  3  Study  4  Laundry  5  Elliptical  6  Elliptical  7  Laundry  8  Elliptical  9  Elliptical  10  Elliptical  11  test  0  test  1  test  2  test  3  test  4  test  5  test  6  test  7  test  8  test  9  test  10  test  11  test  
https://stackoverflow.com/questions/66520720/adding-objects-created-by-a-classmethod-to-a-python-list-using-a-for-loop March 08, 2021 at 03:48AM

没有评论:

发表评论