Python中使用pickle模块时变量地址改变问题

这是最近在使用pickle模块时发现的问题。将变量保存(dump)后再读取(load),读取后的变量地址会发生改变。具体例子如下:

# 保存和读取数字变量
x = 3.5
print("id of x before dump:",id(x))
with open('./x.pkl', 'wb') as f:
    pickle.dump(x, f)
with open('./x.pkl', 'rb') as f:
    x = pickle.load(f)
print("id of x  after load:",id(x))   

运行输出为:

id of x before dump: 2421413849584
id of  x  after  load: 2421413849128

这一性质对一般的变量使用影响不大。但在创建某个对象时,如果对象a的属性attr为另一个对象B(即a.attr = b),这时若对b执行pickle.dump()pickle.load()的操作,由于B的地址改变了,则A和B的所属关系也会消失。例子如下:

class A:
    def __init__(self, attr = None):
        self.attr = attr
class B:
    def __init__(self, value=2):
        self.value = value
a = A()
b = B()
a.attr = b
print("before dump:")
print("a.attr.value:",a.attr.value)
print("b.value:",b.value)

运行输出为

before dump:
a.attr.value: 2
b.value: 2

此时若改变b.value的值, a.attr.value的值也会相应改变:

#改变 b.value, 则a.attr.value也会相应改变
b.value = -1
print(b.value, a.attr.value)

运行输出为

-1 -1

现对ab执行pickle.dump()pickle.load():

a = A()
b = B()
a.attr = b
with open('./b.pkl', 'wb') as f:
    pickle.dump(b, f)
with open('./b.pkl', 'rb') as f:
    b = pickle.load(f)

再改变b.value的值,结果如下:

#改变 b.value, a.attr.value不变
b.value = -1
print(b.value, a.attr.value)

输出结果为

-1 2

由以上测试可以看出,此时a.attr已经不再指向b。事实上,如果我们此时查看两者的地址,可以发现地址已经改变。

print(id(b))
print(id(a.attr))

结果为:

2421439794872
2421439852784

我在自己的程序中用了a.attr = b的结构,在dumpload后出现了这样的bug. 花了很久才找到问题所在。在网上也没有找到专门强调这一问题的文章,因此记录下来,以后写程序的时候要注意。

你可能感兴趣的:(Python中使用pickle模块时变量地址改变问题)