Python扩展 - 有效地构造和检查大整数

时间:2013-08-17 15:40:37

标签: python python-2.7 python-3.x python-c-api

我有一个本地库,其自然界面涉及传递潜在的大数字。我预计大约一半是< 32位;另一季度< 64位;接下来的第八个< 128位 - 依此类推,没有固定的长度限制。

如果我可以约束值以适合单个寄存器,那么<​​p> PyLong_FromUnsignedLongLong()和PyLong_AsUnsignedLongLong()将是合适的。

PyLong_FromString()克服了这一点 - 但是需要中间表示的不必要的代价。 _PyLong_FromByteArray()和_PyLong_AsByteArray()减轻了这个成本(通过简化这个中间表示),但是前导下划线让我想知道这是否会导致可移植性问题。

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

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

2 个答案:

答案 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