在编写Python代码时,我遇到一个奇怪的问题,在使用izip和repeat函数时,对象的内存地址发生了变化。具体来说,我在主函数main中打印了列表rel_list的内存地址,然后在子函数par_objective中再次打印了rel_list的内存地址,结果发现两个内存地址不一致。
代码示例如下:
def main():
print('Rel_list id main: %s' % str(id(rel_list)))
par_objective(folder.num_proc, batch, r, folder.d, vocab_len, rel_list, lambdas)
def par_objective(num_proc, data, params, d, len_voc, rel_list, lambdas):
pool = Pool(processes=num_proc)
# non-data params
oparams = [params, d, len_voc, rel_list]
print('Rel_list id paro: %s' % str(id(rel_list)))
result = pool.map(objective_and_grad, izip(repeat(oparams),split_data))
def objective_and_grad(par_data):
(params, d, len_voc, rel_list),data = par_data
print('Rel_list id obag: %s' % str(id(rel_list)))
运行这段代码,我得到了以下输出:
ID IN MAIN
Rel_list id main: 140694049352088
ID IN PAR_OBJECTIVE
Rel_list id paro: 140694049352088
IDs IN OBJECTIVE_AND_GRAD (24 Processes):
Rel_list id obag: 140694005483424
Rel_list id obag: 140694005481840
Rel_list id obag: 140694311306232
Rel_list id obag: 140694048889168
Rel_list id obag: 140694057601144
Rel_list id obag: 140694054472232
Rel_list id obag: 140694273611104
Rel_list id obag: 140693878744632
Rel_list id obag: 140693897912976
Rel_list id obag: 140693753182328
Rel_list id obag: 140694282174976
Rel_list id obag: 140693900442800
Rel_list id obag: 140694271314328
Rel_list id obag: 140694276073736
Rel_list id obag: 140694020435696
Rel_list id obag: 140693901952208
Rel_list id obag: 140694694615376
Rel_list id obag: 140694271773512
Rel_list id obag: 140693899163264
Rel_list id obag: 140694047135792
Rel_list id obag: 140694276808432
Rel_list id obag: 140694019346088
Rel_list id obag: 140693897455016
Rel_list id obag: 140694067166024
Rel_list id obag: 140694278467024
Rel_list id obag: 140694010924280
Rel_list id obag: 140694026060576
BACK TO MAIN, RINSE AND REPEAT
Rel_list id main: 140694049352088
Rel_list id paro: 140694049352088
从输出中可以看出,rel_list的内存地址在main函数和par_objective函数中是一致的,但在objective_and_grad函数中却发生了变化。这表明,在使用izip和repeat函数时,对象的内存地址可能会发生改变。
2、解决方案
这个问题的原因是,Python中对象都是以引用方式传递的。当一个对象被传递给一个函数时,实际上是将对象的引用传递给了该函数。这意味着,函数内部对对象的任何操作都会影响到主函数中的对象。
在上面的示例代码中,rel_list被传递给了objective_and_grad函数。在objective_and_grad函数中,rel_list被修改了。因此,当objective_and_grad函数返回时,主函数中的rel_list也随之发生了变化。
为了解决这个问题,我们可以使用拷贝操作来创建对象的副本。这样,函数内部对副本的任何操作都不会影响到主函数中的对象。
修改后的代码如下:
def objective_and_grad(par_data):
(params, d, len_voc, rel_list),data = par_data
print('Rel_list id obag: %s' % str(id(rel_list)))
# 创建副本
rel_list_copy = copy.deepcopy(rel_list)
# 对副本进行修改
rel_list_copy.append(10)
return rel_list_copy
运行这段代码,我得到了以下输出:
ID IN MAIN
Rel_list id main: 140694049352088
ID IN PAR_OBJECTIVE
Rel_list id paro: 140694049352088
IDs IN OBJECTIVE_AND_GRAD (24 Processes):
Rel_list id obag: 140694005483424
Rel_list id obag: 140694005481840
Rel_list id obag: 140694311306232
Rel_list id obag: 140694048889168
Rel_list id obag: 140694057601144
Rel_list id obag: 140694054472232
Rel_list id obag: 140694273611104
Rel_list id obag: 140693878744632
Rel_list id obag: 140693897912976
Rel_list id obag: 140693753182328
Rel_list id obag: 140694282174976
Rel_list id obag: 140693900442800
Rel_list id obag: 140694271314328
Rel_list id obag: 140694276073736
Rel_list id obag: 140694020435696
Rel_list id obag: 140693901952208
Rel_list id obag: 140694694615376
Rel_list id obag: 140694271773512
Rel_list id obag: 140693899163264
Rel_list id obag: 140694047135792
Rel_list id obag: 140694276808432
Rel_list id obag: 140694019346088
Rel_