En el argot de Python, invocar código Python desde otro lenguaje se llama "empotrar" (embed) Python.
libpython
Aunque el ejemplo que vemos a continuación es extremadamente rudimentario, la librería libpython
permite realizar cualquier cualquier módulo Python y ejecutar cualquier estructura del lenguaje. Sin embargo, la interacción entre ambos lenguajes resulta compleja y exenta de todo soporte de orientación a objetos, dado que es una librería C.
In [1]:
!mkdir -p bindings/embed/libpython
In [4]:
%%file bindings/embed/libpython/version.cc
#include <Python.h>
int main(int argc, char *argv[]) {
Py_Initialize();
PyRun_SimpleString("import sys; print('{}'.format(sys.version_info[:2]))\n");
Py_Finalize();
return 0;
}
In [5]:
%%file bindings/embed/libpython/Makefile
#!/usr/bin/make -f
# -*- mode:makefile -*-
CXXFLAGS = -I/usr/include -I/usr/include/python2.7/
LDFLAGS = -lpython2.7
TARGET = $(patsubst %.cc, %, $(wildcard *.cc))
all: $(TARGET)
clean:
$(RM) $(TARGET) *.o *~
In [6]:
!make -C bindings/embed/libpython/ clean all
In [7]:
!./bindings/embed/libpython/version
In [9]:
!mkdir -p bindings/embed/boost
In [10]:
%%file bindings/embed/boost/version.cc
#include <boost/python.hpp>
#include <boost/python/import.hpp>
#include <iostream>
using namespace boost::python;
using namespace std;
int main(int argc, char *argv[]) {
Py_Initialize();
PyRun_SimpleString("import sys; result = sys.version_info[:2]");
object mainobj = import("__main__");
object dictionary = mainobj.attr("__dict__");
object result = dictionary["result"];
tuple tup = extract<tuple>(result);
if (!extract<int>(tup[0]).check() || !extract<int>(tup[1]).check())
return 0;
int major = extract<int>(tup[0]);
int minor = extract<int>(tup[1]);
cout << major << "." << minor << endl;
Py_Finalize();
return 0;
}
In [11]:
%%file bindings/embed/boost/Makefile
#!/usr/bin/make -f
# -*- mode:makefile -*-
CXXFLAGS = -Wall -g -I/usr/include -I/usr/include/python2.7/
LDFLAGS = -lpython2.7 -lboost_python-py27
TARGET = $(patsubst %.cc, %, $(wildcard *.cc))
all: $(TARGET)
clean:
$(RM) $(TARGET) *.o *~
In [12]:
!make -C bindings/embed/boost clean all
In [13]:
!./bindings/embed/boost/version
Cuando desde un programa escrito en Python podemos llamar a código escrito en otro lenguaje (mayoritariamente C y C++) se dice que "extendemos" Python.
In [14]:
!mkdir -p ./bindings/extend/libpython/
In [15]:
%%file ./bindings/extend/libpython/greet.c
#include <Python.h>
static PyObject* greet(PyObject* self, PyObject* args) {
char* msg = "Hello World (libpython)";
return Py_BuildValue("s", msg);
}
static PyMethodDef function_binder[] = {
{"greet", greet, METH_VARARGS},
{NULL, NULL}
};
void initgreet() {
Py_InitModule("greet", function_binder);
}
In [16]:
%%file ./bindings/extend/libpython/Makefile
#!/usr/bin/make -f
# -*- mode:makefile -*-
CFLAGS = -Wall -g -I/usr/include -I/usr/include/python2.7/ -fPIC
LDFLAGS = -lpython2.7 -shared -fPIC
TARGET = $(patsubst %.c, %.so, $(wildcard *.c))
all: $(TARGET)
greet.so: greet.o
gcc $(LDFLAGS) -o $@ $^
clean:
$(RM) $(TARGET) *.o *~
In [17]:
!make -C ./bindings/extend/libpython clean all
In [18]:
!rm greet.so
!ln -s bindings/extend/libpython/greet.so .
In [20]:
import greet
greet.greet()
Out[20]:
In [1]:
import ctypes
libc = ctypes.cdll.LoadLibrary('libc.so.6')
libc.printf("hola %d\n", 4)
Out[1]:
In [2]:
!mkdir -p ./bindings/extend/boost/
In [3]:
%%file ./bindings/extend/boost/greet.cc
#include <boost/python.hpp>
char const* greet() {
return "Hello World (boost)";
}
BOOST_PYTHON_MODULE(greet) {
using namespace boost::python;
def("greet", greet);
}
In [5]:
%%file ./bindings/extend/boost/setup.py
from distutils.core import setup, Extension
greet = Extension('greet', sources = ['greet.cc'],
libraries = ['boost_python-py27'])
setup(name = 'greet',
version = '1.0',
description = 'C++ package for python',
ext_modules = [greet])
In [6]:
!cd bindings/extend/boost && python setup.py build
In [2]:
!rm greet.so
!ln bindings/extend/boost/build/lib.linux-x86_64-2.7/greet.so .
In [3]:
import greet
greet.greet()
Out[3]:
El ejemplo anterior "expone" una función. Por supuesto es posible exponer una clase C++ para ser utilizada desde Python: