I have the following code in C++:
class Person
{
public:
enum Gender {Male, Female};
Gender GetGender() const;
}
I wrapped it in boost::python in this way:
BOOST_PYTHON_MODULE(TestPython)
{
scope the_scope = class_<Person>("Person")
.def("GetGender", &Person::GetGender);
enum_<Person::Gender>("Gender")
.value(Male, Person::Male)
.value(Female, Person::Female)
.export_values();
}
When I try to call person.GetGender()
from Python I get the following exception:
Can't pickle : attribute lookup **PyBF.TestPython.Gender**. It guesses the namespace of the Gender (which is actually **PyBF.TestPython.Person.Gender**) enum return type incorrectly.
How can I tell the GetGender
function what type to return explicitly?
Since we do not have the code that produces the error, I assume it occurs when you try to pickle a Person object.
Your problem is not specifically related to the usage of boost. It lies in cPickle module. It has problem pickling object with nested classes. See this answer for an explanation. Here's a simple code example that produces the error:
import cPickle
class MyOuterClass(object):
class MyInnerClass(object):
pass
def __init__(self):
self.my_inner_class = self.MyInnerClass()
def pickle_error():
print "Pickling ..."
my_outer_class = MyOuterClass()
print cPickle.dumps(my_outer_class)
if __name__ == "__main__":
pickle_error()
Running it produces this output:
Pickling ...
Traceback (most recent call last):
File "pickle.py", line 18, in <module>
pickle_error()
File "pickle.py", line 15, in pickle_error
print cPickle.dumps(my_outer_class)
cPickle.PicklingError: Can't pickle <class '__main__.MyInnerClass'>:
attribute lookup __main__.MyInnerClass failed
As mentioned in the linked answer, when cPickle asks inner class for its name it returns '__main__.MyInnerClass'
. However, this name can't be found in module's namespace, hence you get the exception.
Now you experience this because since there isn't something similar to an enum type in python, boost create an object to represent it. The enum_ construct declares a class in the current scope. By capturing the class scope, you end up creating a nested class within Person and you get the pickle error mentioned above.
There's a couple of solutions to your problem.
The simplest would be to declare the enum outside of Person's scope. You may not want to expose a Person's related enum besides it for code organization. You could then declare the Person class in a sub module so your enum is somewhat declared close to your class without being too public.
You could also take a look at boost's pickle support. However I haven't tried it.
A third solution could be to use something else than pickle to store your object.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With