[PYTHON] 래핑 된 함수 앞과 뒤에 어떤 코드를 실행하는 함수와 멤버 함수 위에 래퍼를 쓰는 방법?
PYTHON래핑 된 함수 앞과 뒤에 어떤 코드를 실행하는 함수와 멤버 함수 위에 래퍼를 쓰는 방법?
래퍼 클래스 또는 래핑 된 함수 전후에 일부 코드를 실행할 수있는 함수를 작성하려고합니다.
float foo(int x, float y)
{
return x * y;
}
BOOST_PYTHON_MODULE(test)
{
boost::python::def("foo", <somehow wrap "&foo">);
}
이상적으로, 래퍼는 함수와 멤버 함수 모두에 대해 시그너처를 사용하여 일반적으로 작동해야합니다.
더 많은 정보:
나는 간단한 방법을 찾고 릴리스 / 재 비싼 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)에 포인터를 전달하고 컴파일러가 유형을 알아낼 수 있어야합니다.
누구든지 내가 사용할 수 있거나 올바른 방향으로 나를 가리킬 수있는 기술을 알고 있습니까?
건배!
해결법
-
==============================
1.이 경우 함수를 감싸는 Functor 클래스를 작성한 다음 boost :: python :: detail :: get_signature를 오버로드하여 Functor를 수락 할 수 있습니다.
이 경우 함수를 감싸는 Functor 클래스를 작성한 다음 boost :: python :: detail :: get_signature를 오버로드하여 Functor를 수락 할 수 있습니다.
업데이트 : 멤버 함수에 대한 지원이 추가되었습니다!
예:
#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)); } }
그리고 파이썬에서 :
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() '''), )
-
==============================
2.Stroustrup이 "Wrapping C ++ Member Function Calls"논문에서 설명한 함수 랩핑 기법을 살펴 보았습니까? 여기에는 간결한 방식으로 구현하는 방법을 보여주는 SO 응답도 있습니다. 기본적으로 연산자 -> ()를 오버로드하는 템플릿을 구현합니다. 해당 연산자의 구현 내에서 실제 함수 호출 전에 임시 객체를 생성합니다. 임시 객체의 생성자와 소멸자는 실제 함수 호출 전후의 "pre"와 "post"코드를 호출합니다.
Stroustrup이 "Wrapping C ++ Member Function Calls"논문에서 설명한 함수 랩핑 기법을 살펴 보았습니까? 여기에는 간결한 방식으로 구현하는 방법을 보여주는 SO 응답도 있습니다. 기본적으로 연산자 -> ()를 오버로드하는 템플릿을 구현합니다. 해당 연산자의 구현 내에서 실제 함수 호출 전에 임시 객체를 생성합니다. 임시 객체의 생성자와 소멸자는 실제 함수 호출 전후의 "pre"와 "post"코드를 호출합니다.
from https://stackoverflow.com/questions/2135457/how-to-write-a-wrapper-over-functions-and-member-functions-that-executes-some-co by cc-by-sa and MIT license
'PYTHON' 카테고리의 다른 글
[PYTHON] sklearn : 다항식의 계수를 구하는 방법 (0) | 2018.11.28 |
---|---|
[PYTHON] Python - 목록의 목록에서 항목의 색인 찾기 (0) | 2018.11.28 |
[PYTHON] 창에서 파이썬 기능 제한 시간 초과 (0) | 2018.11.27 |
[PYTHON] 한 번에 OpenCV에서 두 카메라의 비디오 캡처 (0) | 2018.11.27 |
[PYTHON] 파이썬을 사용하여 많은 파일 다운로드하기 (0) | 2018.11.27 |