ユーザ用ツール

サイト用ツール


youtube:python-mixing-005

差分

このページの2つのバージョン間の差分を表示します。

この比較画面へのリンク

両方とも前のリビジョン前のリビジョン
youtube:python-mixing-005 [2024/02/28 18:26] – 削除 - 外部編集 (不明な日付) 127.0.0.1youtube:python-mixing-005 [2024/02/28 18:26] (現在) – ↷ toybox:python-mixing-005 から youtube:python-mixing-005 へページを移動しました。 freemikan
行 1: 行 1:
 +====== Boost.Pythonを使ってみる ======
 +
 +作成日: 2023-08-08 (火)
 +
 +[[https://youtu.be/_X_A6lev4fQ|第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 =====
 +
 +<file jam>
 +import python ;
 +
 +lib boost_python3 ;
 +
 +project
 +  : requirements
 +    <library>boost_python3
 +;
 +
 +build-project simple ;
 +build-project point ;
 +build-project pypoint ;
 +build-project fakegfx ;
 +</file>
 +
 +===== プロジェクト simple =====
 +
 +==== simple.cpp ====
 +
 +<file 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);
 +}
 +</file>
 +
 +==== test_simple.py ====
 +
 +<file python>
 +import simple
 +
 +simple.println("Hello, Boost.Python!")
 +
 +u = simple.to_upper("Hello, Boost.Python!")
 +simple.println(u)
 +</file>
 +
 +==== Jamfile ====
 +
 +<file jam>
 +project simple
 +  : requirements
 +    <location>.
 +  ;
 +
 +python-extension simple : simple.cpp ;
 +</file>
 +
 +===== プロジェクト point =====
 +
 +==== point.cpp ====
 +
 +<file 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);
 +}
 +</file>
 +
 +==== test_point.py ====
 +
 +<file python>
 +import point
 +
 +pt = point.Point()
 +print(f"{pt.x},{pt.y}")
 +
 +pt.translate(100, -200)
 +print(f"{pt.x},{pt.y}")
 +</file>
 +
 +==== Jamfile ====
 +
 +<file jam>
 +project point
 +  : requirements
 +    <location>.
 +    ;
 +
 +python-extension point : point.cpp ;
 +</file>
 +
 +===== プロジェクト pypoint =====
 +
 +==== pypoint.cpp ====
 +
 +<file 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);
 +}
 +</file>
 +
 +==== test_pypoint.py ====
 +
 +<file python>
 +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}")
 +</file>
 +
 +==== Jamfile ====
 +
 +<file jam>
 +project pypoint
 +  : requirements
 +    <location>.
 +    ;
 +
 +python-extension pypoint : pypoint.cpp ;
 +</file>
 +
 +===== プロジェクト fakegfx =====
 +
 +==== fakegfx.h ====
 +
 +<file cpp>
 +#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
 +</file>
 +
 +==== fakegfx.cpp ====
 +
 +<file 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);
 +}
 +</file>
 +
 +==== test_fakegfx.py ====
 +
 +<file python>
 +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()
 +</file>
 +
 +==== Jamfile ====
 +
 +<file jam>
 +project extending
 +  : requirements
 +    <location>.
 +    ;
 +
 +python-extension fakegfx : fakegfx.cpp ;
 +</file>
  

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