10

我有一个本机库,其自然接口将涉及传递潜在的大量数字。我预计大约一半小于 32 位;另一个四分之一 < 64 位;接下来的八分之一 < 128 位 - 依此类推,没有固定长度限制。

如果我可以将值限制为适合单个寄存器,则 PyLong_FromUnsignedLongLong() 和 PyLong_AsUnsignedLongLong() 将是合适的。

PyLong_FromString() 克服了这一点——但代价是需要中间表示。_PyLong_FromByteArray() 和 _PyLong_AsByteArray() 降低了这个成本(通过使这个中间表示简单)但是前导下划线让我想知道这是否会导致可移植性问题。

在 longintrepr.h 中,我发现了 struct _longobject... 这暗示它可能是一种直接与内部表示进行交互的方式...尽管缺乏有关此结构的详细文档仍然是一个障碍。

什么方法将导致 Python 和库之间的最佳吞吐量?是否有我忽略的文档?

4

2 回答 2

8

下划线前缀在 C API 中的含义与普通 Python 中的含义大致相同:“此函数是一个可能会更改的实现细节,所以如果你使用它,请注意自己”。不禁止您使用此类功能,如果这是实现特定目标的唯一方法(例如,在您的情况下显着提高效率),那么只要您意识到危险,就可以使用 API。

如果_PyLong_FromByteArrayAPI 是真正私有的,那么它将是一个static函数,不会被完整记录并以longobject.h. 事实上,Tim Peters(著名的 Python 核心开发者)明确地祝福它的使用

[丹克里斯滕森]

我和我的学生正在编写一个 C 扩展,它会生成一个大的二进制整数,我们希望将其转换为 python long。位数可能远远超过 32 甚至 64。我的学生在 longobject.h 中找到了函数 _PyLong_FromByteArray,这正是我们所需要的,但前导下划线让我很警惕。使用此功能是否安全?

Python 在内部使用它,所以最好是 ;-)

它会继续存在于未来版本的 python 中吗?

没有保证,这就是为什么它有一个前导下划线:它不是官方支持的、外部记录的、广告 Python/C API 的一部分。碰巧我添加了该函数,因为 Python 在内部需要跨不同 C 模块的某种形式的功能。将其作为 Python/C API 的官方部分需要做更多的工作(我没有时间去做),并且会产生一个永恒的新维护负担(无论如何我都不热衷 ;-))。

在实践中,很少有人接触 Python 实现的这一部分,所以我不/期望/它会在未来几年内消失,甚至改变。我能想到的最大的不安全感是,有人可能会发起一场运动,以基于表示负整数的不同方式使其他一些字节数组 <-> 长接口“正式”。但即便如此,我仍希望当前的非官方函数保留,因为 struct模块的“q”格式和pickle模块的协议 = 2 长序列化格式仍然需要 256 的补码表示。

还是我们应该使用其他方法?

不,这就是为什么发明这些功能的原因 ;-)

这是文档(来自 Python 3.2.1):

/* _PyLong_FromByteArray:  View the n unsigned bytes as a binary integer in
   base 256, and return a Python long with the same numeric value.
   If n is 0, the integer is 0.  Else:
   If little_endian is 1/true, bytes[n-1] is the MSB and bytes[0] the LSB;
   else (little_endian is 0/false) bytes[0] is the MSB and bytes[n-1] the
   LSB.
   If is_signed is 0/false, view the bytes as a non-negative integer.
   If is_signed is 1/true, view the bytes as a 2's-complement integer,
   non-negative if bit 0x80 of the MSB is clear, negative if set.
   Error returns:
   + Return NULL with the appropriate exception set if there's not
     enough memory to create the Python long.
*/
PyAPI_FUNC(PyObject *) _PyLong_FromByteArray(
    const unsigned char* bytes, size_t n,
    int little_endian, int is_signed);

它是“下划线前缀”API 的主要原因是因为它依赖于 Python 的实现,long作为以 2 为基数的单词数组。这不太可能改变,但由于您在此基础上实现了一个 API,您可以将调用者与以后 Python API 中的更改隔离开来。

于 2013-08-20T02:27:38.760 回答
0

听起来你需要PyNumber_Long。一些文档点击在这里

于 2013-08-17T16:11:32.410 回答