PickleʇPython攜ԏ㐲P믣賥rialization㩄㿩㬍 Ҳㆎ갥rsistencearshalling㬻⦬atteningᣍ
It is often necessary to save and restore the contents of an object to a file. One approach to this problem is to write a pair of functions that read and write data from a file in a special format. A powerful alternative approach is to use Python's pickle module. Exploiting Python's ability for introspection, the pickle module recursively converts nearly arbitrary Python objects into a stream of bytes that can be written to a file.
㐨Ҫᣴ涔ϳ億ڈݵ펄쾺ͻָ䶔ϳᣍ 渃Ί̢儷֮һʇ㬐䒻收P享ʽ㬒Ԍ؊⸱ʽ䓎ļȡꍐ䈫ʽ㍊ mһ֖Ӑ罷芇ʹӃPython儰ickleģ視㍊ ;ӃPython儷䊡Ĝf㬍 pickleģ冀ݹ鵘ת뻼躵ȎҢ儐ython攏㣬 䗪뻎꿉Ҕȫ΄쾵ėֽځ硣
The Boost Python Library supports the pickle module through the interface as described in detail in the Python Library Reference for pickle. This interface involves the special methods __getinitargs__, __getstate__ and __setstate__ as described in the following. Note that Boost.Python is also fully compatible with Python's cPickle module.
Boost Python ͨ齔ڼa href="http://www.python.org/doc/current/lib/module-pickle.html" >Python Library Reference for pickle Ϫϸeʶ儽ӿږ糖pickleģ視㍊ 能ӿڰ쀨̘ʢ罷荊__getinitargs__ᢍ __getstate__ꍼtt>__setstate__㬍 eʶȧςᣍ עҢBoost.Python빍ꈫ즈ݐython廣Pickleģ視㍊
ԚӃ맲ɏ㬂oost.Python pickle퓿ڰ쀨Ƚ趌؊ⷽ穌ꍊ
層oost.Python)չ 儊啥Ựickleʱ㬍 pickler⢊ԸE啥ӐuӐ__getinitargs__罷衣 胸ᘐ뷵똒븶PythonԪש㨊鈴boost::python::tuple罱㣩ᣍ 屆啥Ӊunpickler떸䊱㬸Oꗩ億ڈݓ×瀠儹錟ꯊ⎊
If __getinitargs__ is not defined, pickle.load will call the constructor (__init__) without arguments; i.e., the object must be default-constructible.
ȧ黼tt>__getinitargs__δ樒壬 pickle.load瓃Ξ⎊鷫캯ʽ㨼tt>__init__㩣덊 촸oԏ㱘ኡ鷫졣
層oost.Python)չ 儊啥Ựickleʱ㬍 pickler⢊ԸE啥ӐuӐ__getstate__罷衣 胸Ӧ絻ر튾ʵ=״̬儐ython攏㡣
層oost.Python)չ 儊啥Ӊunpickler떸䊱㨼tt>pickle.load㩣썊 ˼ʗψҔ__getinitargs__儽ṻΪ⎊鷫죨컉ϣ顣 ˦공npickler⢊ԐμĊ啥ӐuӐ__setstate__罷衣 ȧӐ㬾͒Լtt>__getstate__儽ṻ㨐ython攏㣩Ϊ⎊巔o÷ᣍ
ɏʶȽ趌؊ⷽ稿ɓɓu紎懟tt>.def()ᣍ Boost.Python ͨ齼strong>boost::python::pickle_suite ̡驁˒븶җӚʹӃ儸潓썊ͬʱҲ쓇һւ㺍 __getstate__ꍼtt>__setstate__ ᘐ볉收蒥ᣍ ς=ѝʾK能ӿڵĊ鈴ᣍ
boost/libs/python/testӐȽ趎ļϔʾKȧꎌṩpickle֧㖡㍊
脹햐儃++ ԍ蹽ϲ鷫캯ʽ䫵݊ʵᵄ⎊퍪ȫ떸䡣 Ҳ䋣싼樒尪ckle퓿ڷ__getinitargs__㹻Kᣍ բʇഒԏ·튽迤ģꍊ
樒惡+ pickleꯊ
struct world_pickle_suite : boost::python::pickle_suite
{
static
boost::python::tuple
getinitargs(world const& w)
{
return boost::python::make_tuple(w.get_country());
}
};
thon裺
class_<world>("world", args<const std::string&>())
// ...
.def_pickle(world_pickle_suite())
// ...
ᾀ햐儃++ ꬓЈκι錟꯶쎞稻ָ䵄㉔ኽ㍊ Ҳ䋣쓐ᘒꌡ駝tt>__getstate__/__setstate__ pickle퓿ڷ攣ꍊ
樒惡+ pickleꯊ
struct world_pickle_suite : boost::python::pickle_suite
{
static
boost::python::tuple
getinitargs(const world& w)
{
// ...
}
static
boost::python::tuple
getstate(const world& w)
{
// ...
}
static
void
setstate(world& w, boost::python::tuple state)
{
// ...
}
};
Ϊջ足uitethon裺
class_<world>("world", args<const std::string&>())
// ...
.def_pickle(world_pickle_suite())
// ...
For simplicity, the __dict__ is not included in the result of __getstate__. This is not generally recommended, but a valid approach if it is anticipated that the object's __dict__ will always be empty. Note that the safety guard described below will catch the cases where this assumption is violated.
Ϊ첵冰컣켴t>__getstate__儽ṻuӐༀ輴t>__dict__ᣍ һࣲ덆축6㬍 嫈繻Ԥƚ攏㵄__dict__܊ǎ꿕㬍 բȔʇһ趓組ଷ裬 עҢȧ黎巴왉裬ςʶ儰∫瀷洫ʩ旽彸C鿶ᣍ
ᾀ퀠ˆӚpickle2.cppᣍ 膠ԏ㵄__dict__Ự쀨Ԛ__getstate__儽ṻᣍ բҪ栒뵣亂룬嫈繻膠ԏ㵄__dict__⢷Ǘ܊ǿյģ썊 բʇɱ܃ⵄᣍ
ɏʶ儰ickleҩӐ趖ؒ굄ϝڥ㬍 Boost.Python)չģ冀ėӃ맿Ʉܲ떪倣ꍊ
__getstate__ is defined and the instance's __dict__ is not empty.
樒偋__getstate__㬲⇒ʵ=儼tt>__dict__⻎꿕ᣍ
The author of a Boost.Python extension class might provide a __getstate__ method without considering the possibilities that:
Boost.Python)չ 儗畟ܻጡ駝tt>__getstate__罷裬 慎듐〞ǒԏ¿Ʉܐԣꍊ
˻儀ԚPythonӃ빀ࡣ ΪKսȷ떸䅉ɺ 儊啥㬍 ꜓Ʉܐ蒪pickle胊啥儼tt>__dict__ᣍ
Ӄ맖ὓϲʵ=儼tt>__dict__Զ̭ϮĿᣍ ͬѹҪpickleʵ=儼tt>__dict__ᣍ
To alert the user to this highly unobvious problem, a safety guard is provided. If __getstate__ is defined and the instance's __dict__ is not empty, Boost.Python tests if the class has an attribute __getstate_manages_dict__. An exception is raised if this attribute is not defined:
Ϊ̡Ӄ맕▖쫲냷ϔ載ʌ⣬Boost.Python̡驁˰∫瀷洫ʩᣍ ȧ黶蒥K__getstate__㬲⇒ʵ=儼tt>__dict__燿գ썊 Boost.Python⊔脹ӐuӐ__getstate_manages_dict__ʴᣍ ȧ黸E䐔δ樒壬Բҽ崟쳣㺍
RuntimeError: Incomplete pickle support (__getstate_manages_dict__ not set)
To resolve this problem, it should first be established that the
__getstate__ and __setstate__ methods manage the
instances's __dict__ correctly. Note that this can be done
either at the C++ or the Python level. Finally, the safety guard
should intentionally be overridden. E.g. in C++ (from
pickle3.cpp):
Ϊ渃Ί̢㬓渃ʗψȷ樍 __getstate__ꍼtt>__setstate__罷荊 սȷ需튵=儼tt>__dict__ᣍ עҢ㬕⼈Ԕڃ++ҲԔڐython⣴Η浽ᣍ 곣찲ȫ瀷洫ʩӦ胓ⵘ⸇ᣍ =ȧ㬔ڃ++㨀䗔 pickle3.cpp㩣ꍊ
struct world_pickle_suite : boost::python::pickle_suite
{
// ...
static bool getstate_manages_dict() { return true; }
};
Alternatively in Python:
범ڐython㺍
import your_bpl_module
class your_class(your_bpl_module.your_class):
__getstate_manages_dict__ = 1
def __getstate__(self):
# your code here
def __setstate__(self, state):
# your code here
Ԛ)չ 儂oost.Python)չģ節썊 Ϊ˹Ӑ ̡驍ꕻ儰ickle֧㖽늇֘䳵Ŀꏺᣍ ͨ㣣썪ջ儰ickle֧㖓渃ꗮ֕롱방ckle儀久 ʵϖᣍ
ȧ黊啥Ҳԍ蹽__getinitargs__儷튽֘Ђ鷫죬 ᜃ⊹Ӄ__getstate__ᣍ բԶﱜ憎ϊ淨ϝڥᣍ
ȧ黑ꇳ__getstate__㬍 Ԛ絻صĐython攏㖐ༀ芵=儼tt>__dict__ᣍ
pickle4.cpp=דѝʾKһ֖ʵϖpickle儌洺켊塣 ʗψ㬎҃Ǎ蹽class_::enable_pickling() ָʾBoost.Pythonֻ樒尪ckleҪdz儻鱾ʴ㺍
class_<world>("world", args<const std::string&>())
// ...
.enable_pickling()
// ...
This enables the standard Python pickle interface as described
in the Python documentation. By "injecting" a
__getinitargs__ method into the definition of the wrapped
class we make all instances pickleable:
բ惘䁋Python΄碴Ѓ芶儱ꗼPythonpickle퓿ڡ㍊ ͨ齏ⱻ碗 攜蒥ᰗ∫ᱼtt>__getinitargs__罷裬 ΒCʹ˹Ӑʵ=漿ɰickle㺍
# import the wrapped world class
from pickle4_ext import world
# definition of __getinitargs__
def world_getinitargs(self):
return (self.get_country(),)
# now inject __getinitargs__ (Python is a dynamic language!)
world.__getinitargs__ = world_getinitargs
See also the
tutorial section on injecting additional methods from Python.
闠ڴӐythonעȫ軾ӷ㬒⿉컍 tutorial sectionᣍ
Updated: Feb 2004.