logo
down
shadow

Set a python variable to a C++ object pointer with boost-python


Set a python variable to a C++ object pointer with boost-python

By : Tiến Dũng
Date : November 22 2020, 02:59 PM
it fixes the issue When dealing with language bindings, one often has to be pedantic in the details. By default, when a C++ object transgresses the language boundary, Boost.Python will create a copy, as this is the safest course of action to prevent dangling references. If a copy should not be made, then one needs to be explicit as to the ownership of the C++ object:
To pass a reference to a C++ object to Python while maintaining ownership in C++, use boost::python::ptr() or boost::ref(). The C++ code should guarantee that the C++ object's lifetime is at least as long as the Python object. When using ptr(), if the pointer is null, then the resulting Python object will be None. To transfer ownership of a C++ object to Python, one can apply the manage_new_object ResultConverterGenerator, allowing ownership to be transferred to Python. C++ code should not attempt to access the pointer once the Python object's lifetime ends. For shared ownership, one would need to expose the class with a HeldType of a smart pointer supporting shared semantics, such as boost::shared_ptr.
code :
BOOST_PYTHON_MODULE(example)
{
  boost::python::scope().attr("x") = ...; // example.x
}
boost::python::import("__main__").attr("x") = ...;
#include <iostream>
#include <boost/python.hpp>

// Mockup model.
struct spam
{
  spam(int id)
    : id_(id)
  {
    std::cout << "spam(" << id_ << "): "  << this << std::endl;
  }

  ~spam()
  {
    std::cout << "~spam(" << id_ << "): " << this << std::endl;
  }

  // Explicitly disable copying.
  spam(const spam&) = delete;
  spam& operator=(const spam&) = delete;

  int id_;
};

/// @brief Transfer ownership to a Python object.  If the transfer fails,
///        then object will be destroyed and an exception is thrown.
template <typename T>
boost::python::object transfer_to_python(T* t)
{
  // Transfer ownership to a smart pointer, allowing for proper cleanup
  // incase Boost.Python throws.
  std::unique_ptr<T> ptr(t);

  // Use the manage_new_object generator to transfer ownership to Python.
  namespace python = boost::python;
  typename python::manage_new_object::apply<T*>::type converter;

  // Transfer ownership to the Python handler and release ownership
  // from C++.
  python::handle<> handle(converter(*ptr));
  ptr.release();

  return python::object(handle);
}

namespace {
spam* global_spam;
} // namespace

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  // Expose spam.
  auto py_spam_type = python::class_<spam, boost::noncopyable>(
      "Spam", python::init<int>())
    .def_readonly("id", &spam::id_)
    ;

  // Directly create an instance of Python Spam and insert it into this
  // module's namespace.
  python::scope().attr("spam1") = py_spam_type(1);

  // Construct of an instance of Python Spam from C++ spam, transfering
  // ownership to Python.  The Python Spam instance will be inserted into
  // this module's namespace.
  python::scope().attr("spam2") = transfer_to_python(new spam(2));

  // Construct an instance of Python Spam from C++, but retain ownership of
  // spam in C++.  The Python Spam instance will be inserted into the
  // __main__ scope.
  global_spam = new spam(3);
  python::import("__main__").attr("spam3") = python::ptr(global_spam);
}
>>> import example
spam(1): 0x1884d40
spam(2): 0x1831750
spam(3): 0x183bd00
>>> assert(1 == example.spam1.id)
>>> assert(2 == example.spam2.id)
>>> assert(3 == spam3.id)
~spam(1): 0x1884d40
~spam(2): 0x1831750


Share : facebook icon twitter icon
boost::python - how to pass by reference/pointer to python overriden class functions

boost::python - how to pass by reference/pointer to python overriden class functions


By : user3113178
Date : March 29 2020, 07:55 AM
seems to work fine Well after searching around for a bit I found the answer. Turns out you have to explicitly indicate to call_method not to make a copy when it's pass by reference (by using ref(T)) or pointer (by using ptr(T)). By Changing
code :
void StatusEffectWrapper::TickCharacter(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks)
{
    call_method<void>(self, "TickCharacter", character, field, ticks);
}
void StatusEffectWrapper::TickCharacter(Game::Character::BaseCharacter* character, Game::Battles::BattleField *field, int ticks)
{
    call_method<void>(self, "TickCharacter", ptr(character), ptr(field), ticks);
}
Boost::Python Forward Declaration of boost::python::object throwing python TypeError

Boost::Python Forward Declaration of boost::python::object throwing python TypeError


By : acgt1008
Date : March 29 2020, 07:55 AM
Hope this helps Ah! Fixed it.
Changing the call to globals in the constructor from
code :
globals(main_method.attr("__dict__"));
globals = main_method.attr("__dict__");
Boost.Python - Passing boost::python::object as argument to python function?

Boost.Python - Passing boost::python::object as argument to python function?


By : vivek
Date : March 29 2020, 07:55 AM
To fix this issue Got this fantastic solution from the c++sig mailing list.
Implement a std::map in the C++ class, then overload __getattr__() and __setattr__() to read from and write to that std::map. Then just send it to the python with boost::python::ptr() as usual, no need to keep an object around on the C++ side or send one to the python. It works perfectly.
code :
boost::python::object PyMyModule_global;
class MyClass
{
public:
   //Python checks the class attributes before it calls __getattr__ so we don't have to do anything special here.
   boost::python::object Py_GetAttr(std::string str)
   {
      if(dict.find(str) == dict.end())
      {
         PyErr_SetString(PyExc_AttributeError, JFormat::format("MyClass instance has no attribute '{0}'", str).c_str());
         throw boost::python::error_already_set();
      }
      return dict[str];
   }

   //However, with __setattr__, python doesn't do anything with the class attributes first, it just calls __setattr__.
   //Which means anything that's been defined as a class attribute won't be modified here - including things set with
   //add_property(), def_readwrite(), etc.
   void Py_SetAttr(std::string str, boost::python::object val)
   {
      try
      {
         //First we check to see if the class has an attribute by this name.
         boost::python::object obj = PyMyModule_global["MyClass"].attr(str.c_str());
         //If so, we call the old cached __setattr__ function.
         PyMyModule_global["MyClass"].attr("__setattr_old__")(ptr(this), str, val);
      }
      catch(boost::python::error_already_set &e)
      {
         //If it threw an exception, that means that there is no such attribute.
         //Put it on the persistent dict.
         PyErr_Clear();
         dict[str] = val;
      }
   }
private:
   std::map<std::string, boost::python::object> dict;
};
BOOST_PYTHON_MODULE(MyModule)
{
   boost::python::class_<MyClass>("MyClass", boost::python::no_init)
      .def("__getattr__", &MyClass::Py_GetAttr)
      .def("__setattr_new__", &MyClass::Py_SetAttr);
}
void PyInit()
{
   //Initialize module
   PyImport_AppendInittab( "MyModule", &initMyModule );
   //Initialize Python
   Py_Initialize();

   //Grab __main__ and its globals
   boost::python::object main = boost::python::import("__main__");
   boost::python::object global = main.attr("__dict__");

   //Import the module and grab its globals
   boost::python::object PyMyModule = boost::python::import("MyModule");
   global["MyModule"] = PyMyModule;
   PyMyModule_global = PyMyModule.attr("__dict__");

   //Overload MyClass's setattr, so that it will work with already defined attributes while persisting new ones
   PyMyModule_global["MyClass"].attr("__setattr_old__") = PyMyModule_global["MyClass"].attr("__setattr__");
   PyMyModule_global["MyClass"].attr("__setattr__") = PyMyModule_global["MyClass"].attr("__setattr_new__");
}
Trouble destructor,call python's object with pointer in boost.python

Trouble destructor,call python's object with pointer in boost.python


By : Muhammad Harun-Or-Ro
Date : March 29 2020, 07:55 AM
With these it helps To understand what's really happening, you're missing a copy-constructor:
code :
B()
  A()
B::run()
  A(a)     <- copy construct A to pass by value
    fun1() <- arg passed by value
  ~A()     <- delete copy
  A(a)     <- copy construct A to pass by value
    fun2() <- arg passed by value
  ~A()     <- delete copy
~B()
  ~A()
_obj.attr("fun1")(boost::ref(aa));
_obj.attr("fun2")(boost::ref(aa));
B()
  A()    <- constructed once
B::run()
  fun1() <- arg passed by reference
  fun2() <- arg passed by reference
~B()
  ~A()   <- destroyed once
Pass a C++ object by reference/pointer to Python interpreter using Boost.Python

Pass a C++ object by reference/pointer to Python interpreter using Boost.Python


By : rehager
Date : March 29 2020, 07:55 AM
fixed the issue. Will look into that further I have a C++ object and wish to pass it by reference/pointer to an embedded Python interpreter so that Python can make changes to it which are visible to both C++ and Python. I am using Boost.Python for interop. , In C++, prior to running the script, add:
code :
main_namespace["foo"] = ptr(&foo);
foo.bar = 12
Related Posts Related Posts :
  • What are the centroid of k-means clusters with PCA decomposition?
  • How do mongoengine filter field not null?
  • Categorize results based on Model in haystack?
  • Error installing pycrypto on my mac
  • Can Django ORM has strip field?
  • Python pack / unpack converts to Objective C
  • Python - Selenium Locate elements by href
  • Couldn't iterate over a dictionary context variable in template, despite having all in place, as far as I know?
  • Test if Django ModelForm has instance on customized model
  • Reading excel column 1 into Python dictionary key, column 2 into value
  • AttributeError: 'module' object has no attribute 'timeit' while doing timeit a python function
  • Accessing button using selenium in Python
  • Removing White Spaces in a Python String
  • Sort timestamp in python dictionary
  • How to use Python 2 packages in Python 3 project?
  • retrieve links from web page using python and BeautifulSoup than select 3 link and run it 4 times
  • applying lambda to tz-aware timestamp
  • Having two Generic ListViews on the same page
  • Merging numpy array elements using join() in python
  • pythonic way to parse/split URLs in a pandas dataframe
  • Added iterating over page id in Scrapy, responses in parse method no longer run
  • wanting to add an age gate to my quiz
  • Removing top empty line when writing a text file Python
  • How to use a template html in different folder on Google App Engine python?
  • Access ndarray using list
  • unable to post file+data using python-requests
  • How to test aws lambda functions locally
  • inconsistent plot between matplotlib and seaborn in Python
  • How matplotlib show obvious changes?
  • Project in Python3, reading files, word data
  • Check for specific Item in list without Iteration or find()
  • Unicode encoding when reading from text file
  • Overloaded variables in python for loops?
  • All elements have same value after appending new element
  • Python Threading loop
  • `_pickle.UnpicklingError: the STRING opcode argument must be quoted`
  • Python: How to stop a variable from exceeding a value?
  • python textblob and text classification
  • Django - Context dictionary for attribute inside a class
  • Database is not updated in Celery task with Flask and SQLAlchemy
  • Shapely intersections vs shapely relationships - inexact?
  • How to extract a percentage column from a periodic column and the sum of the column?
  • Zombie ssh process using python subprocess.Popen
  • Python regex to capture a comma-delimited list of items
  • joining string and long in python
  • Value Error in python numpy
  • Check if any character of a string is uppercase Python
  • TensorFlow - why doesn't this sofmax regression learn anything?
  • Python Anaconda Proxy Setup via .condarc file on Windows
  • Creating django objects from emails
  • Get spotify currently playing track
  • Select multiple columns and remove values according to a list
  • Python - How to Subtract a Variable By 1 Every Second?
  • Tkinter unable to alloc 71867 bytes
  • How to add Variable to JSON Python Django
  • CSRF token missing or invalid Django
  • Python: writing to a text file
  • Extracting multiple rows from pandas dataframe and converting to columns
  • Pinging a remote PC with Flask, causing server to block
  • Making a fractal graph using a 2D array?
  • shadow
    Privacy Policy - Terms - Contact Us © animezone.co