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

发布于 2024-12-27 09:07:12 字数 810 浏览 2 评论 0原文

我在 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.

How can I告诉GetGender 函数显式返回什么类型?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

夜无邪 2025-01-03 09:07:12

由于我们没有产生错误的代码,我假设当您尝试 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 支持。不过我还没有尝试过。

第三种解决方案可能是使用 pickle 以外的东西来存储您的对象。

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.

丶情人眼里出诗心の 2025-01-03 09:07:12

您是否有可能在某处定义了另一个“男性”、“女性”?否则我看不到它是如何编译的。
尝试添加类范围:

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

Is it possible you have another Male, Female defined somewhere? otherwise I don't see how this compiles.
Try Adding the class scope:

enum_<Person::Gender>("Gender")
    .EXPORT_ENUM_VALUE(Person::Male)
    .EXPORT_ENUM_VALUE(Person::Female)
    .export_values();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文