如何使用CAPI构造一个decimal.Decimal对象?

How to construct a decimal.Decimal object using the C API?

我有兴趣在 C 的扩展中创建 decimal.Decimal 对象。我在 docs

中找不到任何关于此的文档

是否存在这方面的文档?有没有任何例子?

我在 Python git repository 中找到了实现该对象的源代码,所以我确定我可以进行一些试验和错误,并在工作中得过且过输出头文件导入,但首选文档(如果存在)。

您的问题是关于 decimal.Decimal class,而链接代码指向使用库 libmpdec.

的优化模块 _decimal

以下代码段适用于 Python 3.9 的所有三种情况 (decimal/_decimal/_pydecimal)。

PyObject *module = PyImport_ImportModule((char *) "decimal");
PyObject *clazz = PyObject_GetAttrString(module, (char *) "Decimal");
PyObject *value = PyUnicode_FromString("123.45");
PyObject *object = PyObject_CallOneArg(clazz, value);
PyObject  *str = PyObject_Str(object);
// C++
std::cout << "dec: " << PyUnicode_AsUTF8(str) << std::endl;
// C
// printf("dec: %s\n", PyUnicode_AsUTF8(str));

输出:

dec: 123.45

_decimal 3.3 中 _decimal 实施的一些背景信息可在 https://bugs.python.org/issue7652

中找到

在 Python 3.10 中,将有一个 C API。您需要提供自己的 libmpdec 和 mpdecimal.h header,并使用 import_decimal() 初始化小数 API。 (请注意,C-level import_decimal() 调用与 Python-level 语句 import decimal 完全不同且无关。)

设置后,您可以使用

分配一个未初始化的十进制object
PyObject *dec = PyDec_Alloc();

然后用

得到指向内部mpd_t的指针
mpd_t *dec_internal = PyDec_Get(dec);

并使用 libmpdec 函数初始化 mpd_t。 (请注意,十进制 object 在逻辑上是不可变的,因此您应该避免更改任何十进制 object,而不是您刚刚使用 PyDec_Alloc 分配的十进制 object。)

要使用现有十进制 object 的 mpd_t,您可以执行

const mpd_t *dec_internal = PyDec_GetConst(some_existing_decimal);

然后使用 non-mutative libmpdec 函数。


至于 3.10 之前的代码,没有十进制 C API。您只需使用 PyImport_ImportModulePyObject_GetAttrStringPyObject_Call.

等函数来执行 import decimal; d = Decimal(whatever) 的 C-level 等价操作