2012-01-16 2 views
5

я следующий код в C++:Namespaces перепутаны при возврате контекстного перечисления из метода класса

class Person 
{ 
    public: 
     enum Gender {Male, Female}; 

     Gender GetGender() const; 
} 

Я завернул его в импульсе :: питона таким образом:

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(); 
} 

Когда я пытаюсь позвонить person.GetGender() из Python Я получаю следующее исключение:

 
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 FUNCT Ион какой тип для возврата явно?

+2

Существует некоторая странность с раскалыванием перечислений. см. здесь: http://stackoverflow.com/questions/3214969/ –

ответ

1

Поскольку мы не имеем код, который производит эту ошибку, я предполагаю, что это происходит, когда вы пытаетесь мариновать объект Person.

Ваша проблема не связана конкретно с использованием boost. Он находится в модуле cPickle. Он имеет проблемный травильный объект с вложенными классами. См. Это 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'. Однако это имя не может быть найдено в пространстве имен модуля, поэтому вы получаете исключение.


Теперь вы испытываете это, потому что, так как есть не что-то похожее на перечислимый тип в питоне, форсируют создать объект для представления его. Конструкция enum_ объявляет класс в текущей области. Захватив класс, вы в конечном итоге создаете вложенный класс внутри Person, и вы получите упомянутую выше ошибку рассола.

Существует несколько вариантов решения вашей проблемы.

Простейшим было бы объявить перечисление вне пределов Человека. Возможно, вы не захотите раскрывать связанное с ним перечисление, кроме него, для организации кода. Затем вы можете объявить класс Person в дополнительном модуле, чтобы ваш enum несколько был объявлен рядом с вашим классом, не будучи слишком открытым.

Вы также можете посмотреть boost's pickle support. Однако я не пробовал.

Третьим решением может быть использование чего-то другого, кроме рассола для хранения вашего объекта.

1

Возможно ли, что у вас есть другой мужчина, женщина, где-то определенная? в противном случае я не вижу, как это компилируется. Попробуйте Добавление рамки класса:

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

Извините, что обновил сообщение, я не полностью копировал свой код, надеюсь, теперь он имеет больше смысла – Grim

Смежные вопросы