从类方法返回作用域枚举时,命名空间混淆了

时间:2012-01-16 12:25:06

标签: c++ python boost-python

我在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()时,我得到以下异常:

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.

如何告诉GetGender函数明确返回哪种类型?

2 个答案:

答案 0 :(得分:1)

你有可能在某处定义另一名男性,女性吗?否则我不知道这是如何编译的。 尝试添加类范围:

enum_<Person::Gender>("Gender")
    .EXPORT_ENUM_VALUE(Person::Male)
    .EXPORT_ENUM_VALUE(Person::Female)
    .export_values();

答案 1 :(得分:1)

由于我们没有产生错误的代码,我认为当你尝试挑选一个Person对象时就会发生这种情况。

您的问题与boost的使用没有特别的关系。它位于cPickle模块中。它有嵌套类的问题pickling对象。有关说明,请参阅此answer。这是一个产生错误的简单代码示例:

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's pickle support。但是我还没试过。

第三种解决方案可能是使用除了pickle之外的其他东西来存储你的对象。