Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
1c329aab
Commit
1c329aab
authored
Apr 13, 2016
by
Wenzel Jakob
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
pickling support (fixes #144)
parent
505466ff
Hide whitespace changes
Inline
Side-by-side
Showing
8 changed files
with
164 additions
and
2 deletions
+164
-2
CMakeLists.txt
+1
-0
docs/advanced.rst
+72
-1
docs/changelog.rst
+3
-1
example/example.cpp
+2
-0
example/example15.cpp
+51
-0
example/example15.py
+21
-0
example/example15.ref
+2
-0
include/pybind11/pytypes.h
+12
-0
No files found.
CMakeLists.txt
View file @
1c329aab
...
...
@@ -120,6 +120,7 @@ set(PYBIND11_EXAMPLES
example/example12.cpp
example/example13.cpp
example/example14.cpp
example/example15.cpp
example/issues.cpp
)
...
...
docs/advanced.rst
View file @
1c329aab
...
...
@@ -841,7 +841,7 @@ objects (e.g. a NumPy matrix).
The file :file:`example/example7.cpp` contains a complete example that
demonstrates using the buffer protocol with pybind11 in more detail.
.. [#f1] http
s
://docs.python.org/3/c-api/buffer.html
.. [#f1] http://docs.python.org/3/c-api/buffer.html
NumPy support
=============
...
...
@@ -1184,3 +1184,74 @@ set of admissible operations.
The file :file:`example/example14.cpp` contains a complete example that
demonstrates how to create opaque types using pybind11 in more detail.
Pickling support
================
Python's ``pickle`` module provides a powerful facility to serialize and
de-serialize a Python object graph into a binary data stream. To pickle and
unpickle C++ classes using pybind11, two additional functions most be provided.
Suppose the class in question has the following signature:
.. code-block:: cpp
class Pickleable {
public:
Pickleable(const std::string &value) : m_value(value) { }
const std::string &value() const { return m_value; }
void setExtra(int extra) { m_extra = extra; }
int extra() const { return m_extra; }
private:
std::string m_value;
int m_extra = 0;
};
The binding code including the requisite ``__setstate__`` and ``__getstate__`` methods [#f2]_
looks as follows:
.. code-block:: cpp
py::class_<Pickleable>(m, "Pickleable")
.def(py::init<std::string>())
.def("value", &Pickleable::value)
.def("extra", &Pickleable::extra)
.def("setExtra", &Pickleable::setExtra)
.def("__getstate__", [](const Pickleable &p) {
/* Return a tuple that fully encodes the state of the object */
return py::make_tuple(p.value(), p.extra());
})
.def("__setstate__", [](Pickleable &p, py::tuple t) {
if (t.size() != 2)
throw std::runtime_error("Invalid state!");
/* Invoke the constructor (need to use in-place version) */
new (&p) Pickleable(t[0].cast<std::string>());
/* Assign any additional state */
p.setExtra(t[1].cast<int>());
});
An instance can now be pickled as follows:
.. code-block:: python
try:
import cPickle as pickle # Use cPickle on Python 2.7
except ImportError:
import pickle
p = Pickleable("test_value")
p.setExtra(15)
data = cPickle.dumps(p, -1)
Note that only the cPickle module is supported on Python 2.7. It is also
important to request usage of the highest protocol version using the ``-1``
argument to ``dumps``.
.. seealso::
The file :file:`example/example15.cpp` contains a complete example that
demonstrates how to pickle and unpickle types using pybind11 in more detail.
.. [#f2] http://docs.python.org/3/library/pickle.html#pickling-class-instances
docs/changelog.rst
View file @
1c329aab
...
...
@@ -5,8 +5,10 @@ Changelog
1.5 (not yet released)
----------------------
* Pickling support
* Added a variadic ``make_tuple()`` function
* Address a rare issue that could confuse the current virtual function dispatcher
* Documentation improvements: import issues, symbol visibility, limitations
* Documentation improvements: import issues, symbol visibility,
pickling,
limitations
1.4 (April 7, 2016)
--------------------------
...
...
example/example.cpp
View file @
1c329aab
...
...
@@ -23,6 +23,7 @@ void init_ex11(py::module &);
void
init_ex12
(
py
::
module
&
);
void
init_ex13
(
py
::
module
&
);
void
init_ex14
(
py
::
module
&
);
void
init_ex15
(
py
::
module
&
);
void
init_issues
(
py
::
module
&
);
PYBIND11_PLUGIN
(
example
)
{
...
...
@@ -42,6 +43,7 @@ PYBIND11_PLUGIN(example) {
init_ex12
(
m
);
init_ex13
(
m
);
init_ex14
(
m
);
init_ex15
(
m
);
init_issues
(
m
);
return
m
.
ptr
();
...
...
example/example15.cpp
0 → 100644
View file @
1c329aab
/*
example/example15.cpp -- pickle support
Copyright (c) 2015 Wenzel Jakob <wenzel@inf.ethz.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#include "example.h"
class
Pickleable
{
public
:
Pickleable
(
const
std
::
string
&
value
)
:
m_value
(
value
)
{
}
const
std
::
string
&
value
()
const
{
return
m_value
;
}
void
setExtra1
(
int
extra1
)
{
m_extra1
=
extra1
;
}
void
setExtra2
(
int
extra2
)
{
m_extra2
=
extra2
;
}
int
extra1
()
const
{
return
m_extra1
;
}
int
extra2
()
const
{
return
m_extra2
;
}
private
:
std
::
string
m_value
;
int
m_extra1
=
0
;
int
m_extra2
=
0
;
};
void
init_ex15
(
py
::
module
&
m
)
{
py
::
class_
<
Pickleable
>
(
m
,
"Pickleable"
)
.
def
(
py
::
init
<
std
::
string
>
())
.
def
(
"value"
,
&
Pickleable
::
value
)
.
def
(
"extra1"
,
&
Pickleable
::
extra1
)
.
def
(
"extra2"
,
&
Pickleable
::
extra2
)
.
def
(
"setExtra1"
,
&
Pickleable
::
setExtra1
)
.
def
(
"setExtra2"
,
&
Pickleable
::
setExtra2
)
// For details on the methods below, refer to
// http://docs.python.org/3/library/pickle.html#pickling-class-instances
.
def
(
"__getstate__"
,
[](
const
Pickleable
&
p
)
{
/* Return a tuple that fully encodes the state of the object */
return
py
::
make_tuple
(
p
.
value
(),
p
.
extra1
(),
p
.
extra2
());
})
.
def
(
"__setstate__"
,
[](
Pickleable
&
p
,
py
::
tuple
t
)
{
if
(
t
.
size
()
!=
3
)
throw
std
::
runtime_error
(
"Invalid state!"
);
/* Invoke the constructor (need to use in-place version) */
new
(
&
p
)
Pickleable
(
t
[
0
].
cast
<
std
::
string
>
());
/* Assign any additional state */
p
.
setExtra1
(
t
[
1
].
cast
<
int
>
());
p
.
setExtra2
(
t
[
2
].
cast
<
int
>
());
});
}
example/example15.py
0 → 100644
View file @
1c329aab
from
__future__
import
print_function
import
sys
sys
.
path
.
append
(
'.'
)
from
example
import
Pickleable
try
:
import
cPickle
as
pickle
# Use cPickle on Python 2.7
except
ImportError
:
import
pickle
p
=
Pickleable
(
"test_value"
)
p
.
setExtra1
(
15
)
p
.
setExtra2
(
48
)
data
=
pickle
.
dumps
(
p
,
-
1
)
# -1 is important (use highest protocol version)
print
(
"
%
s
%
i
%
i"
%
(
p
.
value
(),
p
.
extra1
(),
p
.
extra2
()))
p2
=
pickle
.
loads
(
data
)
print
(
"
%
s
%
i
%
i"
%
(
p2
.
value
(),
p2
.
extra1
(),
p2
.
extra2
()))
example/example15.ref
0 → 100644
View file @
1c329aab
test_value 15 48
test_value 15 48
include/pybind11/pytypes.h
View file @
1c329aab
...
...
@@ -142,6 +142,8 @@ public:
return
result
;
}
template
<
typename
T
>
inline
T
cast
()
const
{
return
operator
object
().
cast
<
T
>
();
}
operator
bool
()
const
{
if
(
attr
)
{
return
(
bool
)
PyObject_HasAttr
(
obj
.
ptr
(),
key
.
ptr
());
...
...
@@ -161,18 +163,23 @@ private:
struct
list_accessor
{
public
:
list_accessor
(
handle
list
,
size_t
index
)
:
list
(
list
),
index
(
index
)
{
}
void
operator
=
(
list_accessor
o
)
{
return
operator
=
(
object
(
o
));
}
void
operator
=
(
const
handle
&
o
)
{
// PyList_SetItem steals a reference to 'o'
if
(
PyList_SetItem
(
list
.
ptr
(),
(
ssize_t
)
index
,
o
.
inc_ref
().
ptr
())
<
0
)
pybind11_fail
(
"Unable to assign value in Python list!"
);
}
operator
object
()
const
{
PyObject
*
result
=
PyList_GetItem
(
list
.
ptr
(),
(
ssize_t
)
index
);
if
(
!
result
)
pybind11_fail
(
"Unable to retrieve value from Python list!"
);
return
object
(
result
,
true
);
}
template
<
typename
T
>
inline
T
cast
()
const
{
return
operator
object
().
cast
<
T
>
();
}
private
:
handle
list
;
size_t
index
;
...
...
@@ -181,18 +188,23 @@ private:
struct
tuple_accessor
{
public
:
tuple_accessor
(
handle
tuple
,
size_t
index
)
:
tuple
(
tuple
),
index
(
index
)
{
}
void
operator
=
(
tuple_accessor
o
)
{
return
operator
=
(
object
(
o
));
}
void
operator
=
(
const
handle
&
o
)
{
// PyTuple_SetItem steals a referenceto 'o'
if
(
PyTuple_SetItem
(
tuple
.
ptr
(),
(
ssize_t
)
index
,
o
.
inc_ref
().
ptr
())
<
0
)
pybind11_fail
(
"Unable to assign value in Python tuple!"
);
}
operator
object
()
const
{
PyObject
*
result
=
PyTuple_GetItem
(
tuple
.
ptr
(),
(
ssize_t
)
index
);
if
(
!
result
)
pybind11_fail
(
"Unable to retrieve value from Python tuple!"
);
return
object
(
result
,
true
);
}
template
<
typename
T
>
inline
T
cast
()
const
{
return
operator
object
().
cast
<
T
>
();
}
private
:
handle
tuple
;
size_t
index
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment