我在C++中有以下代码:
class Person
{
public:
enum Gender {Male, Female};
Gender GetGender() const;
}
我用这种方式把它包装在boost::python中:
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();
}
当我尝试从Python调用person.GetGender()
时,我得到以下异常:
无法pickle:属性查找**PyBF.TestPython.Gender**。它错误地猜测了Gender(实际上是**PyBF.TestPython.Person.Gender**)枚举返回类型的命名空间。
如何告诉GetGender
函数显式返回什么类型?
由于我们没有产生错误的代码,我认为它发生在您尝试pickle Person对象时。
您的问题与boost的使用无关。它位于cPickle模块中。它在用嵌套类酸洗对象时遇到问题。有关解释,请参阅此答案。下面是一个产生错误的简单代码示例:
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()
运行它会产生以下输出:
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
如链接答案中所述,当cPickle向内部类询问其名称时,它会返回'__main__.MyInnerClass'
。但是,在模块的命名空间中找不到这个名称,因此会出现异常。
现在你会遇到这种情况,因为在python中没有类似于枚举类型的东西,所以boost创建一个对象来表示它。enum_构造在当前作用域中声明了一个类。通过捕获类范围,您最终在Person中创建了一个嵌套类,并得到了上面提到的pickle错误。
你的问题有几个解决办法。
最简单的方法是在Person的作用域之外声明枚举。您可能不想为代码组织公开Person的相关枚举。然后,您可以在子模块中声明Person类,这样您的枚举在某种程度上被声明为接近您的类,而不会过于公开。
你也可以看看boost的泡菜支撑。不过我还没试过。
第三种解决方案可能是使用pickle以外的其他东西来存储对象。
是否可能在某个地方定义了另一个男性、女性?否则,我看不出这是如何编译的。尝试添加类作用域:
enum_<Person::Gender>("Gender")
.EXPORT_ENUM_VALUE(Person::Male)
.EXPORT_ENUM_VALUE(Person::Female)
.export_values();