plates" [VELD1995], a technique originally developed foroptimization of high-performance matrix algebra expressions.  Theessence is that instead of performing the computation immediately,operators are overloaded to construct a type representing thecomputation.  In matrix algebra, dramatic optimizations are oftenavailable when the structure of an entire expression can be taken intoaccount, rather than evaluating each operation "greedily".Boost.Python uses the same technique to build an appropriate Pythonmethod object based on expressions involving self.

魔法的施展只是简单应用了“表达式模板(expression templates)”[VELD1995],一种最初为高性能矩阵代数表达式优化而开发的技术。其精髓是,不是立即进行计算,而是利用运算符重载,来构造一个代表计算的类型。在矩阵代数里,当考虑整个表达式的结构,而不是“贪婪地”对每步运算求值时,经常可以获得显著的优化。Boost.Python使用了同样的技术,它用包含self的表达式,构建了一个适当的Python成员方法对象。

Inheritance

继承

C++ inheritance relationships can be represented to Boost.Python by addingan optional bases<...> argument to the class_<...> templateparameter list as follows:

要在Boost.Python里描述C++继承关系,可以在class_<...>模板参数列表里添加一个可选的bases<...>,如下:

class_<Derived, bases<Base1,Base2> >("Derived")
     ...

This has two effects:

这有两种作用:

  1. When the class_<...> is created, Python type objectscorresponding to Base1 and Base2 are looked up inBoost.Python's registry, and are used as bases for the new PythonDerived type object, so methods exposed for the Python Base1and Base2 types are automatically members of the Derivedtype.  Because the registry is global, this works correctly even ifDerived is exposed in a different module from either of itsbases.
  2. C++ conversions from Derived to its bases are added to theBoost.Python registry.  Thus wrapped C++ methods expecting (apointer or reference to) an object of either base type can becalled with an object wrapping a Derived instance.  Wrappedmember functions of class T are treated as though they have animplicit first argument of T&, so these conversions areneccessary to allow the base class methods to be called for derivedobjects.
  1. class_<...>创建时,会在Boost.Python的注册表里查找Base1Base2所对应的Python类型对象,并将它们作为新的Python Derived类型对象的基类,因此为Python的Base1Base2类型导出的成员函数自动成为Derived类型的成员。因为注册表是全局的,所以Derived和它的基类可以在不同的模块中导出。
  2. 在Boost.Python的注册表里,添加了从Derived到它的基类的C++转换。这样,封装了Derived实例的对象就可以调用其基类的方法,而该封装的C++方法本该由一个基类对象(指针或引用)来调用。类T的成员方法封装后,可视为它们具有一个隐含的第一参数T&,所以为了允许派生类对象调用基类方法,这些转换是必须的。

Of course it's possible to derive new Python classes from wrapped C++class instances.  Because Boost.Python uses the new-style classsystem, that works very much as for the Python built-in types.  Thereis one significant detail in which it differs: the built-in typesgenerally establish their invariants in their __new__ function, sothat derived classes do not need to call __init__ on the baseclass before invoking its methods :

当然,也可以从封装的C++类实例派生新的Python类。因为Boost.Python使用了新型类系统,从封装类派生就像是从Python内置类型派生一样。但有一个重大区别:内置类型一般在__new__函数里建立不变式,因此其派生类不需要调用基类的__init__

>>> class L(list):
...      def __init__(self):
...          pass
...
>>> L().reverse()
>>>

Because C++ object construction is a one-step operation, C++ instancedata cannot be constructed until the arguments are available, in the__init__ function:

因为C++的对象构造是一个单步操作,在__init__函数里,只有参数齐全,才能构造C++实例数据:

>>> class D(SomeBoostPythonClass):
...      def __init__(self):
...          pass
...
>>> D().some_boost_python_method()
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: bad argument type for built-in operation

This happened because Boost.Python couldn't find instance data of typeSomeBoostPythonClass within the D instance; D's __init__function masked construction of the base class.  It could be correctedby either removing D's __init__ function or having it callSomeBoostPythonClass.__init__(...) explicitly.

发生错误的原因是,Boost.Python在实例D中,找不到类型SomeBoostPythonClass的实例数据;D__init__函数遮盖了基类的构造函数。纠正方法为,删除D__init__函数,或者让它显式调用SomeBoostPythonClass.__init__(...)

Virtual Functions

虚函数

Deriving new types in Python from extension classes is not veryinteresting unless they can be used polymorphically from C++.  Inother words, Python method implementations should appear to overridethe implementation of C++ virtual functions when called through baseclass pointers/references from C++.  Since the only way to alter thebehavior of a virtual function is to override it in a derived class,the user must build a special derived class to dispatch a polymorphicclass' virtual functions:

用Python从扩展类派生新的类型没有太大意思,除非可以在C++里面多态地使用派生类。换句话说,在C++里,通过基类指针或引用调用C++虚函数时,Python实现的方法应该看起来像是覆盖了C++虚函数的实现。因为改变虚函数行为的唯一方法是,在派生类里覆盖它,所以用户必须构建一个特殊的派生类,来分派多态类的虚函数:

//
// interface to wrap:
//
class Base
{
 public:
    virtual int f(std::string x) { return 42; }
    virtual ~Base();
};

int calls_f(Base const& b, std::string x) { return b.f(x); }

//
// Wrapping Code
//

// Dispatcher class
struct BaseWrap : Base
{
    // Store a pointer to the Python object
    BaseWrap(PyObject* self_) : self(self_) {}
    PyObject* self;

    // Default implementation, for when f is not overridden
    int f_default(std::string x) { return this->Base::f(x); }
    // Dispatch implementation
    int f(std::string x) { return call_method<int>(self, "f", x); }
};

...
    def("calls_f", calls_f);
    class_<Base, BaseWrap>("Base")
        .def("f", &Base::f, &BaseWrap::f_default)
        ;

Now here's some Python code which demonstrates:

这是Python演示代码:

>>> class Derived(Base):
...     def f(self, s):
...          return len(s)
...
>>> calls_f(Base(), 'foo')
42
>>> calls_f(Derived(), 'forty-two')
9

Things to notice about the dispatcher class:

关于分派类需要注意:

Deeper Reflection on the Horizon?

更深的反射即将出现?

Admittedly, this formula is tedious to repeat, especially on a projectwith many polymorphic classes.  That it is neccessary reflects somelimitations in C++'s compile-time introspection capabilities: there'sno way to enumerate the members of a class and find out which arevirtual functions.  At least one very promising project has beenstarted to write a front-end which can generate these dispatchers (andother wrapping code) automatically from C++ headers.

无可否认,重复这种公式化动作是冗长乏味的,尤其是项目里有大量多态类的时候。这里有必要反映一些C++编译时内省能力的限制:C++无法列举类的成员并找出虚函数。不过,至少有一个项目已经启动,有希望编写出一个前端程序,可以从C++头文件自动生成这些分派类(和其他封装代码),

Pyste is being developed by Bruno da Silva de Oliveira.  It builds onGCC_XML, which generates an XML version of GCC's internal programrepresentation.  Since GCC is a highly-conformant C++ compiler, thisensures correct handling of the most-sophisticated template code andfull access to the underlying type system.  In keeping with theBoost.Python philosophy, a Pyste interface description is neitherintrusive on the code being wrapped, nor expressed in some unfamiliarlanguage: instead it is a 100% pure Python script.  If Pyste issuccessful it will mark a move away from wrapping everything directlyin C++ for many of our users.  It will also allow us the choice toshift some of the metaprogram code from C++ to Python.  We expect thatsoon, not only our users but the Boost.Python developers themselveswill be "thinking hybrid" about their own code.

Bruno da Silva de Oliveira正在开发Pyste。Pyste基于GCC_XML构建,而GCC_XML可以生成XML版本的GCC内部程序描述。因为GCC是一种高度兼容标准的C++编译器,从而确保了对最复杂的模板代码的正确处理,和对底层类型系统的完全访问。和Boost.Python的哲学一致,Pyste接口描述既不侵入待封装的代码,也不使用某种不熟悉的语言来表达,相反,它是100%的纯Python脚本。如果Pyste成功的话,它将标志,我们的许多用户不必直接用C++封装所有东西。Pyste也将允许我们选择性地把一些元编程代码从C++转移到Python。我们期待不久以后,不仅用户,而且Boost.Python开发者也

返回
【上篇】
【下篇】

作者:

抱歉!评论已关闭.