Python 复制字典和在SQLAlchemy ORM对象上使用deepcopy时出现问题
我正在做一个模拟退火算法来优化给定的学生和项目分配 这是来自维基百科的语言不可知伪代码:Python 复制字典和在SQLAlchemy ORM对象上使用deepcopy时出现问题,python,sqlalchemy,deep-copy,simulated-annealing,Python,Sqlalchemy,Deep Copy,Simulated Annealing,我正在做一个模拟退火算法来优化给定的学生和项目分配 这是来自维基百科的语言不可知伪代码: s ← s0; e ← E(s) // Initial state, energy. sbest ← s; ebest ← e // Initial "best" solution k ← 0 // Energ
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.
s← s0;E← E(s)//初始状态,能量。
斯贝斯特← s埃伯斯特← e//初始“最佳”解决方案
K← 0//能量评估计数。
当kemax//当时间还剩&不够好时:
冷嘲热讽← 邻居///挑选一些邻居。
新能源← E(snew)//计算它的能量。
如果enewrandom(),那么//我们应该转向它吗?
s← snew;E← enew//是,更改状态。
K← k+1//再进行一次评估
return sbest//返回找到的最佳解决方案。
以下是对该技术的改编。我的主管说这个想法在理论上是好的
首先,我从一整套随机分配中选取一些分配(即学生及其分配项目的整个字典,包括项目的排名),复制并传递给我的函数。让我们把这个分配称为aOld(它是一个字典)aOld
有一个与之相关的权重,称为wOld
。权重如下所述
该函数执行以下操作:
- 让此分配,
成为aOld
最佳节点
- 从所有学生中,随机挑选一些学生,并将其粘贴在列表中
- 剥离(取消分配)他们的项目++反映项目(
参数现在为已分配
)和讲师(如果一个或多个项目不再分配,则释放插槽)False
- 将该列表随机化
- 再次尝试分配(重新分配)该列表中的每个项目
- 计算权重(将等级相加,等级1=1,等级2=2…无项目等级=101)
- 对于这个新的分配
,如果权重重新
小于我在开始时拾取的分配权重wNew
,那么这就是wOld
(由上面的最佳节点
模拟退火算法定义)。将算法重新应用于
并继续,
- 如果
,则再次将算法应用于wOld
,然后继续aOld
节点=(权重、分配、项目、讲师)
现在,我只能执行此算法一次,但我需要尝试一个数字N(在维基百科代码片段中用kmax
表示),并确保我始终随身携带上一个节点和最佳节点
为了不修改我的原始词典(我可能想重置为),我对词典做了一个浅拷贝。从我在文档中读到的内容来看,它似乎只复制引用,而且因为我的字典包含对象,所以更改复制的字典最终还是会更改对象。因此,我尝试使用copy.deepcopy()
。这些字典引用了已经用SQLA映射的对象
问题:
我已经得到了一些解决所面临问题的方法,但由于我对使用Python非常熟悉,它们对我来说都相当神秘
Deepcopy不能很好地使用SQLA。有人告诉我,ORM对象上的DeepCopy可能存在一些问题,使其无法按预期工作。显然,我最好使用“构建副本构造函数,即def copy(self):return FooBar(…)”。有人能解释一下这是什么意思吗
我检查并发现deepcopy
存在问题,因为SQLAlchemy在对象上放置了额外的信息,即\u sa\u instance\u state
属性,我不希望在副本中包含该属性,但该属性是对象必须具备的。有人告诉我:“有很多方法可以手动清除旧的\u sa\u instance\u state
并在对象上放置一个新的状态,但最简单的方法是使用\u init\u()
创建一个新对象并设置重要的属性,而不是进行完整的深度复制。”这到底意味着什么?我是否创建了一个新的未映射类,类似于旧的映射类
另一种解决方案是,我必须“在您的对象上实现\uuu deepcopy\uuuuu()
,并确保设置了一个新的\u sa\u实例\u状态,sqlalchemy.orm.attributes中有一些函数可以帮助实现这一点。”这再一次超出了我的理解范围,所以有人可以解释一下它的含义吗
一个更一般的问题:鉴于上述信息,如果我的实际对象(由字典引用,因此是节点),我有没有建议如何维护最佳节点
(必须始终通过while循环保持)和上一个节点
的信息/状态是否因发生解除分配/重新分配而发生变化?也就是说,不使用复制
您不希望像那样复制sqlalchemy对象。您可以实现自己的方法,这些方法可以很容易地创建副本,但这可能不是您想要的。你不想在数据库中保存学生和项目的副本,是吗?所以不要复制这些数据
因此,您有一本保存分配的词典。在此过程中,永远不要修改SQLAlchemy对象。所有可以修改的信息都应存储在这些词典中。如果你
# transactional session
Session = sessionmaker(transactional=True)
sess = Session()