Python:获取PyObject的字符串表示形式?

58

我有一个 C Python 扩展程序,我想打印一些诊断信息。

我正在接收一个 PyObject* 字符串。

怎样是获取此对象的字符串表示形式的规范方法,使其可用作 const char *

7个回答

59

使用PyObject_Repr(模拟 Python 的 repr 函数)或 PyObject_Str(模拟 str),然后调用 PyString_AsString 来获取 char *(通常应该将其作为 const char* 使用,例如:

)

PyObject* objectsRepresentation = PyObject_Repr(yourObject);
const char* s = PyString_AsString(objectsRepresentation);

对于任何 PyObject,此方法都可以使用。如果你绝对确定 yourObject 是一个Python字符串而不是其他类型的对象,比如数字,那么可以跳过第一行,直接执行:

const char* s = PyString_AsString(yourObject);

3
我正在尝试在Python 3中使用PyBytes_AsString(yourObject),但是出现了TypeError: expected bytes, str found的错误。 - brita_
我在我的回答中甚至没有提到PyBytes_AsString。你尝试过我在回答中建议的吗? - piokuc
24
在Py3.x中,PyString被PyBytes替代,但功能并不完全相同。 我最终使用了:PyUnicode_AsUTF8(objectsRepresentation)。 - brita_
14
别忘了执行Py_DECREF(objectsRepresentation),因为PyObject_Repr()返回一个新的引用! - Steve

41

如果您正在使用Python 3,则以下是正确的答案:

static void reprint(PyObject *obj) {
    PyObject* repr = PyObject_Repr(obj);
    PyObject* str = PyUnicode_AsEncodedString(repr, "utf-8", "~E~");
    const char *bytes = PyBytes_AS_STRING(str);

    printf("REPR: %s\n", bytes);

    Py_XDECREF(repr);
    Py_XDECREF(str);
}

1
如果我的 PyObject 是普通的 Python 字符串,我该如何将其转换为 const char* - Montreal
1
请注意,PyObject_Repr 在您的字符串周围放置单引号。 - IDDQD
@Montreal 和上面的例子一样,但省略 PyObject_Repr。为了安全起见,您可以使用 if(!PyUnicode_CheckExact(obj)){...} 来验证 PyObject *obj 是否确实是 PyUnicode_Type - IDDQD
2
E”是什么意思? - mkrieger1
1
在这个例子中,@mkrieger1会用字符串“E”替换无效的字符/数据。 - Romuald Brunet
"将英语翻译成中文。仅返回已翻译的文本:结果字符串中的单引号..." - sea-kg

12

如果您需要在Python 3中只是打印对象,您可以使用以下其中之一的函数:

static void print_str(PyObject *o)
{
    PyObject_Print(o, stdout, Py_PRINT_RAW);
}

static void print_repr(PyObject *o)
{
    PyObject_Print(o, stdout, 0);
}

4
尝试使用PyObject_Repr(模仿 Python 的 repr)或 PyObject_Str(模仿 Python 的 str)函数。
文档如下:
计算对象 o 的字符串表示形式。 成功时返回字符串表示形式,失败时返回 NULL。 这相当于 Python 表达式 repr(o)。 由内置函数 repr() 调用。

这看起来就是我需要的... 一旦我获得了这些函数返回的PyObject,我该如何以C友好的方式访问它(例如调用printf等)? - Mark Harrison

2

对于 Python >=3.3:

char* str = PyUnicode_1BYTE_DATA(py_object);

是的,这是一个非const指针,你可以通过它可能修改(不可变)字符串。


Python 3.10错误:无效的从‘Py_UCS1’ {即‘unsigned char’} 到 ‘char*’ 的转换。 - sea-kg

1
对于任意的PyObject*,首先调用PyObject_Repr()PyObject_Str()来获取一个PyUnicode*对象。
在Python 3.3及以上版本中,调用PyUnicode_AsUTF8AndSize。除了你想要的Python字符串外,该函数还接受一个可选地址以存储长度。
Python字符串是具有显式长度字段并可能包含空字节的对象,而const char*本身通常是指向以null结尾的C字符串的指针。将Python字符串转换为C字符串可能会导致信息丢失。因此,所有其他Python C-API函数如果从字符串返回const char*不建议使用
如果您不关心字符串中是否包含嵌入的null字节且不介意损失一部分字符串,则可以将size参数设置为NULL。例如,
PyObject* foo = PyUnicode_FromStringAndSize("foo\0bar", 7);

printf("As const char*, ignoring length: %s\n",
    PyUnicode_AsUTF8AndSize(foo, NULL));

打印

As const char*, ignoring length: foo

但是你也可以传递一个size变量的地址,与const char*一起使用,以确保你获取整个字符串。

PyObject* foo = PyUnicode_FromStringAndSize("foo\0bar", 7);

printf("Including size: ");
size_t size;
const char* data = PyUnicode_AsUTF8AndSize(foo, &size);
fwrite(data, sizeof(data[0]), size, stdout);
putchar('\n');

在我的终端上,它输出:
$ ./main | cat -v
Including size: foo^@bar

1

PyObject *module_name; PyUnicode_AsUTF8(module_name)

PyObject *module_name; PyUnicode_AsUTF8(module_name)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接