在Python扩展对象中使用宽字符成员可行吗?
在Python的C扩展中,创建一个对象的成员变量,类型是char *
,其实很简单。你只需要在PyMemberDef
声明中使用T_STRING
这个定义就可以了。
但是,为什么似乎没有和wchar_t *
相对应的东西呢?如果真的有,那是什么呢?
举个例子:
struct object
里有一个char *text
。
PyMemberDef
数组里有{"text", T_STRING, offsetof(struct object, text), READONLY, "这是一段普通的字符字符串。"}
而如果是类似这样的:
struct object
里有一个wchar_t *wtext
。
PyMemberDef
数组里就应该有{"wtext", T_WSTRING, offsetof(struct object, wtext), READONLY, "这是一段宽字符字符串"}
我明白像PyUnicode_AsString()
这样的函数可以用来把数据编码成UTF-8,存储在普通的字符字符串里,然后再解码。但这样做就需要对通用的getattr
和setattr
方法进行封装,以处理编码后的文本。而且当你想在结构体中使用固定大小的字符数组时,这种方法就不太方便了,因为你不希望能存储的字符数量发生变化。
1 个回答
直接使用 wchar_t
这个类型并不适合在不同的平台上使用,因为它的表现可能会有所不同。Python 为了处理 Unicode 字符,定义了一个叫 Py_UNICODE
类型,作为存储 Unicode 字符的单位。
根据你使用的平台,Py_UNICODE
可能会被定义为 wchar_t
(如果这个类型可用的话),或者是一个无符号短整型、整型或长整型。它的大小会根据 Python 的配置(比如 UCS2 或 UCS4)以及使用的架构和 C 编译器而有所不同。你可以在 unicodeobject.h
文件中找到相关的定义。
在你的使用场景中,你的对象可以有一个属性是 Unicode 字符串,使用 T_OBJECT
来表示:
static struct PyMemberDef attr_members[] = {
{ "wtext", T_OBJECT, offsetof(PyAttrObject, wtext), READONLY, "wide string"}
...
你可以在对象的初始化函数中进行类型检查:
...
if (!PyUnicode_CheckExact(arg)) {
PyErr_Format(PyExc_ValueError, "arg must be a unicode string");
return NULL;
}
Py_INCREF(arg);
self->wtext = arg;
...
如果你需要遍历 Unicode 字符串中的低级字符,可以使用一个宏,它会返回一个 Py_UNICODE *
指针:
int i = 0;
Py_ssize_t size = PyUnicode_GetSize(self->wtext);
Py_UNICODE *chars = PyUnicode_AS_UNICODE(self->wtext);
for (i = 0; i < size; i++) {
// use chars[i]
...