这是最近在使用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
现对a
和b
执行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
的结构,在dump
和load
后出现了这样的bug. 花了很久才找到问题所在。在网上也没有找到专门强调这一问题的文章,因此记录下来,以后写程序的时候要注意。
网友评论