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

时间:2021-02-23 00:50:52

标签: python python-c-api python-decimal

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

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

是否存在这方面的文档?有什么例子吗?

我在 Python git repository 中找到了实现对象的源代码,所以我确信我可以进行一些试验和错误,并通过头文件导入来解决问题,但首选文档(如果存在)。

2 个答案:

答案 0 :(得分:2)

在 Python 3.10 中,将为此提供一个 C API。您需要提供自己的 libmpdec 和 mpdecimal.h 标头,并使用 import_decimal() 初始化十进制 API。 (请注意,C 级 import_decimal() 调用与 Python 级语句 import decimal 完全不同且无关。)

设置后,您可以使用

分配一个未初始化的 Decimal 对象
PyObject *dec = PyDec_Alloc();

然后用

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

并使用 libmpdec 函数初始化 mpd_t。 (请注意,decimal 对象在逻辑上是不可变的,因此除了刚刚使用 PyDec_Alloc 分配的对象之外,您应该避免改变任何 Decimal 对象。)

要使用现有 Decimal 对象的 mpd_t,您可以执行

const mpd_t *dec_internal = PyDec_GetConst(some_existing_decimal);

然后使用非可变的 libmpdec 函数。


至于 3.10 之前的代码,没有 Decimal C API。您只需使用 import decimal; d = Decimal(whatever)PyImport_ImportModulePyObject_GetAttrString 等函数执行 PyObject_Call 的 C 级等效操作。

答案 1 :(得分:0)

您的问题是关于 decimal.Decimal 类,而链接的代码指向使用库 _decimal 的优化模块 libmpdec

以下代码段适用于 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

可以在 https://bugs.python.org/issue7652

找到 Python 3.3 中 _decimal 实现的一些背景信息