Найти - Пользователи
Полная версия: С/С++ и Python
Начало » Python для экспертов » С/С++ и Python
1
Yotce
Есть класс на питоне.

class PyClass(...)

m_object = ...

def __init__(self, ...)
чтото делаем.

def py_method_a(self)
return m_object

def py_method_b(self, arg_1, arg_2)
return m_object(arg)
и для него нужна связка на C++

class CClass
{
ret_type1 method_a(); // здесь произвести вызов метода py_method_a
ret_type2 method_b(arg_1, arg_2); // здесь метод py_method_b
}
Не как не могу понять как это реализовать С API PyThon вроде разобрался вызвать функцию получается, а склассом что-то туплю.
Может ктонить привести работающий пример таково типа?
Также осталось загадкой как это зделать на boost::python
Андрей Светлов
Давайте для начала на boost. Если потребуется, потом можно будет перевести на Python C API.
# для начала нужен экземпляр PyClass. Откуда вы его возьмете - выходит за рамки рассматриваемого вопроса
bp::object inst = get_some_object();

ret_type1 ret1 = bp::extract<ret_type1>(inst.attr("method_a")());
ret_type2 ret2 = bp::extract<ret_type2>(inst.attr("method_b")(arg_1, arg_2));
Для plain C заменяем bp::object на PyObject* и используем PyObject_Call<…>(…), не забывая аккуратно считать ссылки.
Yotce
Что делаю не так?
Написал простой класс

но при вызове result = boost::python::extract<std::string>(inst.attr(“get_method”)()); выдаёт ошибку
TypeError: unbound method get_method() must be called with MyClass instance as first argument (got nothing instead)
#include <string>
#include <iostream>
#include <boost/python.hpp>

int main( int argc, char ** argv )
{
Py_Initialize();

try
{
std::string result;

boost::python::object module = boost::python::import("test");
boost::python::object name_space = module.attr("__dict__");

boost::python::object inst = name_space["MyClass"];

//inst.attr("set_method")("TEST MESSAGE SEND 1");

result = boost::python::extract<std::string>(inst.attr("get_method")());
std::cout << " result 0 " << result << std::endl;

result = boost::python::extract<std::string>(inst.attr("get_method")());
std::cout << " result 1 " << result << std::endl;

boost::python::extract<std::string>(inst.attr("set_method")("TEST MESSAGE SEND 2"));
result = boost::python::extract<std::string>(inst.attr("get_method")());
std::cout << " result 2 " << result << std::endl;


} catch (boost::python::error_already_set)
{
PyErr_Print();
}

Py_Finalize();
return 0;
}
import os

class InstClass:

m_string = None

def __init__(self, str = None):
self.m_string = str

def recv(self):
return self.m_string

def send(self, str):
self.m_string = str


class MyClass:
'''
classdocs
'''

m_inst_class = None

def __init__(self):
'''
Constructor
'''
self.m_inst_class = InstClass()

def get_method(self):
return self.m_inst_class.recv()

def set_method(self, str):
self.m_inst_class.send(str)


if __name__ == "__main__":
my_class = MyClass()
my_class.set_method("first exec set_method")
result = my_class.get_method()
print ' Result ', result

os.system("pause")
Андрей Светлов
А вы работайте с экземпляром класса, а не классом как таковым:

boost::python::object inst = name_space();

Далее: старатесь не затенять стандартные имена во избежание странных конфликтов: не стоит называть переменную str и модуль test
import test должен импортировать стандартные тесты питона, если они установлены (Убунта, зараза, очень своеобразно пакует Питон).
import foo.test для вашего пакета foo - сугубо личное дело и вполне допустим.

А еще стоит создавать модуль __main__. Некоторые библиотеки терпеть не могут его отсутствие.
Yotce
После изменения
...
boost::python::object inst = name_space["MyClass"];
...
на
...
boost::python::object inst = name_space["MyClass"]();
...
метод класса вызывается только значение вернуть не получается
при использовании

char *c_str = boost::python::extract<char *>(inst.attr("get_method")());
std::printf("%s", c_str);
возвращается null, а при использовании std::string вместо char выдаёт ошибку
TypeError: No registered converter was able to produce a C++ rvalue of type clas
s std::basic_string<char,struct std::char_traits<char>,class std::allocator<char
> > from this Python object of type NoneType
Правка:

если возвращать число работает.
Андрей Светлов
Я думал, с этим вы сами разберетесь.
boost::python не может преобразовать None -> std::string, и это правильно.
Задайте строку - значение по умолчанию. Или преобразуйте так, чтобы None -> std::string()
Yotce
Андрей Светлов
Я думал, с этим вы сами разберетесь.
boost::python не может преобразовать None -> std::string, и это правильно.
Задайте строку - значение по умолчанию. Или преобразуйте так, чтобы None -> std::string()
Тупанул :)
Yotce
Андрей Светлов
Огромное спасиб за помощь.
Андрей Светлов
Пожалуйста. Обращайтесь в случае чего…
Да, еще:
       boost::python::object module     = boost::python::import("test");
boost::python::object name_space = module.attr("__dict__");

boost::python::object inst = name_space["MyClass"];
конечно, работает. Но, имхо, лучше писать
bp::object inst = module.attr(“MyClass”)
Вы же на питоне делаете module.attribute, а не module.__dict__, хоть это одно и то же.

namespace bp = boost::python;
в .cpp файлах несколько уменьшает количество набиваемых символов и улучшает читаемость.
В .hpp стоит использовать полное имя boost::python::object (по крайней мере пока вы не поместили это в свой namespace).
using boost::python; употреблять не рекомендую - засоряет пространство имен и ощутимо тормозит компилятор. А еще можно нарваться на internal compiler error (по крайней мере в VC 7.1).
Эти рекомендации, конечно, относятся не к питону как таковому а к использованию namespace в C++.
This is a "lo-fi" version of our main content. To view the full version with more information, formatting and images, please click here.
Powered by DjangoBB