使用单个元组调用 PyObject_CallMethod 解压参数?
Calling PyObject_CallMethod with a single tuple unpacks arguments?
考虑以下几点:
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'
我在找什么:
- 为什么?
- 要获得预期输出,我需要做的最小改变是什么?
问题似乎与 Py_BuildValue
的工作方式有关(似乎被 PyObject_CallMethod
). From the docs 使用(强调我的):
Py_BuildValue() does not always build a tuple. It builds a tuple only
if its format string contains two or more format units. If the format
string is empty, it returns None; if it contains exactly one format
unit, it returns whatever object is described by that format unit. To
force it to return a tuple of size 0 or one, parenthesize the format
string.
这意味着不是将带有 tup
的格式字符串 "O"
构建为 args=(tup,)
并调用 fmt.format(*args)
(扩展为 fmt.format(("hello", "world"))
),而是构建args=tup
,因此 fmt.format(*args)
扩展为 fmt.format("hello", "world")
,如您所想。解决方案也在docs:
To force it to return a tuple of size 0 or one, parenthesize the format
string.
所以,只需更改:
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
编译):
#include <Python.h>
int main() {
Py_Initialize();
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));
Py_Finalize();
}
考虑以下几点:
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'
我在找什么:
- 为什么?
- 要获得预期输出,我需要做的最小改变是什么?
问题似乎与 Py_BuildValue
的工作方式有关(似乎被 PyObject_CallMethod
). From the docs 使用(强调我的):
Py_BuildValue() does not always build a tuple. It builds a tuple only if its format string contains two or more format units. If the format string is empty, it returns None; if it contains exactly one format unit, it returns whatever object is described by that format unit. To force it to return a tuple of size 0 or one, parenthesize the format string.
这意味着不是将带有 tup
的格式字符串 "O"
构建为 args=(tup,)
并调用 fmt.format(*args)
(扩展为 fmt.format(("hello", "world"))
),而是构建args=tup
,因此 fmt.format(*args)
扩展为 fmt.format("hello", "world")
,如您所想。解决方案也在docs:
To force it to return a tuple of size 0 or one, parenthesize the format string.
所以,只需更改:
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
编译):
#include <Python.h>
int main() {
Py_Initialize();
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));
Py_Finalize();
}