在SQLAlchemy ORM obj上复制字典和使用deepcopy时出现问题

2024-09-27 21:34:06 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在做一个模拟退火算法来优化给定的学生和项目分配。在

这是来自维基百科的语言无关的伪代码:

s ← s0; e ← E(s)                                // Initial state, energy.
sbest ← s; ebest ← e                            // Initial "best" solution
k ← 0                                           // Energy evaluation count.
while k < kmax and e > emax                     // While time left & not good enough:
  snew ← neighbour(s)                           // Pick some neighbour.
  enew ← E(snew)                                // Compute its energy.
  if enew < ebest then                          // Is this a new best?
    sbest ← snew; ebest ← enew                  // Save 'new neighbour' to 'best found'.
  if P(e, enew, temp(k/kmax)) > random() then   // Should we move to it?
    s ← snew; e ← enew                          // Yes, change state.
  k ← k + 1                                     // One more evaluation done
return sbest                                    // Return the best solution found.

以下是对该技术的改编。我的主管说理论上这个主意不错。在

首先,我从整个随机分配集合中获取一些分配(即学生及其分配项目的整个字典,包括项目的排名),复制并传递给我的函数。让我们把这个分配称为aOld(它是一个字典)。aOld有一个与之相关的权重,称为wOld。权重如下所述。在

该函数执行以下操作:

  • 让这个分配,aOld就是best_node
  • 从所有的学生中,随机抽取几个学生,然后把它们列在一个列表中
  • 剥离(释放)他们的项目++反映项目(allocated参数现在是False)和讲师(如果他们的一个或多个项目不再分配,则释放插槽)
  • 把名单随机化
  • 再次尝试分配(重新分配)该列表项目中的所有人
  • 计算权重(将等级相加,等级1=1,等级2=2。。。无项目等级=101)
  • 对于这个新的分配aNew,如果权重wNew小于我在开始时选择的分配权重wOld,那么这就是best_node(由上面的Simulated Annealing算法定义)。将算法应用于aNew,然后继续。在
  • 如果wOld < wNew,则将该算法再次应用于aOld,然后继续。在

分配/数据点表示为“节点”,这样node = (weight, allocation_dict, projects_dict, lecturers_dict)

现在,我只能执行这个算法一次,但是我需要尝试一个数字N(在Wikipedia代码片段中用kmax表示),并确保我总是随身携带上一个node和{}。在

为了不修改我原来的字典(我可能想重新设置),我对字典做了一个浅拷贝。从我在文档中读到的内容来看,它似乎只复制了引用,而且由于我的词典包含对象,所以无论如何,更改复制的词典最终都会更改对象。所以我尝试使用copy.deepcopy(),这些字典引用的是用SQLA映射的对象。在


Questions:

我已经得到了一些解决所面临的问题的方法,但由于我对Python的无知,它们对我来说听起来都相当神秘。在

  1. Deepcopy不能很好地使用SQLA。有人告诉我,ORM对象上的deepcopy可能存在一些问题,使它无法像您预期的那样工作。显然,我最好是“构建复制构造函数,即defcopy(self):returnfoobar(…..)”有人能解释一下这是什么意思吗?

  2. 我检查后发现deepcopy有问题,因为SQLAlchemy在您的对象上放置了额外的信息,即_sa_instance_state属性,我不想在副本中出现,但对于对象来说是必需的。有人告诉我:“有很多方法可以手动删除旧的_sa_instance_state并在对象上放置一个新的,但最简单的方法是用__init__()创建一个新的对象,并设置重要的属性,而不是进行完全的深度复制。”这到底意味着什么?我是否要创建一个新的、未映射的类类似于旧的已映射类?

  3. 另一种解决方案是,我必须在您的对象上“实现__deepcopy__()”,并确保设置了一个新的实例状态,其中包含sqlalchemy.orm.attributes这对我来说很有帮助。“这又一次超出了我的能力,所以有人能解释一下这意味着什么吗?

  4. 一个更一般的问题:对于上面的信息,有没有关于如何维护best_node(必须始终在while循环中保持)和previous_node(如果我的实际对象是被字典引用,因此节点)因释放/重新分配而发生变化?也就是说,不用拷贝?


Tags: 项目对象算法node字典学生权重best
2条回答

你不想像那样复制sqlalchemy对象。您可以实现自己的方法,这些方法可以很容易地生成副本,但这可能不是您想要的。你不想在你的数据库里有学生和项目的副本吗?所以不要复制这些数据。在

所以你有一个字典来保存你的分配。在此过程中,不应修改SQLAlchemy对象。所有可以修改的信息都应该存储在这些字典中。如果需要修改对象以将其考虑在内,请在末尾将数据复制回。在

我有另一个可能的解决方案:使用事务。这可能仍然不是最好的解决方案,但实现它应该更快。在

首先创建这样的会话:

# transactional session
Session = sessionmaker(transactional=True)
sess = Session()

那样的话,它将是事务性的。事务的工作方式是sess.commit()将使您的更改永久化,而{}将还原这些更改。在

在模拟退火的情况下,您希望在找到新的最佳解决方案时提交。以后,您可以调用rollback()将状态恢复到该位置。在

相关问题 更多 >

    热门问题