2014-11-26 6 views
2

Boost.Python을 사용하여 Python으로 C++ 함수를 내보내는 중입니다. 이 함수에서 로컬 스택 프레임 인 에있는 파이썬 객체에 액세스하려면없이이 객체를 파이썬 측에서 액세스해야합니다.Boost.python은 객체를 로컬 액세스 범위로 가져옵니다.

예 : 나는 PyEval_GetLocals를 사용하여 로컬 스택 프레임에 액세스 할 수 있습니다

x = X() 

def fun(): 
    cppfun() 
    # no explicit access to x 

cppfun 내부는 C 코드 다음 다음 X와 C++ 파이썬에 수출 기능 cppfun 및 객체 ++ 가지고 있지만 파이썬 이후 측면에 x에 대한 참조가 포함되어 있지 않은 경우이 객체는 해당 로컬 스택 프레임에 포함되지 않습니다 (마찬가지로 print(locals()) 내부에 fun, x 등이 포함될 수 있습니다 (예 : print(x)).

내가 cppfun 내부 x에 액세스 할 수있는 어떤 방법은 어떻게 든 파이썬 측에 fun 내에서 액세스하지 않고 locals으로 당겨 파이썬 강제 할 수 있습니다, 거기 있습니까? 나는 단순히 boost::python::eval("x")을 실행하려했지만 잘못된 범위에서도 실행됩니다.

추가 : 그래서 난 하지fun 또는 그런 일 (나는이 방법을 사용할 수없는 알고) 내부의 외부 프레임의 쓰기에서 x을 만들고 싶어 할; 이 질문은 순전히 파이썬 측면에서 액세스하지 않고 외부 프레임에서 변수에 대한 읽기 액세스를 얻는 방법에 관한 것입니다.

답변

0

PyEval_GetGlobals()을 사용하여 외부 범위에 액세스 할 수 있습니다. PyEval_GetGlobals()은 현재 실행의 전역 변수 사전 인 프레임을 반환합니다. 파이썬 내장 함수 인 globals() 함수와 매우 유사합니다.이 함수는 함수가 정의 된 모듈의 전역 심볼 테이블을 반환합니다. 그러나 프레임 스택은 표준 모듈과 확장 모듈간에 약간 다르게 처리됩니다. 확장 모듈의 경우 현재 실행 프레임이 호출자이므로 PyEval_GetGlobals()은 확장 모듈의 전역이 아닌 호출자 모듈의 전역 심볼을 반환합니다.

대체 한 후, PyEval_GetFrame() 통해 현재 프레임에 대한 핸들을 얻을 수있는 각 프레임 의 (f_local) 로컬 및 글로벌 (f_global) 사전 검사 스택으로 걷는다. 여기


기술은 그들 사이의 미묘한 차이를 모두 보여주는 전체 최소 일례이다. 예에서 get_global()PyEval_GetGlobals()을 사용하고 search_stack_locals()은 스택의 각 프레임에 대한 로컬 사전을 검사합니다. spam.py에서

#include <boost/python.hpp> 

namespace detail { 

/// @brief Return a handle to a global variable. If one is not found, then 
///  None is returned. 
boost::python::object get_global(std::string name) 
{ 
    // Borrow a reference from the locals dictionary to create a handle. 
    // If PyEval_GetGlobals() returns NULL, then Boost.Python will throw. 
    namespace python = boost::python; 
    python::dict globals(python::borrowed(PyEval_GetGlobals())); 
    return globals.get(name); 
} 

/// @brief Search through the call stack for a variable. If found, the 
///  object is returned. Otherwise, None. 
boost::python::object search_stack_locals(std::string name) 
{ 
    // Get a handle to the current frame. 
    namespace python = boost::python; 
    python::object frame(python::borrowed(
    reinterpret_cast<PyObject*>(PyEval_GetFrame()))); 

    // Iterate through the stack's frames until the variable has been found 
    // or the stack has been exhausted. 
    while (frame) 
    { 
    // If the current frame has the desired variable, then return it. 
    python::dict locals(frame.attr("f_locals")); 
    if (locals.has_key(name)) 
    { 
     return locals.get(name); 
    } 

    // Move up the stack. 
    frame = frame.attr("f_back"); 
    } 

    // Return None 
    return python::object(); 
} 

} // namespace detail 

/// @brief Mockup function to demonstrate finding non-local variables. 
boost::python::object cppfun(std::string name) 
{ 
    return boost::python::make_tuple(
    detail::get_global(name), detail::search_stack_locals(name)); 
} 

BOOST_PYTHON_MODULE(example) 
{ 
    namespace python = boost::python; 
    python::def("cppfun", &cppfun); 
} 

:

import example 

x = 'spam.global.x' 
y = 'spam.global.y' 

def inner(): 
    for name in ('x', 'y', 'z'): 
     print name, example.cppfun(name) 

def outer(): 
    x = 'spam.outer.x' 
    inner() 

대화 형 사용 :

>>> x = 'main.global.x' 
>>> y = 'main.global.y' 
>>> z = 'main.global.z' 
>>> import spam 
>>> spam.outer() 
x ('spam.global.x', 'spam.outer.x') 
y ('spam.global.y', 'main.global.y') 
z (None, 'main.global.z') 

를 적어 둡니다 PyEval_GetGlobals()를 사용하는 경우, example 확장 모듈 호출자의 모듈의 전역 심볼 테이블 (spam)을 사용하는 것이다. 인터프리터의 주요 네임 스페이스에서 선언 된 전역은 스택을 반복 할 때만 발견되었습니다.