【问题标题】:Trouble with copying dictionaries and using deepcopy on an SQLAlchemy ORM object复制字典和在 SQLAlchemy ORM 对象上使用 deepcopy 的问题
【发布时间】:2011-02-27 13:35:33
【问题描述】:

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

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

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
  • 从所有学生中,选择随机数量的学生并粘贴在一个列表中
  • 剥离(DEALLOCATE)他们的项目 ++ 反映项目(allocated 参数现在是 False)和讲师的更改(如果他们的一个或多个项目不再分配,则释放空位)
  • 随机化该列表
  • 再次尝试分配 (REALLOCATE) 该列表项目中的每个人
  • 计算权重(将排名相加,排名 1 = 1,排名 2 = 2...,没有项目排名 = 101)
  • 对于这个新的分配aNew,如果权重wNew小于我一开始拾取的分配权重wOld,那么这就是best_node(由上面的Simulated Annealing算法定义) )。将算法应用于 aNew 并继续。
  • 如果是wOld &lt; wNew,则再次将算法应用于aOld 并继续。

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

现在,我只能执行此算法一次,但我需要尝试一个数字 N(在维基百科 sn-p 中由 kmax 表示)并确保我始终拥有前一个 @ 987654339@ 和best_node

为了不修改我原来的字典(我可能想重置),我做了字典的浅拷贝。从我在文档中阅读的内容来看,它似乎只复制了引用,并且由于我的字典包含对象,因此更改复制的字典最终会更改对象。所以我尝试使用copy.deepcopy()。这些字典引用了已经用 SQLA 映射的对象。


Questions:

我已经为所面临的问题提供了一些解决方案,但由于我对使用 Python 非常熟悉,它们对我来说听起来都相当神秘。

  1. Deepcopy 不能很好地与 SQLA 配合使用。有人告诉我,ORM 对象上的深拷贝可能存在阻止它按预期工作的问题。显然,我最好“构建复制构造函数,即 def copy(self): return FooBar(....)”。 谁能解释一下这是什么意思?

  2. 我检查并发现 deepcopy 存在问题,因为 SQLAlchemy 在您的对象上放置了额外的信息,即 _sa_instance_state 属性,我不希望在副本中但对于对象来说这是必需的.有人告诉我:“有一些方法可以手动清除旧的 _sa_instance_state 并在对象上放置一个新对象,但最直接的方法是使用 __init__() 创建一个新对象并设置重要的属性,而不是做一个完整的深拷贝。” 这到底是什么意思?我是否要创建一个新的、未映射的类,类似于旧的映射类?

  3. 另一种解决方案是,我必须“在您的对象上实现 __deepcopy__() 并确保设置了新的 _sa_instance_state,sqlalchemy.orm.attributes 中有一些函数可以帮助解决这个问题。” 这又一次超出了我的理解范围,所以有人可以解释一下这是什么意思吗?

  4. 一个更一般的问题:鉴于上述信息,是否有任何关于如何维护 best_node(必须始终通过我的 while 循环)和 previous_node 的信息/状态的建议,如果我的实际对象(由字典引用,因此是节点)由于发生释放/重新分配而发生变化?也就是不使用copy?

【问题讨论】:

    标签: python sqlalchemy deep-copy simulated-annealing


    【解决方案1】:

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

    首先像这样创建你的会话:

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

    这样它将是事务性的。事务的工作方式是sess.commit() 将使您的更改永久化,而sess.rollback() 将恢复它们。

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

    【讨论】:

    • 这看起来很有趣。 sess.rollback() 恢复为什么?原来的还是以前的状态?此外,这意味着我实际上不必更改我的任何课程吗?只是我提交它们的地方发生了变化吗?
    • sess.rollback() 将恢复到上次调用 sess.commit() 时的状态。您的字典不是 SQLAlchemy 对象,因此它们不会被还原。你必须自己处理这些。除此之外,您不需要任何额外的更改。
    • 它并没有显着改变任何东西,但 rollback() 能力非常有用,因为我正在从“状态”跳到“状态”。
    【解决方案2】:

    您不想像那样复制 sqlalchemy 对象。您可以实现自己的方法来轻松制作副本,但这可能不是您想要的。您不希望数据库中的学生和项目的副本是吗?所以不要复制这些数据。

    所以你有一个字典来保存你的分配。在此过程中,您永远不应修改 SQLAlchemy 对象。所有可以修改的信息都应该存储在这些字典中。如果您需要修改对象以考虑到这一点,请在最后复制数据。

    【讨论】:

    • @Winston:我希望我可以实现自己的方法来简化复制,但我几乎没时间了,而且仍然是 Python 编程(以及一般编程)的初学者,所以这似乎是一个在这个时候有点令人生畏:)。是的,我有一个保存分配的字典——我只向它添加行,然后从不触摸它,除了查询信息。我正在为模拟退火更改 studentprojectlecturers 字典。
    • [续] 到目前为止,SQLAlchemy 并没有真正抱怨,尽管我正在做的是——根据对我的问题的回答——错误(在将映射对象添加到会话后更改它)。我的主要问题是我需要使用deepcopy 的概念,但不能。我映射Student 等的原因是因为我必须保持我的分配映射非常简单。因此,分配中的学生 id 是学生映射表的外键(因此我可以在需要时查询有关学生的信息)。这有点疯狂:)
    • @Winston:既然你提到了,我才想起我有一个叫resetSPL()的函数,它基本上重置了学生、项目和讲师的属性……我应该不 我应该这样做吗?
    • 不,基本上在进行模拟退火之类的算法时,您真的不应该使用 sqlalchemy。 SQLAlchemy 用于持久性,这不是您想要的。你对它的使用和它的预期用途太不同了:你只会头疼。
    • SQLA 非常适合我的 Monte-Carlo 模拟,因为我不断将所有内容添加到数据库中,然后将其用于计算——我想这是我最需要持久性的地方。此外,我想将所有模拟存储到数据库中以供以后参考...但是我需要生成一个对每次模拟运行都是唯一的密钥... sigh
    猜你喜欢
    • 1970-01-01
    • 2017-02-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-20
    相关资源
    最近更新 更多