ユーザ用ツール

サイト用ツール


youtube:python-mixing-005

Boost.Pythonを使ってみる

作成日: 2023-08-08 (火)

第5回 Boost.Pythonを使ってみる

プロジェクトレイアウト

.
└── extending-demos/
    ├── Jamroot
    ├── simple/
    │   ├── Jamfile
    │   ├── simple.cpp
    │   └── test_simple.py
    ├── point/
    │   ├── Jamfile
    │   ├── point.cpp
    │   └── test_point.py
    ├── pypoint/
    │   ├── Jamfile
    │   ├── pypoint.cpp
    │   └── test_pypoint.py
    └── fakegfx/
        ├── Jamfile
        ├── fakegfx.h
        ├── fakegfx.cpp
        └── test_fakegfx.py

Jamroot

import python ;

lib boost_python3 ;

project
  : requirements
    <library>boost_python3
;

build-project simple ;
build-project point ;
build-project pypoint ;
build-project fakegfx ;

プロジェクト simple

simple.cpp

#include <boost/python.hpp>
#include <boost/algorithm/string.hpp>
#include <iostream>

namespace {
void println(std::string const &s) {
    std::cout << s << '\n';
}

std::string to_upper(std::string const &s) {
    return boost::to_upper_copy<std::string>(s);
}
} // ns anon

BOOST_PYTHON_MODULE(simple) {
    namespace python = boost::python;
    python::def("println", println);
    python::def("to_upper", to_upper);
}

test_simple.py

import simple

simple.println("Hello, Boost.Python!")

u = simple.to_upper("Hello, Boost.Python!")
simple.println(u)

Jamfile

project simple
  : requirements
    <location>.
  ;

python-extension simple : simple.cpp ;

プロジェクト point

point.cpp

#include <boost/python.hpp>

namespace {
    struct Point {
        double x = 0.0;
        double y = 0.0;

        Point() = default;
        Point(double x, double y) : x{x}, y{y} {}
    };
    
    void translate(Point &pt, double tx, double ty) {
        pt.x += tx;
        pt.y += ty;
    }
}

BOOST_PYTHON_MODULE(point) {
    using namespace boost::python;
    
    class_<Point>("Point")
        .def(init<double, double>())
        .def("translate", translate)
        .def_readwrite("x", &Point::x)
        .def_readwrite("y", &Point::y);
    
    def("translate", translate);
}

test_point.py

import point

pt = point.Point()
print(f"{pt.x},{pt.y}")

pt.translate(100, -200)
print(f"{pt.x},{pt.y}")

Jamfile

project point
  : requirements
    <location>.
    ;

python-extension point : point.cpp ;

プロジェクト pypoint

pypoint.cpp

#include <boost/python.hpp>

namespace {

    void translate(boost::python::object pt, double tx, double ty) {
        pt.attr("x") += tx;
        pt.attr("y") += ty;
    }

} // ns anon

BOOST_PYTHON_MODULE(pypoint) {
    boost::python::def("translate", translate);
}

test_pypoint.py

import pypoint

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

pt = Point(1, 2)

pypoint.translate(pt, 100, -200)

print(f"{pt.x},{pt.y}")

Jamfile

project pypoint
  : requirements
    <location>.
    ;

python-extension pypoint : pypoint.cpp ;

プロジェクト fakegfx

fakegfx.h

#ifndef FAKEGFX_H
#define FAKEGFX_H

#include <iostream>

struct Point {
    Point() = default;
    Point(double x, double y) : x{x}, y{y} {}
    double x, y;
};

inline void translate(Point &pt, double tx, double ty) {
    pt.x += tx;
    pt.y += ty;
}

class Shape {
public:
    virtual ~Shape() = default;
    virtual void draw() const = 0;
};

class RectangleShape : public Shape {
public:
    RectangleShape(Point const &position)
        : position_{position} {}
    void draw() const override {
        std::cout << "▬" << std::endl;
    }

private:
    Point position_;
};

inline void draw_shape(Shape const &shape) {
    shape.draw();
}

inline void draw_rectangle_shape(RectangleShape const &shape) {
    shape.draw();
}

#endif

fakegfx.cpp

#include "fakegfx.h"

#include <boost/python.hpp>
#include <boost/current_function.hpp>
#include <iostream>

namespace {
class ShapeWrap : public Shape, public boost::python::wrapper<Shape> {
public:
    void draw() const override {
        this->get_override("draw")();
    }
};

class RectangleShapeWrap
        : public RectangleShape
        , public boost::python::wrapper<RectangleShape> {
public:
    RectangleShapeWrap(Point const &position) : RectangleShape{position} {}

    void draw() const override {
        if (boost::python::override draw = this->get_override("draw")) {
            draw();
        } else {
            RectangleShape::draw();
        }
    }
    
    void default_draw() const {
        std::cout << BOOST_CURRENT_FUNCTION << std::endl;
        RectangleShape::draw();
    }
};
} // ns anon

BOOST_PYTHON_MODULE(fakegfx) {
    using namespace boost::python;

    class_<Point>("Point")
        .def(init<double, double>())
        .def("translate", &translate)
        .def_readwrite("x", &Point::x)
        .def_readwrite("y", &Point::y);

    class_<ShapeWrap, boost::noncopyable>("Shape")
        .def("draw", pure_virtual(&Shape::draw));

    class_<RectangleShapeWrap, bases<Shape>, boost::noncopyable>("RectangleShape", init<Point const&>())
        .def("draw", &RectangleShape::draw /*1*/, &RectangleShapeWrap::default_draw /*2*/);
        // drawの呼び出しを、関数2に転送する
        // 関数2のシグネチャが関数1と一致することを保証させる
        // 関数1の指定はそのためだけに必要となる

    def("draw_shape", draw_shape);
    def("draw_rectangle_shape", draw_rectangle_shape);
}

test_fakegfx.py

import fakegfx

# some points
pt = fakegfx.Point(1, 2)
print(f"{pt.x}, {pt.y}")

pt.translate(-100, 200)
print(f"{pt.x}, {pt.y}")

pt2 = fakegfx.Point()
print(f"{pt2.x}, {pt2.y}")

# circle shape
# derived from C++ shape class
# Shape <- CircleShape
class CircleShape(fakegfx.Shape):
    def draw(self):
        #super().draw() # cause pure virtual function call
        print("○")

circle = CircleShape()

# rectangle shape
# defined in C++ code
rectangle = fakegfx.RectangleShape(pt)

# square shape
# derived from C++ rectangle shape class
# Shape <- RectangleShape <- SquareSahpe
class SquareShape(fakegfx.RectangleShape):
    def __init__(self):
        super().__init__(pt)
        
    def draw(self):
        fakegfx.RectangleShape.draw(self) # test non-cyclic
        print("▧")


square = SquareShape()

print("#circle#")
fakegfx.draw_shape(circle)
print("#rectangle#")
fakegfx.draw_shape(rectangle)
print("#square#")
fakegfx.draw_shape(square)

print("-circle-")
circle.draw()
print("-rectangle-")
rectangle.draw()
print("-square-")
square.draw()

Jamfile

project extending
  : requirements
    <location>.
    ;

python-extension fakegfx : fakegfx.cpp ;

youtube/python-mixing-005.txt · 最終更新: 2024/02/28 18:26 by freemikan

特に明示されていない限り、本Wikiの内容は次のライセンスに従います: CC0 1.0 Universal
CC0 1.0 Universal Donate Powered by PHP Valid HTML5 Valid CSS Driven by DokuWiki