用单个元组调用PyObject_CallMethod会解压缩参数吗?

时间:2015-02-01 20:34:19

标签: python cpython

请考虑以下事项:

PyObject* fmt = PyUnicode_FromString("{0!r}");
PyObject* tup = PyTuple_New(2);
PyTuple_SetItem(tup, 0, PyUnicode_FromString("hello"));
PyTuple_SetItem(tup, 1, PyUnicode_FromString("world"));
PyObject* formatted = PyObject_CallMethod(fmt, "format", "O", tup);
PyObject* bytes = PyUnicode_AsEncodedString(formatted, "UTF-8", "strict");
printf(PyBytes_AS_STRING(bytes));

我希望它像这个python代码一样:

>>> u'{0!r}'.format((u"hello", u"world"))
"(u'hello', u'world')"

然而我的输出只是:

u'hello'

我可以想象它实际上是在调用函数:

>>> u'{0!r}'.format(u"hello", u"world")
u'hello'

我在寻找:

  1. 为什么?
  2. 我可以获得预期的最小变化是什么?

1 个答案:

答案 0 :(得分:1)

问题似乎与Py_BuildValue的工作方式有关(似乎PyObject_CallMethod使用了这种方式)。来自docs(强调我的):

  

Py_BuildValue()并不总是构建一个元组。它只构建一个元组   如果其格式字符串包含两个或更多格式单位。如果是格式   string为空,返回None; 如果它只包含一种格式   单位,它返回该格式单位描述的任何对象。 To   强制它返回大小为0或1的元组,将格式括起来   字符串。

这意味着,不是将格式字符串"O"tup一起构建到args=(tup,)并调用fmt.format(*args)(扩展为fmt.format(("hello", "world")),而是构建{{1} }},所以args=tup扩展为fmt.format(*args),正如您所想。解决方案也在docs

  

要强制它返回大小为0或1的元组,请将格式括起来   字符串。

所以,只需改变:

fmt.format("hello", "world")

要:

PyObject* formatted = PyObject_CallMethod(fmt, "format", "O", tup);

您获得了PyObject* formatted = PyObject_CallMethod(fmt, "format", "(O)", tup); 的所需输出。完整代码段(使用('hello', 'world')编译):

gcc thissnippet.c -I /usr/include/python3.4m/ -l python3.4m