Python用for循环追加@classmethod生成对象到列表后全元素为最后一个的问题
问题本质
你的get_task方法从实现逻辑上就存在根本性错误:
- 类方法的第一个参数接收的是
Task类本身(按Python惯例应该命名为cls,写成self本身就容易造成逻辑误导) - 你在方法内直接给类对象挂载属性,最后
return self,意味着每次调用方法返回的都是同一个全局唯一的Task类对象 - 循环过程中对属性的修改,本质上是覆盖这个全局类对象的共享属性,不管你往列表里append多少次,所有列表项指向的都是同一个内存地址的类对象
- 你之前尝试的
copy.copy/copy.deepcopy全部无效的核心原因是:Python 中类是元类生成的单例对象,对类本身执行拷贝操作并不会生成新的独立对象,本质还是返回原类的引用。等你执行拷贝时,类对象的属性已经被最后一次循环覆盖成了"test",所有拷贝出来的引用自然全是错误值。
修复方案
修改get_task的返回逻辑,每次从数据库查完字段后,实例化一个全新的Task对象再返回,不要直接返回类本身。
对应你原本的数据库查询逻辑,正确的类实现参考:
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(cls, 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()] # 用查询到的字段值生成全新的Task实例返回 return cls( taskID=taskID, taskName=task[0]['taskName'], points=task[0]['points'], approved=task[0]['approved'], assignedUserID=task[0]['assignedUserID'], createdByUserID=task[0]['createdByUserID'], dateCreated=task[0]['dateCreated'], dateCompleted=task[0]['dateCompleted'], frequency=task[0]['frequency'] )
你写的最小可复现示例,修改后的get_task实现如下:
class Task(object): def __init__(self, taskID, taskName): self.taskID = taskID self.taskName = taskName @classmethod def get_task(cls, 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'] # 生成独立实例返回,不要直接修改类本身的属性 return cls( taskID=taskIDList[index], taskName=taskNames[index] )
修改完成后,每次循环拿到的都是内存独立的Task对象,列表元素之间不会共享引用,打印输出的结果就会符合预期。
注:原实现中存在拼写错误
self.aproved,实际对应字段为approved,可在修改时一并修正。
内容的提问来源于stack exchange,提问作者polymathica
相关产品推荐
相关产品推荐

