我有一个本地库,其自然界面涉及传递潜在的大数字。我预计大约一半是< 32位;另一季度< 64位;接下来的第八个< 128位 - 依此类推,没有固定的长度限制。
如果我可以约束值以适合单个寄存器,那么<p> PyLong_FromUnsignedLongLong()和PyLong_AsUnsignedLongLong()将是合适的。PyLong_FromString()克服了这一点 - 但是需要中间表示的不必要的代价。 _PyLong_FromByteArray()和_PyLong_AsByteArray()减轻了这个成本(通过简化这个中间表示),但是前导下划线让我想知道这是否会导致可移植性问题。
在longintrepr.h中,我发现了struct _longobject ...这暗示它可能是一种直接与内部表示交互的方式......虽然没有关于这种结构的详细文档仍然是一个障碍。
什么方法会导致Python和库之间的最佳吞吐量?是否有我忽略的文件?
答案 0 :(得分:7)
下划线前缀在很大程度上意味着C API与普通Python中的相同:“这个函数是一个可以改变的实现细节,所以如果你使用它就要注意自己”。您不被禁止使用此类功能,如果这是实现特定目标的唯一方法(例如,在您的情况下显着提高效率),那么只要您意识到危险,就可以使用API。
如果_PyLong_FromByteArray
API确实是私有的,则它将是static
函数,并且不会在longobject.h
中完整记录并导出。实际上,Tim Peters(一位着名的Python核心开发人员)明确地blesses its use:
[Dan Christensen]
我的学生和我正在写一个产生大片的C扩展 二进制的整数,我们想要转换为python long。该 比特数可以超过32甚至64.我的学生找到了 longobject.h中的函数_PyLong_FromByteArray正是如此 我们需要什么,但领先的下划线让我很谨慎。安全吗? 使用这个功能?
Python在内部使用它,所以最好是; - )
它将继续存在于未来的python版本中吗?
没有保证,这就是为什么它有一个领先的下划线:它不是 一个官方支持的,外部记录的,广告的一部分 Python / C API。碰巧我添加了这个功能,因为 Python内部需要某种形式的功能 不同的C模块。使其成为Python / C API的官方部分 会有更多的工作(我没有时间),而且 创造了永恒的新维护负担(我不热衷于此 无论如何; - ))。
在实践中,很少有人接触Python的这部分实现,所以 我不会/期望/它会在未来几年内消失甚至改变。 我能想到的最大的不安全感是有人可能 发起一个十字军东征以制作一些其他字节数组&lt; - &gt;长接口 基于表示负整数的不同方式的“官方”。 但即便如此,我仍然期待目前的非正式职能仍然存在, 因为256的补码表示仍然是必要的
struct
模块的“q”格式,以及pickle
模块的协议= 2 长序列化格式。或者我们应该使用其他方法吗?
没有。这就是为什么这些功能一开始就被发明的原因; - )
这是文档(来自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
的实现作为二次幂基础中的单词数组。这可能不会改变,但由于您在此基础上实现了API,因此您可以将调用者与Python API中的更改隔离开来。
答案 1 :(得分:0)
听起来你需要PyNumber_Long
。一些文档命中是here。