了解 Python 中的酸洗

Posted

技术标签:

【中文标题】了解 Python 中的酸洗【英文标题】:Understanding Pickling in Python 【发布时间】:2011-11-22 01:12:18 【问题描述】:

我最近接到了一项任务,我需要将字典(其中每个键引用一个列表)以腌制形式放置。唯一的问题是我不知道腌制形式是什么。谁能指出一些好的资源的正确方向来帮助我学习这个概念?

【问题讨论】:

docs.python.org/library/pickle.html 是“泡菜”的第一个谷歌搜索结果,甚至超过了腌制蔬菜的***页面。 @Wooble:我知道它完全偏离主题,但 Google 搜索会因您的位置、搜索历史甚至电子邮件/聊天历史而异;)。但是,是的,+1 指向文档。 @0xc0de 对。对我来说,最高条目腌制蔬菜。 :-) 我想我应该开始更多地编码。 另见:How to use pickle to store / load data 【参考方案1】:

pickle 模块实现了一种基本但强大的算法,用于序列化和反序列化 Python 对象结构。

Pickling - 是将 Python 对象层次结构转换为字节流的过程,而 Unpickling - 是逆操作,将字节流转换回对象层次结构。

酸洗(和反酸洗)也称为序列化编组扁平化

import pickle

data1 = 'a': [1, 2.0, 3, 4+6j],
         'b': ('string', u'Unicode string'),
         'c': None

selfref_list = [1, 2, 3]
selfref_list.append(selfref_list)

output = open('data.pkl', 'wb')

# Pickle dictionary using protocol 0.
pickle.dump(data1, output)

# Pickle the list using the highest protocol available.
pickle.dump(selfref_list, output, -1)

output.close()

从腌制文件中读取 -

import pprint, pickle

pkl_file = open('data.pkl', 'rb')

data1 = pickle.load(pkl_file)
pprint.pprint(data1)

data2 = pickle.load(pkl_file)
pprint.pprint(data2)

pkl_file.close()

来源 - https://docs.python.org/2/library/pickle.html

【讨论】:

这只是我见过的最好的代码示例之一。格式精美,简洁明了。谢谢。 我不明白为什么data1 = pickle.load(pkl_file) 没有加载完整的文件(data.pkl)? 酸洗是否需要文件输出参数?您如何保留序列化对象以将其存储在其他地方? 对于使用 Python 3 的用户:pickle.dump(data1, output) 默认为 pickle.DEFAULT_PROTOCOL(撰写此评论时的协议 3)而不是协议 0。【参考方案2】:

Pickling 是一种迷你语言,可用于将相关状态从 python 对象转换为字符串,其中该字符串唯一地表示该对象。然后 (un)pickling 可用于将字符串转换为活动对象,方法是从创建字符串的保存状态“重建”对象。

>>> import pickle
>>> 
>>> class Foo(object):
...   y = 1
...   def __init__(self, x):
...     self.x = x
...     return
...   def bar(self, y):
...     return self.x + y
...   def baz(self, y):
...     Foo.y = y  
...     return self.bar(y)
... 
>>> f = Foo(2)
>>> f.baz(3)
5
>>> f.y
3
>>> pickle.dumps(f)
"ccopy_reg\n_reconstructor\np0\n(c__main__\nFoo\np1\nc__builtin__\nobject\np2\nNtp3\nRp4\n(dp5\nS'x'\np6\nI2\nsb."

您在这里可以看到,pickle 不保存类的源代码,但确实存储了对类定义的引用。基本上,你几乎可以阅读挑选出来的字符串……它说(粗略翻译)“调用 copy_reg 的重构器,其中参数是 __main__.Foo 定义的类,然后做其他事情”。另一件事是实例的保存状态。如果您看得更深,您可以提取“字符串 x”设置为“整数 2”(大致为:S'x'\np6\nI2)。这实际上是字典条目的腌制字符串的剪辑部分……dictf.__dict__,即'x': 2。如果您查看pickle 的源代码,它非常清楚地给出了从python 到腌制字节码的每种类型的对象和操作的翻译。

另请注意,酸洗语言有不同的变体。默认为协议 0,更易于阅读。还有协议 2,如下所示(以及 1,3 和 4,具体取决于您使用的 python 版本)。

>>> pickle.dumps([1,2,3])
'(lp0\nI1\naI2\naI3\na.'
>>> 
>>> pickle.dumps([1,2,3], -1)
'\x80\x02]q\x00(K\x01K\x02K\x03e.'

同样,它仍然是酸洗语言的方言,您可以看到协议 0 字符串表示“获取列表,包括 I1、I2、I3”,而协议 2 更难阅读,但表示相同事物。第一个位 \x80\x02 表示它是协议 2 - 然后你有 ] 它说它是一个列表,然后你可以再次看到整数 1,2,3 在那里。同样,检查 pickle 的源代码以查看 pickle 语言的确切映射。

要将酸洗反转为字符串,请使用 load/loads。

>>> p = pickle.dumps([1,2,3])
>>> pickle.loads(p)
[1, 2, 3]

【讨论】:

作为一个初学者,我脑子里一直在想这个问题,泡菜在里面有什么作用?这个答案比其他答案更能解决这个问题。【参考方案3】:

Pickling 只是序列化:将数据放入可以存储在文件中并在以后检索的表单中。以下是pickle 模块上的文档:

http://docs.python.org/release/2.7/library/pickle.html

【讨论】:

【参考方案4】:

http://docs.python.org/library/pickle.html#example

import pickle

data1 = 'a': [1, 2.0, 3, 4+6j],
         'b': ('string', u'Unicode string'),
         'c': None

selfref_list = [1, 2, 3]
selfref_list.append(selfref_list)

output = open('data.pkl', 'wb')

# Pickle dictionary using protocol 0.
pickle.dump(data1, output)

# Pickle the list using the highest protocol available.
pickle.dump(selfref_list, output, -1)

output.close()

【讨论】:

【参考方案5】:

Python 中的 Pickling 用于序列化和反序列化 Python 对象,例如您的字典。我通常使用cPickle 模块,因为它比Pickle 模块快得多。

import cPickle as pickle    

def serializeObject(pythonObj):
    return pickle.dumps(pythonObj, pickle.HIGHEST_PROTOCOL)

def deSerializeObject(pickledObj):
    return pickle.loads(pickledObj)

【讨论】:

Highest.protocol有什么用?【参考方案6】:

有时我们想保存对象以便以后检索它们(即使在生成数据的程序终止之后)。或者我们想将对象传输给我们应用程序之外的某人或其他东西。 Pickle module 用于对对象进行序列化和反序列化。

serializing object (Pickling): Create a representation of an object.
deserializing object (Unpickling): Re-load the object from representation.

dump: pickle to file
load: unpickle from file
dumps: returns a pickled representation. We can store it in a variable.
loads: unpickle from the supplied variable.

例子:

import pickle

print("Using dumps and loads to store it in variable")
list1 = [2, 4]
dict1 = 1: list1, 2: 'hello', 3: list1
pickle_dict = pickle.dumps(dict1)
print(pickle_dict)

dict2 = pickle.loads(pickle_dict)
print(dict2)

# obj1==obj2 => True
# obj1 is obj2 => False

print(id(dict1.get(1)), id(dict1.get(3)))
print(id(dict2.get(1)), id(dict2.get(3)))
print("*" * 100)
print("Using dump and load to store it in File ")

cars = ["Audi", "BMW", "Maruti 800", "Maruti Suzuki"]
file_name = "mycar.pkl"
fileobj = open(file_name, 'wb')
pickle.dump(cars, fileobj)
fileobj.close();

file_name = "mycar.pkl"
fileobj = open(file_name, 'rb')
mycar = pickle.load(fileobj)
print(mycar)

【讨论】:

【参考方案7】:

Pickling 允许您序列化和反序列化 Python 对象结构。简而言之,Pickling 是一种将 python 对象转换为字符流的方法,以便该字符流包含在另一个 python 脚本中重构对象所需的所有信息。

import pickle

def pickle_data():
    data = 
           'name': 'sanjay',
           'profession': 'Software Engineer',
           'country': 'India'
        
    filename = 'PersonalInfo'
    outfile = open(filename, 'wb')
    pickle.dump(data,outfile)
    outfile.close()

pickle_data()

【讨论】:

以上是关于了解 Python 中的酸洗的主要内容,如果未能解决你的问题,请参考以下文章

为啥带有酸洗的多处理序列化取决于范围?

如何在 Python 中解释 Dill 的酸洗跟踪输出? (分析(非)酸洗/(反)序列化瓶颈)

Python酸洗EOF问题

Python、cPickle、酸洗 lambda 函数

Python酸洗保持对象身份

Python 酸洗错误:TypeError:对象泡菜未返回列表。 numpy的问题?