操作对象和值类型

注入代码

inject-code 节点将给定的代码插入到生成的代码中,用于指定的类型或函数,它是 object-typevalue-typemodify-functionadd-function 节点的子节点。它可能包含 insert-template 子节点。

<inject-code class="native | target"
             position="beginning | end" since="..."
             file="[file]"
             snippet="[label]"/>

class 属性指定了生成的代码中哪个模块将受到代码注入的影响 (参见 代码生成术语)。class 属性接受以下值:

  • native: C++ 代码

  • target: 绑定代码

如果position属性设置为beginning(默认值),代码将插入到函数的开头。如果设置为end,代码将插入到函数的末尾。

有关上述属性如何交互的详细描述,请参阅代码注入语义

可选的 file 属性指定了文件名 (参见 Using Snippets From External Files)。

可选的 snippet 属性指定了片段标签 (参见 使用外部文件中的片段)。

在注入代码时,有许多占位符会被替换(参见类型系统变量)。

有几种方法可以指定代码:

将代码嵌入XML

代码可以嵌入到XML中(注意要使用正确的XML实体来表示字符,如‘<’,‘>’,‘&’):

<value-type>
    <inject-code class="native | target"
        position="beginning | end" since="...">
        // the code
    </inject-code>
</value-type>

使用XML中指定的模板

可以创建代码模板以便在XML中重复使用 (参见 使用代码模板)。这允许替换自定义占位符。

<value-type>
    <inject-code class="native | target" class="native | target">
        <insert-template name="template_name"/>
    </inject-code>
</value-type>

使用外部文件中的代码片段

代码或文档片段也可以从类型系统搜索路径中找到的外部文件中检索(参见 -T, --typesystem-paths=[::...])。

<value-type>
    <inject-code class="native | target"
        position="beginning | end" since="..."
        file="external_source.cpp"
        snippet="label"/>
</value-type>

在外部文件 external_source.cpp 中,注释形式之间的代码:

// @snippet label
...
// @snippet label

将被提取。

修改字段

modify-field 节点允许您在将给定的C++字段映射到目标语言时更改其访问权限,它是object-typevalue-type节点的子节点。

<object-type>
    <modify-field name="..."
        write="true | false"
        read="true | false"
        remove="true | false"
        opaque-container = "yes | no"
        snake-case="yes | no | both" />
</object-type>

name 属性是字段的名称,可选的 writeread 属性指定了字段在目标语言 API 中的访问权限(默认情况下两者都设置为 true)。

remove 属性是一个可选的布尔属性,它可以标记该字段在生成时被丢弃。

可选的 rename 属性可用于更改生成的目标语言 API 中给定字段的名称。

可选的 opaque-container 属性指定在读取访问时是否应返回不透明容器 (参见 Opaque Containers)。

可选的 snake-case 属性允许覆盖类条目或 typesystem 元素上指定的值。

修改函数

modify-function 节点允许您在将给定的 C++ 函数映射到目标语言时对其进行修改,它是 functionnamespace-typeobject-typevalue-type 节点的子节点。嵌套的 modify-argument 节点可用于修改参数或返回值。

<object-type>
    <modify-function signature="..."
                     since="..."
                     remove="true | false"
                     access="public | private | protected"
                     allow-thread="true | auto | false"
                     exception-handling="no | auto-off | auto-on | yes"
                     final="true | false"
                     overload-number="number"
                     rename="..."
                     snake-case="yes | no | both"
                     deprecated = "true | false" />
</object-type>

signature 属性是一个标准化的 C++ 签名,不包括返回值但包括可能的 const 声明。当 modify-function 作为 function 节点的子节点出现以修改全局函数时,不需要此属性。

since 属性指定了此函数修改时的API版本。

allow-thread 属性指定是否应将函数包装到 Py_BEGIN_ALLOW_THREADSPy_END_ALLOW_THREADS 中,即暂时释放 GIL(全局解释器锁)。对于任何与线程相关的函数(等待操作)、可能调用虚函数(可能在 Python 中重新实现)的函数,以及建议用于长时间 I/O 操作或类似操作的情况下,这样做是必要的。不过,这会带来性能开销。值 auto 表示对于被认为安全的函数(例如简单的 getter),它将关闭。该属性默认为 false

exception-handling 属性指定是否生成异常处理代码(将函数调用嵌套在 try / catch 语句中)。它接受以下值:

  • no, false: 不生成异常处理代码

  • auto-off: 为声明非空throw列表的函数生成异常处理代码

  • 自动开启:除非函数声明为noexcept,否则生成异常处理代码

  • 是的,true:始终生成异常处理代码

可选的 overload-number 属性指定在检查参数时重载的位置。通常,当存在多个重载时,例如在 Qt 中的示例:

void QPainter::drawLine(QPointF, QPointF);
void QPainter::drawLine(QPoint, QPoint);

它们将被重新排序,以便首先检查匹配参数的函数,该函数接受一个QPoint。这是为了避免在使用第二个重载时,从QPointQPointF的潜在昂贵的隐式转换。然而,在某些情况下,这并不是期望的;最显著的是当一个类继承自一个容器并且存在两种类型的重载时,就像QPolygon类的情况一样:

class QPolygon : public QList<QPoint> {};

void QPainter::drawPolygon(QPolygon);
void QPainter::drawPolygon(QList<QPoint>);

默认情况下,首先会检查接受QList的重载,尝试避免从QList构造QPolygon。对于类型为QPolygon的参数,点列表的类型检查也会成功,因为它继承了QList。这带来了一个问题,因为序列类型检查由于需要检查每个容器元素是否为QPoint而代价高昂。因此,最好首先检查QPolygon的重载。这是通过如下指定数字来实现的:

<object-type name="QPainter">
    <modify-function signature="drawPolygon(QPolygon)" overload-number="0"/>
    <modify-function signature="drawPolygon(QList&lt;QPoint&gt;)" overload-number="1"/>
</object-type>

应为所有重载提供数字;否则,顺序将按照声明顺序排列。

可选的 final 属性可以为虚函数指定,并禁用生成在 Python 中覆盖该函数的代码(本地调用)。这在结果类型不可构造时非常有用。

remove 属性是一个可选的布尔属性,它可以标记该函数在生成时被丢弃。

可选的 rename 属性可用于更改生成的目标语言 API 中给定函数的名称。

可选的 access 属性会改变生成的目标语言 API 中给定函数的访问权限。

可选的 snake-case 属性允许覆盖类条目或 typesystem 元素上指定的值。

可选的 已弃用 属性允许覆盖由C++属性检测到的弃用。它在两种方式下都有效。

添加函数

add-function 节点允许您在目标语言上添加一个给定的函数,如果该函数是一个方法,则它是 object-typevalue-type 节点的子节点;如果该函数是命名空间内的函数或全局函数,则它是 namespace-typetypesystem 的子节点。它可能包含 modify-argument 节点。

通常,在添加函数时,必须注入一些代码以提供函数逻辑。这可以使用inject-code节点来完成。

<object-type>
    <add-function signature="..." return-type="..."
                  access="public | protected"
                  overload-number="number"
                  static="yes | no" classmethod="yes | no"
                  python-override ="yes | no"
                  since="..."/>
</object-type>

return-type 属性默认为 voidaccess 默认为 publicstatic 默认为 no

since 属性指定了添加此函数时的API版本。

classmethod 属性指定函数是否应为 Python 类方法。 它设置了 METH_CLASS 标志,这意味着 PyTypeObject 而不是实例 PyObject 作为 self 传递,需要在注入的代码中处理。

对于可选属性overload-number,请参见modify-function

请注意,Qt的类文档中的“static”标签几乎总是意味着应该生成一个Python的classmethod,因为对象的类总是可以从静态C++代码中访问,而Python需要classmethod提供的显式“self”参数。

为了创建支持关键字参数的函数参数,请在signature字段中用@包围特定的函数参数。

<add-function signature="foo(int @parameter1@,float @parameter2@)">
    ...
</add-function>

使用关键字参数,add-function 使得在 signature 字段中指定默认参数变得容易

<add-function signature="foo(int @parameter1@=1,float @parameter2@=2)">
    ...
</add-function>

请参阅Sequence Protocol以添加相应的函数。

可选的属性 python-override 表示一种特殊类型的添加函数,一个将被生成本地包装器的 python-override(参见 修改虚函数)。

声明函数

declare-function 节点允许你声明类型中存在的一个函数,如果该函数是一个方法,则它是 object-typevalue-type 节点的子节点;如果该函数是命名空间内的函数或全局函数,则它是 namespace-typetypesystem 的子节点。它可能包含 modify-argument 节点。

<container-type>
    <declare-function signature="..." return-type="..." since="..."
                      allow-thread="true | auto | false"
                      exception-handling="off | auto-off | auto-on | on"
                      overload-number="number"
                      snake-case="yes | no | both"/>
</container-type>

return-type 属性默认为 void

since 属性指定了添加此函数时的API版本。

对于可选属性allow-threadexception-handlingoverload-numbersnake-case,请参见modify-function

这对于让shiboken了解其代码解析器无法检测到的函数非常有用。例如,在Qt 6中,QList容器的append()函数接受一个parameter_type参数,该参数通过一些代码解析器无法解析的模板表达式专门化为简单类型的T和复杂类型的const T &。在这种情况下,可以使用简单的签名声明该函数:

<container-type name="QList">
    <declare-function signature="append(T)"/>
</container-type>

这告诉shiboken存在一个具有该签名的公共函数,并且将在QList的特化中创建绑定。

add-pymethoddef

add-pymethoddef 元素允许您向类型的 PyMethodDef 数组中添加一个自由函数。不会生成参数或结果转换,从而允许可变参数函数和更灵活的参数检查。

<add-pymethoddef name="..." function="..." flags="..." doc="..."
                 signatures="..."/>

name 属性指定了名称。

function 属性指定了实现(类型为 PyCFunction 的静态函数)。

flags 属性指定了标志(通常是 METH_VARARGS,请参阅 Common Object Structures)。

可选的 doc 属性指定要设置为 ml_doc 字段的文档。

可选的 signatures 属性指定了函数签名的分号分隔列表。

属性

property 元素允许您指定由类型和getter和setter函数组成的属性。

它可能作为复杂类型的子元素出现,例如 object-typevalue-type

如果PySide6扩展不存在,将使用PyGetSetDef结构体生成代码,类似于为字段生成的代码。

如果存在PySide6扩展,这些属性将补充从基于Qt的代码中的Q_PROPERTY宏获得的属性。除非强制生成代码,否则这些属性将在libpyside中处理。

<property name="..." type="..." get="..." set="..."
          generate-getsetdef="yes | no" since="..."/>

name 属性指定属性的名称,type 属性指定 C++ 类型,get 属性指定访问器函数的名称。

可选的 set 属性指定了设置函数的名称。

可选的 generate-getsetdef 属性指定是否生成代码,如果 PySide6 扩展存在(表示此属性不由 libpyside 处理)。它默认为 no

可选的 since 属性指定了此属性出现时的 API 版本。

对于一个典型的C++类,例如:

class Test {
public:
    int getValue() const;
    void setValue();
};

value 然后可以被指定为一个属性:

<value-type name="Test">
    <property name="value" type="int" get="getValue" set="setValue"/>

这样,可以使用更符合Python风格的写法:

test = Test()
test.value = 42

对于Qt类(带有PySide6扩展),可以指定不显示为Q_PROPERTY的额外setter和getter作为属性:

<object-type name="QMainWindow">
    <property name="centralWidget" type="QWidget *"
              get="centralWidget" set="setCentralWidget"/>

除了为Qt Designer使用定义的QMainWindow的正常属性外。

注意

Qt编码风格中,属性名称通常与getter名称冲突。建议使用remove函数修改来排除生成包装器中的getter。

配置

configuration 元素允许您生成一个预处理器条件,根据表达式排除模块头中的类型。这是专门为 Qt Feature system 量身定制的,但也可以用于类似的系统。

它可能作为复杂类型的子元素出现,例如 object-typevalue-type

<configuration condition="..."/>

condition 属性指定了预处理条件。

这是一种根据某些配置省略类的替代方法(另请参见选项 --drop-type-entries="[;TypeEntry1;...]"),旨在从一个生成的源树构建多个配置,但仍然需要在 CMakeLists.txt 文件中列出正确的源文件。

修改虚函数

一些C++虚函数不适合用于Python绑定:

virtual void getInt(int *result) const;

在这种情况下,您将修改它以返回整数(或者在多个输出参数的情况下返回元组):

virtual int getInt() const;

对于绑定本身,使用常见的参数修改(移除参数,使用注入的代码片段修改返回类型)来修改签名。

为了使在Python中重新实现具有修改签名的函数成为可能,添加一个python-override函数,使用任意名称进行消歧:

<add-function signature="getIntPyOverride()"
              return-type="int" python-override="true"/>

这会导致一个静态函数执行调用进入Python以生成覆盖到原生包装器中。

在现有的虚函数中,在shell / override位置注入一个代码片段,该片段调用新添加的函数。前两个参数是全局解释器锁句柄 (Shiboken::GilState)和由覆盖检查确定的Python方法(PyObject *)。然后,该片段转换参数和返回值,并在之后返回:

<modify-function signature="getInt(int*)const">
    <inject-code class="shell" position="override">
    *result = getIntPyOverride(gil, pyOverride.object());
    return;
    </inject-code>
</modify-function>