Как написать оболочку над функциями и функциями-членами, которые выполняют некоторый код до и после завернутой функции?

Я пытаюсь написать некоторый класс-оболочку или функцию, которая позволяет мне выполнять некоторый код до и после завернутой функции.

float foo(int x, float y) { return x * y; } BOOST_PYTHON_MODULE(test) { boost::python::def("foo", <somehow wrap "&foo">); } 

В идеале оболочка должна быть общей, работая как для функций, так и для функций-членов, с любой подписью.

Больше информации:

Я ищу простой способ выпускать / повторно приобретать GIL вокруг моих дорогих вызовов C ++ без необходимости вручную писать тонкие обертки следующим образом:

 float foo_wrapper(int x, float y) { Py_BEGIN_ALLOW_THREADS int result = foo(x, y); Py_END_ALLOW_THREADS return result; } BOOST_PYTHON_MODULE(test) { boost::python::def("foo", &foo_wrapper); } 

Этот тип обертки будет повторяться несколько раз для всех видов функций, и я хотел бы найти решение, которое позволило бы мне избежать кодирования всех из них.

Я пробовал некоторые подходы, но лучше всего я мог прийти с требованием, чтобы пользователь явно указывал типы возвращаемых значений и параметров, например:

 boost::python::def("foo", &wrap_gil<float, int, float>(&foo_wrapper)); 

Но мне кажется, что нужно просто передать указатель на функцию (& foo_wrapper) и дать компилятору выяснить типы.

Кто-нибудь знает технику, которую я мог бы использовать, или указать мне в правильном направлении?

Ура!

  • Настроить расположение файла .so, созданного Cython
  • Как реализовать оболочку stdin, stdout?
  • обертывание библиотеки C (GSL) в коде cython с помощью обратного вызова
  • Запустите скрипт MATLAB из python + pass args
  • 2 Solutions collect form web for “Как написать оболочку над функциями и функциями-членами, которые выполняют некоторый код до и после завернутой функции?”

    В этом случае вы можете написать класс Functor, который обертывает вашу функцию, а затем перегрузить boost :: python :: detail :: get_signature, чтобы принять ваш Functor!

    UPDATE: добавлена ​​поддержка функций-членов тоже!

    Пример:

     #include <boost/shared_ptr.hpp> #include <boost/python.hpp> #include <boost/python/signature.hpp> #include <boost/mpl/vector.hpp> #include <iostream> #include <string> #include <sstream> static boost::shared_ptr<std::ostringstream> test_stream_data; std::ostringstream& test_stream() { if (!test_stream_data) { test_stream_data.reset(new std::ostringstream); } return *test_stream_data; } std::string get_value_and_clear_test_stream() { std::string result; if (test_stream_data) { result = test_stream_data->str(); } test_stream_data.reset(new std::ostringstream); return result; } std::string func(int a, double b) { std::ostringstream oss; oss << "func(a=" << a << ", b=" << b << ")"; std::string result = oss.str(); test_stream() << "- In " << result << std::endl; return result; } class MyClass { public: MyClass(std::string p_name) : m_name(p_name) { test_stream() << "- In MyClass::MyClass(p_name=\"" << p_name << "\")" << std::endl; } MyClass(MyClass const& p_another) : m_name(p_another.m_name) { test_stream() << "- In MyClass::MyClass(p_another=MyClass(\"" << p_another.m_name << "\"))" << std::endl; } ~MyClass() { test_stream() << "- In MyClass(\"" << this->m_name << "\")::~MyClass()" << std::endl; } boost::shared_ptr<MyClass> clone_and_change(std::string p_new_name) { test_stream() << "- In MyClass(\"" << this->m_name << "\").clone_and_change(p_new_name=\"" << p_new_name << "\")" << std::endl; boost::shared_ptr<MyClass> result(new MyClass(*this)); result->m_name = p_new_name; return result; } std::string get_name() { test_stream() << "- In MyClass(\"" << this->m_name << "\").get_name()" << std::endl; return this->m_name; } std::string m_name; }; struct ScopePreAndPostActions { ScopePreAndPostActions() { test_stream() << "[Before action...]" << std::endl; } ~ScopePreAndPostActions() { test_stream() << "[After action...]" << std::endl; } }; template <class FuncType_> struct FuncWrapper; // You can code-generate specializations for other arities... template <class R_, class A0_, class A1_> struct FuncWrapper<R_ (A0_, A1_)> { typedef R_ (*func_type)(A0_, A1_); typedef typename boost::add_const<typename boost::add_reference<typename A0_>::type>::type AC0_; typedef typename boost::add_const<typename boost::add_reference<typename A1_>::type>::type AC1_; func_type m_wrapped_func; FuncWrapper(func_type p_wrapped_func) : m_wrapped_func(p_wrapped_func) { } R_ operator()(AC0_ p0, AC1_ p1) { ScopePreAndPostActions actions_guard; return this->m_wrapped_func(p0, p1); } }; template < class R_, class C_, class A0_=void, class A1_=void, class A2_=void // ... > struct MemberFuncWrapper; template <class R_, class C_, class A0_> struct MemberFuncWrapper<R_, C_, A0_> { typedef R_ (C_::*member_func_type)(A0_); typedef typename boost::add_const<typename boost::add_reference<typename A0_>::type>::type AC0_; member_func_type m_wrapped_method; MemberFuncWrapper(member_func_type p_wrapped_method) : m_wrapped_method(p_wrapped_method) { } R_ operator()(C_* p_self, AC0_ p0) { ScopePreAndPostActions actions_guard; return (p_self->*(this->m_wrapped_method))(p0); return R_(); } }; namespace boost { namespace python { namespace detail { // You can code-generate specializations for other arities... template <class R_, class P0_, class P1_> inline boost::mpl::vector<R_, P0_, P1_> get_signature(FuncWrapper<R_ (P0_, P1_)>, void* = 0) { return boost::mpl::vector<R_, P0_, P1_>(); } template <class R_, class C_, class P0_> inline boost::mpl::vector<R_, C_*, P0_> get_signature(MemberFuncWrapper<R_, C_, P0_>, void* = 0) { return boost::mpl::vector<R_, C_*, P0_>(); } } } } // ------------------------------------------------------------------- template <class FuncPtr_> void make_wrapper(FuncPtr_); // You can code-generate specializations for other arities... template <class R_, class A0_, class A1_> FuncWrapper<R_ (A0_, A1_)> make_wrapper(R_ (*p_wrapped_func)(A0_, A1_)) { return FuncWrapper<R_ (A0_, A1_)>(p_wrapped_func); } template <class R_, class C_, class A0_> MemberFuncWrapper<R_, C_, A0_> make_wrapper(R_ (C_::*p_wrapped_method)(A0_)) { return MemberFuncWrapper<R_, C_, A0_>(p_wrapped_method); } template <class R_, class C_, class A0_, class A1_> MemberFuncWrapper<R_, C_, A0_, A1_> make_wrapper(R_ (C_::*p_wrapped_method)(A0_, A1_)) { return MemberFuncWrapper<R_, C_, A0_, A1_>(p_wrapped_method); } using namespace boost::python; void RegisterTestWrapper() { def("GetValueAndClearTestStream", &get_value_and_clear_test_stream); def("TestFunc", &func); def( "TestWrappedFunctor", make_wrapper(&func) ); { class_< MyClass, shared_ptr<MyClass>, boost::noncopyable > c("MyClass", init<std::string>()); c.def("CloneAndChange", &MyClass::clone_and_change); c.def("GetName", &MyClass::get_name); c.def("WrappedCloneAndChange", make_wrapper(&MyClass::clone_and_change)); } } 

    И на python:

     import unittest from _test_wrapper import GetValueAndClearTestStream, TestFunc, TestWrappedFunctor, MyClass class Test(unittest.TestCase): def setUp(self): GetValueAndClearTestStream() def testWrapper(self): self.assertEqual(TestFunc(69, 1.618), 'func(a=69, b=1.618)') self.assertEqual(GetValueAndClearTestStream(), '- In func(a=69, b=1.618)\n') self.assertEqual(TestWrappedFunctor(69, 1.618), 'func(a=69, b=1.618)') self.assertEqual( GetValueAndClearTestStream(), ( '[Before action...]\n' '- In func(a=69, b=1.618)\n' '[After action...]\n' ), ) def testWrappedMemberFunction(self): from textwrap import dedent x = MyClass("xx") y = x.WrappedCloneAndChange("yy") z = y.WrappedCloneAndChange("zz") self.assertEqual(x.GetName(), "xx") self.assertEqual(y.GetName(), "yy") self.assertEqual(z.GetName(), "zz") self.assertEqual( GetValueAndClearTestStream(), dedent('''\ - In MyClass::MyClass(p_name="xx") [Before action...] - In MyClass("xx").clone_and_change(p_new_name="yy") - In MyClass::MyClass(p_another=MyClass("xx")) [After action...] [Before action...] - In MyClass("yy").clone_and_change(p_new_name="zz") - In MyClass::MyClass(p_another=MyClass("yy")) [After action...] - In MyClass("xx").get_name() - In MyClass("yy").get_name() - In MyClass("zz").get_name() '''), ) 

    Вы просмотрели технику обертывания функции, описанную Stroustrup в своей статье « Wrapping C ++ Member Calls »? Здесь также есть ответ SO, который демонстрирует, как реализовать его в сжатой форме. В основном вы бы использовали шаблон, который перегружает operator->() . В рамках реализации этого operator вы должны создать временный объект перед вашим фактическим вызовом функции. Конструктор и деструктор временного объекта позаботятся о том, чтобы вызвать ваш « pre- » и « post- » код до и после вашего фактического вызова функции, соответственно.

    Python - лучший язык программирования в мире.