操纵对象和值类型#
inject-code#
inject-code
节点将给定的代码插入到指定的类型或函数的生成代码中,并且它是 object-type、value-type、modify-function 和 add-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
属性指定文件名(参见 从外部文件使用代码段)。
可选的 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<path>, --typesystem-paths=<path>[:<path>:...])。
<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#
modify-field
节点允许您在将指定 C++ 字段映射到目标语言时更改其访问权限,并且它是 object-type 或 value-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
属性是字段的名称,可选的 write
和 read
属性指定在目标语言 API 中字段的访问权限(默认情况下都设置为 true)。
remove
属性是一个可选的布尔属性,可以用作标记字段在生成过程中被丢弃。
可选的 rename
属性可以用来自定义生成目标语言 API 中给定字段的名称。
可选的 opaque-container
属性指定是否在读取访问时返回一个不透明的容器(参见 不透明容器)。
可选的 snake-case 属性允许覆盖类入口或 typesystem 元素上指定的值。
modify-function#
modify-function
节点允许您在将指定 C++ 函数映射到目标语言时修改它,并且它是 function、namespace-type、object-type 或 value-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_THREADS》和《Py_END_ALLOW_THREADS》,即暂时释放全局解释器锁(GIL)。这样做是必要的,对于任何线程相关函数(等待操作)、可能调用虚函数的函数(可能在Python中重写),以及推荐用于长时间I/O操作或类似情况。但这会有性能开销。值《auto》表示对于被认为安全的功能(例如,简单的获取器)将关闭此功能。该属性的默认值为《false》。
《exception-handling》属性指定是否生成异常处理代码(将函数调用嵌套到try/catch语句中)。它接受以下值
no, false: 不生成异常处理代码
auto-off: 对于声明非空《throw》列表的函数,生成异常处理代码
auto-on: 除了函数声明了《noexcept》之外,总是生成异常处理代码
yes, true: 总是生成异常处理代码
可选的《overload-number》属性指定在检查参数时重载的位置。通常,当存在多个重载时,例如在Qt中,它们的顺序将被重新排序,以便首先检查为接受《QPoint》的函数匹配参数。这样做的目的是为了避免在第二次重载中从《QPoint》到《QPointF》的潜在昂贵的隐式转换。但是,在某些情况下这可能不是希望的;最显著的是,当一个类从容器继承,并且存在两种类型的重载,就像《QPolygon》类的情况一样
void QPainter::drawLine(QPointF, QPointF);
void QPainter::drawLine(QPoint, QPoint);
默认情况下,接受《QList》的重载将被首先检查,以尽量避免从《QList》构建《QPolygon》。对于一个点列表的类型检查也会成功于《QPolygon》类型的参数,因为它继承了《QList》。这是一个问题,因为序列类型检查代价高昂,因为需要检查容器中的每个元素都是《QPoint》。因此,最好首先检查《QPolygon》重载。这可以通过以下方式指定数字来达成
class QPolygon : public QList<QPoint> {};
void QPainter::drawPolygon(QPolygon);
void QPainter::drawPolygon(QList<QPoint>);
应给出所有重载的数字;否则,顺序将是声明顺序。
<object-type name="QPainter">
<modify-function signature="drawPolygon(QPolygon)" overload-number="0"/>
<modify-function signature="drawPolygon(QList<QPoint>)" overload-number="1"/>
</object-type>
应给出所有重载的数字;否则,顺序将是声明顺序。
可选的《final》属性可指定给虚函数,并禁用生成在Python(本地调用)中覆盖函数的代码。这在结果类型不可构造时很有用。
《remove》属性是一个可选的布尔属性,它可以标记函数在被生成时被丢弃。
可选的《rename》属性可用于更改在生成的目标语言API中提供的函数的名称。
可选的《access》属性更改了在生成的目标语言API中提供的函数的访问权限。
可选的 snake-case 属性允许覆盖类入口或 typesystem 元素上指定的值。
可选的已弃用属性允许覆盖由C++属性检测到的弃用。它以两种方式工作。
add-function跳转到此标题的链接
《add-function》节点允许您将指定的函数添加到目标语言中。如果函数应该是一个方法,它是object-type或value-type节点的子节点;如果函数应该是一个命名空间内部或全局函数,它是namespace-type和typesystem节点的子节点。它可能包含modify-argument节点。
通常在添加函数时,必须注入一些代码来提供函数逻辑。这可以通过使用inject-code节点来完成。
<object-type>
<add-function signature="..." return-type="..."
access="public | protected"
overload-number="number"
static="yes | no" classmethod="yes | no"
since="..."/>
</object-type>
返回类型《return-type》的默认值为void,访问权限为public,静态的为no。
《since》属性指定了添加此函数时的API版本。
《classmethod》属性指定该函数是否应该是Python类方法。它设置了METH_CLASS标志,这意味着将传递的self是一个PyTypeObject而不是PyObject实例,这需要在注入代码中处理。
有关optional属性《overload-number》的详细信息,请参阅modify-function。
请注意,Qt类文档中的“static”标签几乎总是意味着应该生成一个Python classmethod,因为对象的类始终可以从静态C++代码中访问,而Python需要cls提供显式的“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>
有关添加相应函数的详细信息,请参阅序列协议。
declare-function#
《declare-function》节点允许您声明类型中存在的函数,如果函数应该是一个方法,它是object-type或value-type节点的子节点;如果函数应该是一个命名空间内部或全局函数,它是namespace-type和typesystem节点的子节点。它可能包含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-thread、exception-handling
、overload-number
和 snake-case
,请参阅 modify-function。
这有助于让 Shiboken 知道光解析器未检测到的函数。例如,在 Qt 6 中,QList<T>
容器的 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#
property
元素允许您指定由类型和获取/设置函数组成的属性。
它可能出现在复杂类型(如 object-type 或 value-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 处理)。默认为 不。
可选的 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"/>
有了这个,可以采用更 Pythonic 的风格
test = Test()
test.value = 42
对于具有 PySide6 扩展的 Qt 类,可以指定为属性,这些额外的设置和获取器未作为 Q_PROPERTY
出现
<object-type name="QMainWindow">
<property name="centralWidget" type="QWidget *"
get="centralWidget" set="setCentralWidget"/>
除了为 Qt Designer 使用而定义的 QMainWindow
的正常属性外
注意
在 Qt 编程风格中,属性名通常与获取器名冲突。建议使用 remove
函数修改排除获取器,以生成包装器。
configuration#
configuration
元素允许您将表达式排除的类型作为预处理器的条件生成到模块头文件中。这专门针对 Qt 功能系统 ,但也可能用于类似系统。
它可能出现在复杂类型(如 object-type 或 value-type)的子元素中。
<configuration condition="..."/>
条件 condition
属性指定了预处理器条件。
这是一种省略依赖于某些配置的类(也参见选项 --drop-type-entries="<TypeEntry0>[;TypeEntry1;...]")的替代方法,目的是从单个生成的源树构建多个配置,但仍需要在 CMakeLists.txt
文件中列出正确的源文件。